diff --git a/.yoi/tickets/00001KXKJGYGD/item.md b/.yoi/tickets/00001KXKJGYGD/item.md index 0577b18d..5aa1b310 100644 --- a/.yoi/tickets/00001KXKJGYGD/item.md +++ b/.yoi/tickets/00001KXKJGYGD/item.md @@ -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' diff --git a/.yoi/tickets/00001KXKJGYGD/thread.md b/.yoi/tickets/00001KXKJGYGD/thread.md index f9c1fe73..58c39947 100644 --- a/.yoi/tickets/00001KXKJGYGD/thread.md +++ b/.yoi/tickets/00001KXKJGYGD/thread.md @@ -182,4 +182,31 @@ Validation: - nix build .#yoi --no-link -> exit 0 +--- + + + +## 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 + + --- diff --git a/crates/manifest/src/lib.rs b/crates/manifest/src/lib.rs index 1f541eb9..5470f239 100644 --- a/crates/manifest/src/lib.rs +++ b/crates/manifest/src/lib.rs @@ -83,8 +83,8 @@ pub struct WorkerManifest { /// `[feature.web].enabled = true`. #[serde(default)] pub web: Option, - /// 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 `/SKILL.md` skill /// bundles). Paths are resolved against the manifest's base /// directory like other path fields. Absent ⇒ no skills loaded; diff --git a/crates/protocol/src/lib.rs b/crates/protocol/src/lib.rs index bdb4f975..933ad2bb 100644 --- a/crates/protocol/src/lib.rs +++ b/crates/protocol/src/lib.rs @@ -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. diff --git a/crates/tui/src/app.rs b/crates/tui/src/app.rs index 03058a33..1f968a0a 100644 --- a/crates/tui/src/app.rs +++ b/crates/tui/src/app.rs @@ -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. diff --git a/crates/worker/src/worker.rs b/crates/worker/src/worker.rs index c0c58815..8007d51b 100644 --- a/crates/worker/src/worker.rs +++ b/crates/worker/src/worker.rs @@ -833,7 +833,7 @@ impl Worker { /// /// 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; diff --git a/web/workspace/src/lib/workspace/console/composer-command.test.ts b/web/workspace/src/lib/workspace/console/composer-command.test.ts index a2aa9cd3..8f7b05d5 100644 --- a/web/workspace/src/lib/workspace/console/composer-command.test.ts +++ b/web/workspace/src/lib/workspace/console/composer-command.test.ts @@ -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(actual: T, expected: T): void { } Deno.test("parseSigilSegments converts TUI-style references", () => { - assertEquals(parseSigilSegments("read @src/main.rs then #memory and /workflow"), [ - { 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" }, - ]); + 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 /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", () => { diff --git a/web/workspace/src/lib/workspace/console/composer-completion.test.ts b/web/workspace/src/lib/workspace/console/composer-completion.test.ts index 8249b133..a340b86c 100644 --- a/web/workspace/src/lib/workspace/console/composer-completion.test.ts +++ b/web/workspace/src/lib/workspace/console/composer-completion.test.ts @@ -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", + ]); }); diff --git a/web/workspace/src/lib/workspace/console/composer-completion.ts b/web/workspace/src/lib/workspace/console/composer-completion.ts index 5a214b0c..1eeaf143 100644 --- a/web/workspace/src/lib/workspace/console/composer-completion.ts +++ b/web/workspace/src/lib/workspace/console/composer-completion.ts @@ -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"; } } diff --git a/web/workspace/src/routes/w/[workspaceId]/runtimes/[runtimeId]/workers/[workerId]/console/+page.svelte b/web/workspace/src/routes/w/[workspaceId]/runtimes/[runtimeId]/workers/[workerId]/console/+page.svelte index c18d1bf0..9fc73632 100644 --- a/web/workspace/src/routes/w/[workspaceId]/runtimes/[runtimeId]/workers/[workerId]/console/+page.svelte +++ b/web/workspace/src/routes/w/[workspaceId]/runtimes/[runtimeId]/workers/[workerId]/console/+page.svelte @@ -46,7 +46,7 @@ } type WorkerCompletionsResult = { - kind: "file" | "knowledge" | "workflow"; + kind: "file" | "knowledge"; prefix: string; entries: ComposerCompletionEntry[]; diagnostics: Diagnostic[];