fix: remove workflow completion surface
This commit is contained in:
parent
d30dca2d99
commit
0b56052a44
|
|
@ -2,7 +2,7 @@
|
|||
title: 'Remove workflow tracking and workflow resources'
|
||||
state: 'inprogress'
|
||||
created_at: '2026-07-15T19:02:13Z'
|
||||
updated_at: '2026-07-15T21:04:19Z'
|
||||
updated_at: '2026-07-15T21:22:40Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-07-15T19:54:36Z'
|
||||
|
|
|
|||
|
|
@ -182,4 +182,31 @@ Validation:
|
|||
- nix build .#yoi --no-link -> exit 0
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: hare at: 2026-07-15T21:22:40Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Follow-up fix for focused re-review blocker.
|
||||
|
||||
Summary:
|
||||
- Removed `/` as a web console completion sigil; composer completions now only recognize commands, file refs, and Knowledge refs.
|
||||
- Removed `workflow` from the web console completion result type and route-side completion response typing.
|
||||
- Updated web completion tests so slash text remains plain text/no completion token.
|
||||
- Removed stale Workflow completion/resolver wording from protocol and nearby comments.
|
||||
- Did not add hidden Workflow compatibility or broad Skills replacement.
|
||||
|
||||
Validation:
|
||||
- rg "ActiveWorkflow|active_workflow|Active workflow" -> no matches (exit 1)
|
||||
- focused completion-surface rg for workflow_invoke / workflow completion kind / slash Workflow resolver wording / resources/workflows / .yoi/workflow / Resident workflows -> no matches (exit 1)
|
||||
- focused web/protocol rg "kind.*workflow" -> no matches (exit 1); remaining project-wide "kind: workflow" mentions are only legacy persisted SystemItem ignore tests from the bounded compatibility path.
|
||||
- git diff --check -> exit 0
|
||||
- cd web/workspace && deno task check && deno task test -> exit 0
|
||||
- cargo test -p yoi --tests -> exit 0
|
||||
- cargo check -p yoi -> exit 0
|
||||
- yoi ticket doctor -> exit 0
|
||||
- nix build .#yoi --no-link -> exit 0
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -83,8 +83,8 @@ pub struct WorkerManifest {
|
|||
/// `[feature.web].enabled = true`.
|
||||
#[serde(default)]
|
||||
pub web: Option<WebConfig>,
|
||||
/// External Agent Skills (`SKILL.md`) directories to ingest as
|
||||
/// Workflows. Each entry is a path to a skills *root* (i.e. a
|
||||
/// External Agent Skills (`SKILL.md`) candidate directories. Each entry
|
||||
/// is a path to a skills *root* (i.e. a
|
||||
/// directory whose children are individual `<name>/SKILL.md` skill
|
||||
/// bundles). Paths are resolved against the manifest's base
|
||||
/// directory like other path fields. Absent ⇒ no skills loaded;
|
||||
|
|
|
|||
|
|
@ -70,9 +70,7 @@ pub enum Method {
|
|||
///
|
||||
/// Reply is sent on the same socket as `Event::Completions` (not
|
||||
/// broadcast). The IPC server handles this directly and writes
|
||||
/// the response straight back to the requesting socket. Empty
|
||||
/// results for resolvers that are not yet wired up
|
||||
/// (Knowledge / Workflow).
|
||||
/// the response straight back to the requesting socket.
|
||||
ListCompletions {
|
||||
kind: CompletionKind,
|
||||
prefix: String,
|
||||
|
|
@ -601,11 +599,7 @@ pub enum AlertSource {
|
|||
|
||||
/// Kind of completion requested by `Method::ListCompletions`.
|
||||
///
|
||||
/// Mirrors the TUI prefix sigils: `@` → `File`, `#` → `Knowledge`,
|
||||
/// `/` → `Workflow`. Knowledge and Workflow resolvers are currently
|
||||
/// stubs (always reply with empty `entries`); the wire shape is
|
||||
/// nailed down here so the TUI side can ship without waiting for
|
||||
/// the memory / workflow tickets.
|
||||
/// Mirrors the completion prefix sigils: `@` → `File`, `#` → `Knowledge`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
|
@ -616,7 +610,7 @@ pub enum CompletionKind {
|
|||
|
||||
/// One candidate returned in `Event::Completions::entries`.
|
||||
///
|
||||
/// `value` is a path (file kind) or a slug (knowledge / workflow).
|
||||
/// `value` is a path (file kind) or a Knowledge slug.
|
||||
/// `is_dir` is meaningful only for the file kind — it lets the TUI
|
||||
/// keep a trailing `/` after a directory selection so the user can
|
||||
/// drill in without re-typing the prefix.
|
||||
|
|
|
|||
|
|
@ -607,8 +607,7 @@ impl App {
|
|||
/// suggestion" — partial typing like `@README.` followed by
|
||||
/// Enter should chip when the popup is on `README.md`.
|
||||
///
|
||||
/// Files (and Knowledge / Workflow entries, which have no dir
|
||||
/// concept) chipify here. Directory file entries return `false`
|
||||
/// Files and Knowledge entries chipify here. Directory file entries return `false`
|
||||
/// so the caller can fall through to `apply_completion_text`
|
||||
/// for drill-in — chip-ifying a directory on Enter would strand
|
||||
/// the user with no way to inspect children.
|
||||
|
|
|
|||
|
|
@ -833,7 +833,7 @@ impl<C: LlmClient, St: Store> Worker<C, St> {
|
|||
///
|
||||
/// Default `true`: normal Workers may expose each resident section according
|
||||
/// to its own gate and manifest settings. Internal disposable workers set
|
||||
/// this to `false` so summary, Knowledge, and Workflow residency are all
|
||||
/// this to `false` so summary and Knowledge residency are both
|
||||
/// suppressed while explicit tools remain available.
|
||||
pub fn set_resident_injection(&mut self, enabled: bool) {
|
||||
self.inject_resident_summary = enabled;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
import { buildComposerRequest, parseSigilSegments } from "./composer-command.ts";
|
||||
import {
|
||||
buildComposerRequest,
|
||||
parseSigilSegments,
|
||||
} from "./composer-command.ts";
|
||||
|
||||
declare const Deno: {
|
||||
test(name: string, fn: () => void): void;
|
||||
|
|
@ -19,13 +22,16 @@ function assertEquals<T>(actual: T, expected: T): void {
|
|||
}
|
||||
|
||||
Deno.test("parseSigilSegments converts TUI-style references", () => {
|
||||
assertEquals(parseSigilSegments("read @src/main.rs then #memory and /workflow"), [
|
||||
assertEquals(
|
||||
parseSigilSegments("read @src/main.rs then #memory and /literal"),
|
||||
[
|
||||
{ kind: "text", content: "read " },
|
||||
{ kind: "file_ref", path: "src/main.rs" },
|
||||
{ kind: "text", content: " then " },
|
||||
{ kind: "knowledge_ref", slug: "memory" },
|
||||
{ kind: "text", content: " and /workflow" },
|
||||
]);
|
||||
{ kind: "text", content: " and /literal" },
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("buildComposerRequest sends user segments when sigils are present", () => {
|
||||
|
|
@ -51,7 +57,10 @@ Deno.test("buildComposerRequest parses colon commands", () => {
|
|||
const help = buildComposerRequest(":help compact");
|
||||
assert(help.ok, "help should be accepted");
|
||||
assertEquals(help.request, undefined);
|
||||
assert(help.notice?.includes(":compact"), "help should return a local notice");
|
||||
assert(
|
||||
help.notice?.includes(":compact"),
|
||||
"help should return a local notice",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("buildComposerRequest rejects invalid colon commands", () => {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ Deno.test("completionTokenAt detects TUI-style sigils before the cursor", () =>
|
|||
});
|
||||
assertEquals(completionTokenAt(":comp", 5)?.kind, "command");
|
||||
assertEquals(completionTokenAt("ask #mem", 8)?.kind, "knowledge");
|
||||
assertEquals(completionTokenAt("run /work", 9)?.kind, "workflow");
|
||||
assertEquals(completionTokenAt("run /work", 9), null);
|
||||
});
|
||||
|
||||
Deno.test("applyCompletion replaces the active token and advances the cursor", () => {
|
||||
|
|
@ -50,5 +50,7 @@ Deno.test("applyCompletion replaces the active token and advances the cursor", (
|
|||
});
|
||||
|
||||
Deno.test("localCommandCompletions filters colon commands", () => {
|
||||
assertEquals(localCommandCompletions("com").map((entry) => entry.value), ["compact"]);
|
||||
assertEquals(localCommandCompletions("com").map((entry) => entry.value), [
|
||||
"compact",
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export type ComposerCompletionKind = "command" | "file" | "knowledge" | "workflow";
|
||||
export type ComposerCompletionKind = "command" | "file" | "knowledge";
|
||||
|
||||
export type ComposerCompletionToken = {
|
||||
sigil: ":" | "@" | "#" | "/";
|
||||
sigil: ":" | "@" | "#";
|
||||
kind: ComposerCompletionKind;
|
||||
start: number;
|
||||
end: number;
|
||||
|
|
@ -35,7 +35,7 @@ export function completionTokenAt(
|
|||
): ComposerCompletionToken | null {
|
||||
const boundedCursor = Math.max(0, Math.min(cursor, value.length));
|
||||
const before = value.slice(0, boundedCursor);
|
||||
const match = /(^|\s)([:@#/])([^\s]*)$/.exec(before);
|
||||
const match = /(^|\s)([:@#])([^\s]*)$/.exec(before);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -51,7 +51,9 @@ export function completionTokenAt(
|
|||
};
|
||||
}
|
||||
|
||||
export function localCommandCompletions(prefix: string): ComposerCompletionEntry[] {
|
||||
export function localCommandCompletions(
|
||||
prefix: string,
|
||||
): ComposerCompletionEntry[] {
|
||||
const normalized = prefix.toLowerCase();
|
||||
return COLON_COMMAND_COMPLETIONS.filter((entry) =>
|
||||
entry.value.toLowerCase().startsWith(normalized)
|
||||
|
|
@ -65,13 +67,19 @@ export function applyCompletion(
|
|||
): CompletionApplyResult {
|
||||
const suffix = entry.is_dir ? "/" : " ";
|
||||
const replacement = `${token.sigil}${entry.value}${suffix}`;
|
||||
const restStart = !entry.is_dir && value[token.end] === " " ? token.end + 1 : token.end;
|
||||
const next = `${value.slice(0, token.start)}${replacement}${value.slice(restStart)}`;
|
||||
const restStart = !entry.is_dir && value[token.end] === " "
|
||||
? token.end + 1
|
||||
: token.end;
|
||||
const next = `${value.slice(0, token.start)}${replacement}${
|
||||
value.slice(restStart)
|
||||
}`;
|
||||
const cursor = token.start + replacement.length;
|
||||
return { value: next, cursor };
|
||||
}
|
||||
|
||||
function completionKindForSigil(sigil: ComposerCompletionToken["sigil"]): ComposerCompletionKind {
|
||||
function completionKindForSigil(
|
||||
sigil: ComposerCompletionToken["sigil"],
|
||||
): ComposerCompletionKind {
|
||||
switch (sigil) {
|
||||
case ":":
|
||||
return "command";
|
||||
|
|
@ -79,7 +87,5 @@ function completionKindForSigil(sigil: ComposerCompletionToken["sigil"]): Compos
|
|||
return "file";
|
||||
case "#":
|
||||
return "knowledge";
|
||||
case "/":
|
||||
return "workflow";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
}
|
||||
|
||||
type WorkerCompletionsResult = {
|
||||
kind: "file" | "knowledge" | "workflow";
|
||||
kind: "file" | "knowledge";
|
||||
prefix: string;
|
||||
entries: ComposerCompletionEntry[];
|
||||
diagnostics: Diagnostic[];
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user