@veewo/claw 0.2.21 → 0.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -141
- package/dist/cli.js +222 -14
- package/dist/cli.js.map +1 -1
- package/dist/codex-driver.d.ts +2 -2
- package/dist/codex-driver.js +1 -1
- package/dist/command-service.js +7 -1
- package/dist/command-service.js.map +1 -1
- package/dist/session-daemon.js +1 -0
- package/dist/session-daemon.js.map +1 -1
- package/package.json +45 -45
package/README.md
CHANGED
|
@@ -1,141 +1,141 @@
|
|
|
1
|
-
# @veewo/claw
|
|
2
|
-
|
|
3
|
-
`@veewo/claw` is the CLI entrypoint for running the `.claw` workflow in a project.
|
|
4
|
-
|
|
5
|
-
It gives agents and developers a concrete way to plan work, recall project knowledge, deposit truth and ADR notes, and close rounds out cleanly instead of leaving project state scattered across transient chats.
|
|
6
|
-
|
|
7
|
-
## What the CLI is for
|
|
8
|
-
|
|
9
|
-
- initialize and normalize the `.claw` project surface
|
|
10
|
-
- run project-scoped planning and task lifecycle commands
|
|
11
|
-
- index and query project documentation recall
|
|
12
|
-
- support truth ingestion and closeout flows
|
|
13
|
-
|
|
14
|
-
## Install
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npm install -g @veewo/claw
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
After installing the CLI, project search still needs one-time setup inside each `.claw` project:
|
|
21
|
-
|
|
22
|
-
1. Run `claw context` so `.claw/project.json` is normalized and the default local embedding config is present.
|
|
23
|
-
2. Run `claw search index --refresh` once so the local embedding model can be downloaded or reused and the first vector index can be built.
|
|
24
|
-
|
|
25
|
-
## Host startup context
|
|
26
|
-
|
|
27
|
-
`claw context --host <host>` is the single structured startup-state entrypoint
|
|
28
|
-
for host adapters. A host Hook owns its native event payload, validates its
|
|
29
|
-
trusted cwd and session identity, invokes `context`, and maps the JSON result
|
|
30
|
-
to its own prompt, card, or host-action surface. The CLI does not own platform
|
|
31
|
-
Hook event names or Hook-output envelopes.
|
|
32
|
-
|
|
33
|
-
The result may contain `activeWorkflow`, `error`, `startupRecovery.versionSync`,
|
|
34
|
-
and `searchGuidance`, in addition to project and session state. Adapters must
|
|
35
|
-
not accept cwd or session identity from model input. A missing `activeWorkflow`
|
|
36
|
-
means the session has no bound plan; it does not authorize plan discovery by
|
|
37
|
-
scanning unrelated project tasks.
|
|
38
|
-
|
|
39
|
-
Then run:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
claw init
|
|
43
|
-
claw search index --refresh
|
|
44
|
-
claw search "existing truth or ADR topic"
|
|
45
|
-
claw plan create --title "My task" --goal "Define the first task"
|
|
46
|
-
claw plan create "My templated task" --template default --goal "Route through the default template"
|
|
47
|
-
claw plan create "Ephemeral harness" --scope session --goal "Use plan and Goal workflows without project deposition"
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
`claw plan create` uses explicit `--template` first, otherwise the project's configured `defaultPlanTemplate`, and finally falls back to the built-in `default` template. You can select a template explicitly with `claw plan create "<title>" --template <name>` or `claw plan create --template <name> --title "<title>"`.
|
|
51
|
-
|
|
52
|
-
New project tasks are grouped under `.claw/tasks/YYYY-MM-DD/`. On the first `claw context` call of each local calendar day, claw performs a lock-protected maintenance pass: it removes expired entries from `.claw/runtime/tmp/`, removes workflow task directories that exceed the task TTL even when incomplete, moves eligible date-scoped task folders into the archive, applies `maxTasksToKeep` and archive TTL, removes expired or invalid bindings, and sweeps expired session workflows. This is lazy maintenance, not a background scheduler.
|
|
53
|
-
|
|
54
|
-
`--scope session` stores the workflow in a user-level directory keyed by the platform session id, so it works without a project `.claw` directory and recovers across cwd changes. It preserves plan/task/subplan/Goal behavior while disabling project knowledge capture, memory
|
|
55
|
-
|
|
56
|
-
Projects can add reusable templates directly under `.claw/templates` with `.json`, `.js`, `.mjs`, or `.cjs` files. Put `defaultPlanTemplate` in `.claw/project.json` for a shared team default, or in `.claw/project-override.json` for a local personal override.
|
|
57
|
-
|
|
58
|
-
When `.claw/project.json` has `planning: true`, the default `default` template seeds one planning task in `process.discussing`. It loads the effective `externalPlanningSkill`, falling back to `claw-kit:planning`, and stays open while the requirements and proposed solution are discussed and confirmed with the user. Use `plan start` when execution tasks remain; when planning itself resolves the request, complete task 1 and close the plan.
|
|
59
|
-
|
|
60
|
-
When `planning: false`, `claw plan create` seeds the smallest executable plan directly in `process.active`.
|
|
61
|
-
|
|
62
|
-
## Workflow shape
|
|
63
|
-
|
|
64
|
-
In a typical round, the CLI helps land this loop in a project:
|
|
65
|
-
|
|
66
|
-
`plan` -> `search and recall` -> `execute` -> `deposit truth / ADR` -> `close out`
|
|
67
|
-
|
|
68
|
-
That project-level plan structure helps agents carry longer-running work more cleanly than leaving the task in loose chat state alone.
|
|
69
|
-
|
|
70
|
-
## Persistent sessions
|
|
71
|
-
|
|
72
|
-
Open a persistent terminal with:
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
claw session open <dir> <agent-session-id>
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
The workdir is immutable for the lifetime of that session. Opening another
|
|
79
|
-
directory closes the prior live connection and opens the composite identity
|
|
80
|
-
`(canonical workdir, agent session id)`; two directories with the same agent id
|
|
81
|
-
remain isolated.
|
|
82
|
-
|
|
83
|
-
Inside the terminal, these commands implicitly target `currentPlan`:
|
|
84
|
-
|
|
85
|
-
```text
|
|
86
|
-
plan show [--simple]
|
|
87
|
-
plan edit ...
|
|
88
|
-
plan wait
|
|
89
|
-
plan done --retrospective "..."
|
|
90
|
-
task add ...
|
|
91
|
-
task edit --id ...
|
|
92
|
-
task done --id ...
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Use `plan resume` to resume the retained current plan, `plan resume <planId>` to
|
|
96
|
-
make a specified resumable plan current, and `plan leave` to enter
|
|
97
|
-
`end.leave` and clear focus. Every `end.*` triggers end-state finalization;
|
|
98
|
-
`end.leave` remains resumable and does not set `completedAt`.
|
|
99
|
-
|
|
100
|
-
`search --dir <dir> <query>` changes only that search operation. It never
|
|
101
|
-
changes the session workdir or current plan.
|
|
102
|
-
|
|
103
|
-
On an interrupted connection, mutations are never replayed automatically.
|
|
104
|
-
Reopen with the exact command returned by the error, then inspect
|
|
105
|
-
`plan show --simple`. Retained v2 state expires seven days after its last
|
|
106
|
-
update. Legacy session caches are not migrated and canonical plans are never
|
|
107
|
-
deleted by v2 cleanup.
|
|
108
|
-
|
|
109
|
-
Host adapters remain compatible with the stateless CLI. They can adopt
|
|
110
|
-
`@veewo/claw-client` incrementally once they consume the same structured
|
|
111
|
-
post-commit effects; opening a persistent session does not change existing
|
|
112
|
-
adapter behavior.
|
|
113
|
-
|
|
114
|
-
Codex startup workflow should rely on the session hook or startup recovery path instead of treating any extra manual recovery step as required after plan creation.
|
|
115
|
-
|
|
116
|
-
## Search and recall
|
|
117
|
-
|
|
118
|
-
`claw search` is the project recall command for `.claw` memory, truth, ADR, and declared markdown docs. Use it for retained project context rather than code search.
|
|
119
|
-
|
|
120
|
-
When a task needs deeper code investigation or relationship tracing, GitNexus can complement this workflow, but it is optional rather than required for using `claw` itself.
|
|
121
|
-
|
|
122
|
-
Typical setup:
|
|
123
|
-
|
|
124
|
-
```bash
|
|
125
|
-
claw context
|
|
126
|
-
claw search index --refresh
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
If you need deeper backup detail on config or recall behavior, use the adapter reference notes in [packages/codex-adapter/references/project-config-reference.md](../codex-adapter/references/project-config-reference.md) or [packages/opencode-adapter/references/project-config-reference.md](../opencode-adapter/references/project-config-reference.md).
|
|
130
|
-
|
|
131
|
-
## Configuration
|
|
132
|
-
|
|
133
|
-
If you need backup `.claw/project.json` detail, start with the adapter reference notes above and use [docs/project-json-reference.md](../../docs/project-json-reference.md) only for deeper canonical detail.
|
|
134
|
-
|
|
135
|
-
`claw-kit` also stays usable alongside other harnesses or external skills, so the CLI does not assume a single host or investigation surface.
|
|
136
|
-
|
|
137
|
-
The config model is team-friendly as well: `.claw/project.json` carries the shared canonical workflow, while `.claw/project-override.json` leaves room for personal runtime preferences.
|
|
138
|
-
|
|
139
|
-
## Repository
|
|
140
|
-
|
|
141
|
-
- [claw-kit](https://github.com/chanyuenpang/claw-kit)
|
|
1
|
+
# @veewo/claw
|
|
2
|
+
|
|
3
|
+
`@veewo/claw` is the CLI entrypoint for running the `.claw` workflow in a project.
|
|
4
|
+
|
|
5
|
+
It gives agents and developers a concrete way to plan work, recall project knowledge, deposit truth and ADR notes, and close rounds out cleanly instead of leaving project state scattered across transient chats.
|
|
6
|
+
|
|
7
|
+
## What the CLI is for
|
|
8
|
+
|
|
9
|
+
- initialize and normalize the `.claw` project surface
|
|
10
|
+
- run project-scoped planning and task lifecycle commands
|
|
11
|
+
- index and query project documentation recall
|
|
12
|
+
- support truth ingestion and closeout flows
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g @veewo/claw
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
After installing the CLI, project search still needs one-time setup inside each `.claw` project:
|
|
21
|
+
|
|
22
|
+
1. Run `claw context` so `.claw/project.json` is normalized and the default local embedding config is present.
|
|
23
|
+
2. Run `claw search index --refresh` once so the local embedding model can be downloaded or reused and the first vector index can be built.
|
|
24
|
+
|
|
25
|
+
## Host startup context
|
|
26
|
+
|
|
27
|
+
`claw context --host <host>` is the single structured startup-state entrypoint
|
|
28
|
+
for host adapters. A host Hook owns its native event payload, validates its
|
|
29
|
+
trusted cwd and session identity, invokes `context`, and maps the JSON result
|
|
30
|
+
to its own prompt, card, or host-action surface. The CLI does not own platform
|
|
31
|
+
Hook event names or Hook-output envelopes.
|
|
32
|
+
|
|
33
|
+
The result may contain `activeWorkflow`, `error`, `startupRecovery.versionSync`,
|
|
34
|
+
and `searchGuidance`, in addition to project and session state. Adapters must
|
|
35
|
+
not accept cwd or session identity from model input. A missing `activeWorkflow`
|
|
36
|
+
means the session has no bound plan; it does not authorize plan discovery by
|
|
37
|
+
scanning unrelated project tasks.
|
|
38
|
+
|
|
39
|
+
Then run:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
claw init
|
|
43
|
+
claw search index --refresh
|
|
44
|
+
claw search "existing truth or ADR topic"
|
|
45
|
+
claw plan create --title "My task" --goal "Define the first task"
|
|
46
|
+
claw plan create "My templated task" --template default --goal "Route through the default template"
|
|
47
|
+
claw plan create "Ephemeral harness" --scope session --goal "Use plan and Goal workflows without project deposition"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`claw plan create` uses explicit `--template` first, otherwise the project's configured `defaultPlanTemplate`, and finally falls back to the built-in `default` template. You can select a template explicitly with `claw plan create "<title>" --template <name>` or `claw plan create --template <name> --title "<title>"`.
|
|
51
|
+
|
|
52
|
+
New project tasks are grouped under `.claw/tasks/YYYY-MM-DD/`. On the first `claw context` call of each local calendar day, claw performs a lock-protected maintenance pass: it removes expired entries from `.claw/runtime/tmp/`, removes workflow task directories that exceed the task TTL even when incomplete, moves eligible date-scoped task folders into the archive, applies `maxTasksToKeep` and archive TTL, removes expired or invalid bindings, and sweeps expired session workflows. This is lazy maintenance, not a background scheduler.
|
|
53
|
+
|
|
54
|
+
`--scope session` stores the workflow in a user-level directory keyed by the platform session id, so it works without a project `.claw` directory and recovers across cwd changes. It preserves plan/task/subplan/Goal behavior while disabling project knowledge capture and project retention. When the session's frozen origin belongs to a valid claw project, its terminal transition refreshes that project's memory and enabled GitNexus index; otherwise it creates no refresh state. Use `claw session clean` for the current session or `claw session clean --expired` for the seven-day TTL sweep.
|
|
55
|
+
|
|
56
|
+
Projects can add reusable templates directly under `.claw/templates` with `.json`, `.js`, `.mjs`, or `.cjs` files. Put `defaultPlanTemplate` in `.claw/project.json` for a shared team default, or in `.claw/project-override.json` for a local personal override.
|
|
57
|
+
|
|
58
|
+
When `.claw/project.json` has `planning: true`, the default `default` template seeds one planning task in `process.discussing`. It loads the effective `externalPlanningSkill`, falling back to `claw-kit:planning`, and stays open while the requirements and proposed solution are discussed and confirmed with the user. Use `plan start` when execution tasks remain; when planning itself resolves the request, complete task 1 and close the plan.
|
|
59
|
+
|
|
60
|
+
When `planning: false`, `claw plan create` seeds the smallest executable plan directly in `process.active`.
|
|
61
|
+
|
|
62
|
+
## Workflow shape
|
|
63
|
+
|
|
64
|
+
In a typical round, the CLI helps land this loop in a project:
|
|
65
|
+
|
|
66
|
+
`plan` -> `search and recall` -> `execute` -> `deposit truth / ADR` -> `close out`
|
|
67
|
+
|
|
68
|
+
That project-level plan structure helps agents carry longer-running work more cleanly than leaving the task in loose chat state alone.
|
|
69
|
+
|
|
70
|
+
## Persistent sessions
|
|
71
|
+
|
|
72
|
+
Open a persistent terminal with:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
claw session open <dir> <agent-session-id>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The workdir is immutable for the lifetime of that session. Opening another
|
|
79
|
+
directory closes the prior live connection and opens the composite identity
|
|
80
|
+
`(canonical workdir, agent session id)`; two directories with the same agent id
|
|
81
|
+
remain isolated.
|
|
82
|
+
|
|
83
|
+
Inside the terminal, these commands implicitly target `currentPlan`:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
plan show [--simple]
|
|
87
|
+
plan edit ...
|
|
88
|
+
plan wait
|
|
89
|
+
plan done --retrospective "..."
|
|
90
|
+
task add ...
|
|
91
|
+
task edit --id ...
|
|
92
|
+
task done --id ...
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Use `plan resume` to resume the retained current plan, `plan resume <planId>` to
|
|
96
|
+
make a specified resumable plan current, and `plan leave` to enter
|
|
97
|
+
`end.leave` and clear focus. Every `end.*` triggers end-state finalization;
|
|
98
|
+
`end.leave` remains resumable and does not set `completedAt`.
|
|
99
|
+
|
|
100
|
+
`search --dir <dir> <query>` changes only that search operation. It never
|
|
101
|
+
changes the session workdir or current plan.
|
|
102
|
+
|
|
103
|
+
On an interrupted connection, mutations are never replayed automatically.
|
|
104
|
+
Reopen with the exact command returned by the error, then inspect
|
|
105
|
+
`plan show --simple`. Retained v2 state expires seven days after its last
|
|
106
|
+
update. Legacy session caches are not migrated and canonical plans are never
|
|
107
|
+
deleted by v2 cleanup.
|
|
108
|
+
|
|
109
|
+
Host adapters remain compatible with the stateless CLI. They can adopt
|
|
110
|
+
`@veewo/claw-client` incrementally once they consume the same structured
|
|
111
|
+
post-commit effects; opening a persistent session does not change existing
|
|
112
|
+
adapter behavior.
|
|
113
|
+
|
|
114
|
+
Codex startup workflow should rely on the session hook or startup recovery path instead of treating any extra manual recovery step as required after plan creation.
|
|
115
|
+
|
|
116
|
+
## Search and recall
|
|
117
|
+
|
|
118
|
+
`claw search` is the project recall command for `.claw` memory, truth, ADR, and declared markdown docs. Use it for retained project context rather than code search.
|
|
119
|
+
|
|
120
|
+
When a task needs deeper code investigation or relationship tracing, GitNexus can complement this workflow, but it is optional rather than required for using `claw` itself.
|
|
121
|
+
|
|
122
|
+
Typical setup:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
claw context
|
|
126
|
+
claw search index --refresh
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
If you need deeper backup detail on config or recall behavior, use the adapter reference notes in [packages/codex-adapter/references/project-config-reference.md](../codex-adapter/references/project-config-reference.md) or [packages/opencode-adapter/references/project-config-reference.md](../opencode-adapter/references/project-config-reference.md).
|
|
130
|
+
|
|
131
|
+
## Configuration
|
|
132
|
+
|
|
133
|
+
If you need backup `.claw/project.json` detail, start with the adapter reference notes above and use [docs/project-json-reference.md](../../docs/project-json-reference.md) only for deeper canonical detail.
|
|
134
|
+
|
|
135
|
+
`claw-kit` also stays usable alongside other harnesses or external skills, so the CLI does not assume a single host or investigation surface.
|
|
136
|
+
|
|
137
|
+
The config model is team-friendly as well: `.claw/project.json` carries the shared canonical workflow, while `.claw/project-override.json` leaves room for personal runtime preferences.
|
|
138
|
+
|
|
139
|
+
## Repository
|
|
140
|
+
|
|
141
|
+
- [claw-kit](https://github.com/chanyuenpang/claw-kit)
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createInterface } from "node:readline";
|
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
import { spawn, spawnSync } from "node:child_process";
|
|
9
|
-
import { buildDirectWorkflowGuidance, appendKnowledgeTaskConclusions, buildKnowledgeAtomicDispatch, buildKnowledgeDelegateDispatch, buildKnowledgeAssignmentTemplate, buildKnowledgeWriterAssignments, DEFAULT_MAX_TASKS_TO_KEEP, checkProjectProtocol, ClawError, buildPlanWorkflowGuidance, buildMemoryIndex, buildSessionStartDefaultPrompt, buildSessionStartRecoveredPrompt, editPlan, ensureProjectProtocol, enforceTaskRetention, findKnowledgeFinalizationJobPath, findTaskDirectory, runDailyMaintenance, ingestTruth, initProject, getTemplateTaskDoneChoices, resolvePlanTemplateFile, resolvePlanEffectiveConfig, resolveKnowledgeWriterForHost, resolveProjectContext, resolveWorkflowProjectContext, resolveSessionWorkflowContext, deleteSessionWorkflow, sweepExpiredSessionWorkflows, resolveSessionBoundPlan, resolveContext, resolveSeedPlanTemplate, searchMemoryAsync, warmProjectMemoryEmbedding, showPlan, createSubplan, switchTask, tryCaptureKnowledgeStop, claimKnowledgeFinalizationJob, doneKnowledgeFinalizationJob, readKnowledgeFinalizationJob, waitForKnowledgeFinalizationJobReady, listKnowledgeFinalizationJobs, listRetryableKnowledgeFinalizationJobs, normalizeTruthMarkdownEncoding, recordKnowledgeFinalizationResult, unbindSession, writePlan, } from "@veewo/claw-core";
|
|
9
|
+
import { buildDirectWorkflowGuidance, appendKnowledgeTaskConclusions, buildKnowledgeAtomicDispatch, buildKnowledgeDelegateDispatch, buildKnowledgeAssignmentTemplate, buildDirectKnowledgeAssignments, buildKnowledgeWriterAssignments, DEFAULT_MAX_TASKS_TO_KEEP, checkProjectProtocol, ClawError, assertRootPlanCreateAllowedForPlan, buildPlanWorkflowGuidance, buildMemoryIndex, buildSessionStartDefaultPrompt, buildSessionStartRecoveredPrompt, editPlan, ensureProjectProtocol, enforceTaskRetention, findKnowledgeFinalizationJobPath, findTaskDirectory, runDailyMaintenance, ingestTruth, initProject, getTemplateTaskDoneChoices, resolvePlanTemplateFile, resolvePlanEffectiveConfig, resolveKnowledgeWriterForHost, resolveProjectContext, resolveWorkflowProjectContext, resolveSessionWorkflowContext, deleteSessionWorkflow, sweepExpiredSessionWorkflows, resolveSessionBoundPlan, resolveContext, resolveSeedPlanTemplate, searchMemoryAsync, warmProjectMemoryEmbedding, showPlan, createSubplan, createPlanRef, switchTask, tryCaptureKnowledgeStop, claimKnowledgeFinalizationJob, doneKnowledgeFinalizationJob, readKnowledgeFinalizationJob, waitForKnowledgeFinalizationJobReady, listKnowledgeFinalizationJobs, listRetryableKnowledgeFinalizationJobs, normalizeTruthMarkdownEncoding, governKnowledgeMarkdownPaths, resolveKnowledgeDocUpdateSnapshot, recordKnowledgeFinalizationResult, unbindSession, writePlan, } from "@veewo/claw-core";
|
|
10
10
|
import { buildCodexDriverEnvelope } from "./codex-driver.js";
|
|
11
11
|
import { buildCodexHostActions } from "./codex-host-actions.js";
|
|
12
12
|
import { checkCodexRuntime, resolveCodexSdkEntryPath } from "./codex-runtime.js";
|
|
@@ -21,7 +21,7 @@ const TOP_LEVEL_COMMANDS = [
|
|
|
21
21
|
{ name: "context [--task <name>]", summary: "Resolve project context, auto-initializing or correcting .claw state." },
|
|
22
22
|
{ name: "session clean [--expired]", summary: "Remove current or expired session workflow state." },
|
|
23
23
|
{ name: "check", summary: "Check and auto-correct .claw project protocol fields." },
|
|
24
|
-
{ name: "plan <subcommand> [options]", summary: "Plan lifecycle: create, start, edit, remove, wait, resume, sync, show, done." },
|
|
24
|
+
{ name: "plan <subcommand> [options]", summary: "Plan lifecycle: create, start, edit, remove, wait, resume, leave, sync, show, done." },
|
|
25
25
|
{ name: "codex driver", summary: "Return the versioned code-mode driver used by the Codex adapter." },
|
|
26
26
|
{ name: "template <subcommand> [options]", summary: "Plan template helpers such as validation." },
|
|
27
27
|
{ name: "task <subcommand> [options]", summary: "Task lifecycle helpers inside an existing plan." },
|
|
@@ -142,6 +142,11 @@ const COMMAND_HELP = {
|
|
|
142
142
|
{ flag: "--plan-file <relative-path>", detail: "Advanced: override the session-bound plan file." },
|
|
143
143
|
],
|
|
144
144
|
},
|
|
145
|
+
leave: {
|
|
146
|
+
usage: ["{script} plan leave"],
|
|
147
|
+
description: "Explicitly leave the current plan and clear its session binding so a new root plan may be created.",
|
|
148
|
+
summary: "Leave the current plan without completing it.",
|
|
149
|
+
},
|
|
145
150
|
sync: {
|
|
146
151
|
usage: ["{script} plan sync"],
|
|
147
152
|
description: "Resynchronize a recovered active Codex plan with host progress and Goal Mode without mutating the plan.",
|
|
@@ -328,8 +333,28 @@ const COMMAND_HELP = {
|
|
|
328
333
|
},
|
|
329
334
|
knowledge: {
|
|
330
335
|
usage: ["{script} knowledge <subcommand> [options]"],
|
|
331
|
-
description: "
|
|
336
|
+
description: "Commands for queued knowledge finalization jobs and explicit same-agent knowledge capture.",
|
|
332
337
|
subcommands: {
|
|
338
|
+
prepare: {
|
|
339
|
+
usage: ["{script} knowledge prepare --source agent-memory --project-root <path>"],
|
|
340
|
+
description: "Read the current project configuration and return the immutable assignment projection for one explicit manual knowledge capture. It never initializes, repairs, or mutates the project.",
|
|
341
|
+
summary: "Prepare explicit same-agent knowledge capture.",
|
|
342
|
+
options: [
|
|
343
|
+
{ flag: "--source agent-memory", detail: "(required) Only source supported by the manual same-agent route." },
|
|
344
|
+
{ flag: "--project-root <path>", detail: "(required) Project root used to resolve current team and personal configuration." },
|
|
345
|
+
],
|
|
346
|
+
},
|
|
347
|
+
complete: {
|
|
348
|
+
usage: ["{script} knowledge complete --source agent-memory --project-root <path> --config-fingerprint <hash> [--changed-truth <absolute-path> ...]"],
|
|
349
|
+
description: "Validate the prepared configuration, govern declared canonical paths, normalize knowledge encoding, and queue the existing completion refresh without creating a report or job.",
|
|
350
|
+
summary: "Complete explicit same-agent knowledge capture.",
|
|
351
|
+
options: [
|
|
352
|
+
{ flag: "--source agent-memory", detail: "(required) Only source supported by the manual same-agent route." },
|
|
353
|
+
{ flag: "--project-root <path>", detail: "(required) Project root used to resolve current configuration." },
|
|
354
|
+
{ flag: "--config-fingerprint <hash>", detail: "(required) Fingerprint returned by knowledge prepare." },
|
|
355
|
+
{ flag: "--changed-truth <absolute-path>", detail: "Canonical Truth or ADR Markdown path changed by this capture (repeatable)." },
|
|
356
|
+
],
|
|
357
|
+
},
|
|
333
358
|
wait: {
|
|
334
359
|
usage: ["{script} knowledge wait --project-root <path> --finalize-id <id> [--session-key <key>] [--timeout-ms <n>]"],
|
|
335
360
|
description: "Wait for Stop capture to create a knowledge finalization job. This command does not create or inspect session bindings.",
|
|
@@ -1019,6 +1044,24 @@ function readCindyKnowledgeClaimCaptureInput() {
|
|
|
1019
1044
|
async function runKnowledge(args) {
|
|
1020
1045
|
const subcommand = args.shift();
|
|
1021
1046
|
switch (subcommand) {
|
|
1047
|
+
case "prepare": {
|
|
1048
|
+
const source = readRequiredFlag(args, "--source");
|
|
1049
|
+
const projectRoot = path.resolve(readRequiredFlag(args, "--project-root"));
|
|
1050
|
+
assertNoRemainingArgs(args, "knowledge prepare");
|
|
1051
|
+
assertDirectKnowledgeSource(source);
|
|
1052
|
+
printJson(prepareDirectKnowledgeCapture(projectRoot));
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
case "complete": {
|
|
1056
|
+
const source = readRequiredFlag(args, "--source");
|
|
1057
|
+
const projectRoot = path.resolve(readRequiredFlag(args, "--project-root"));
|
|
1058
|
+
const configFingerprint = readRequiredFlag(args, "--config-fingerprint");
|
|
1059
|
+
const changedTruth = readRepeatedFlag(args, "--changed-truth");
|
|
1060
|
+
assertNoRemainingArgs(args, "knowledge complete");
|
|
1061
|
+
assertDirectKnowledgeSource(source);
|
|
1062
|
+
printJson(completeDirectKnowledgeCapture({ projectRoot, configFingerprint, changedTruth }));
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1022
1065
|
case "list": {
|
|
1023
1066
|
const projectRoot = path.resolve(readRequiredFlag(args, "--project-root"));
|
|
1024
1067
|
const sessionKey = readOptionalFlag(args, "--session-key");
|
|
@@ -1200,6 +1243,98 @@ async function runKnowledge(args) {
|
|
|
1200
1243
|
throw new ClawError("PROJECT_CONFIG_INVALID", `Unknown knowledge subcommand "${subcommand ?? ""}".`);
|
|
1201
1244
|
}
|
|
1202
1245
|
}
|
|
1246
|
+
function prepareDirectKnowledgeCapture(projectRoot) {
|
|
1247
|
+
const project = resolveProjectContext(projectRoot);
|
|
1248
|
+
const ownerSessionKey = resolveOwnerSessionKey() ?? undefined;
|
|
1249
|
+
if (ownerSessionKey && resolveSessionBoundPlan(project, ownerSessionKey)) {
|
|
1250
|
+
throw new ClawError("KNOWLEDGE_DIRECT_WORKFLOW_ACTIVE", "Manual knowledge capture cannot run while this session has an active claw workflow.");
|
|
1251
|
+
}
|
|
1252
|
+
const writer = project.projectConfig?.knowledgeWriter;
|
|
1253
|
+
const docUpdate = resolveKnowledgeDocUpdateSnapshot(project);
|
|
1254
|
+
const assignments = buildDirectKnowledgeAssignments({ writer, ...(docUpdate ? { docUpdate } : {}) });
|
|
1255
|
+
for (const assignment of assignments) {
|
|
1256
|
+
for (const resourcePath of [assignment.contractPath, assignment.formatPath]) {
|
|
1257
|
+
if (resourcePath && (!fs.existsSync(resourcePath) || !fs.statSync(resourcePath).isFile())) {
|
|
1258
|
+
throw new ClawError("KNOWLEDGE_DIRECT_RESOURCE_MISSING", "A required knowledge-capture contract resource is unavailable.", { resourcePath });
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
const configFingerprint = directKnowledgeConfigFingerprint({ project, assignments, docUpdate });
|
|
1263
|
+
return {
|
|
1264
|
+
ok: true,
|
|
1265
|
+
command: "knowledge.prepare",
|
|
1266
|
+
schemaVersion: 1,
|
|
1267
|
+
source: "agent-memory",
|
|
1268
|
+
project: { projectRoot: project.projectRoot, truthDir: project.truthDir },
|
|
1269
|
+
configFingerprint,
|
|
1270
|
+
assignments,
|
|
1271
|
+
refresh: {
|
|
1272
|
+
operations: ["memory.reindex.project", ...(project.projectConfig?.gitnexus === true ? ["gitnexus.refresh"] : [])],
|
|
1273
|
+
},
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
function completeDirectKnowledgeCapture(input) {
|
|
1277
|
+
const prepared = prepareDirectKnowledgeCapture(input.projectRoot);
|
|
1278
|
+
if (prepared.configFingerprint !== input.configFingerprint) {
|
|
1279
|
+
throw new ClawError("KNOWLEDGE_DIRECT_CONFIG_CHANGED", "Knowledge-capture configuration changed after prepare; run knowledge prepare again before completion.", { expected: input.configFingerprint, actual: prepared.configFingerprint });
|
|
1280
|
+
}
|
|
1281
|
+
const project = resolveProjectContext(input.projectRoot);
|
|
1282
|
+
const relativePaths = input.changedTruth.map((candidate) => relativeTruthPath(project.truthDir, candidate));
|
|
1283
|
+
const builtin = prepared.assignments.find((assignment) => assignment.kind === "builtin");
|
|
1284
|
+
const governance = builtin
|
|
1285
|
+
? governKnowledgeMarkdownPaths({
|
|
1286
|
+
truthDir: project.truthDir,
|
|
1287
|
+
relativePaths,
|
|
1288
|
+
datedSectionsToKeep: builtin.datedSectionsToKeep ?? 6,
|
|
1289
|
+
})
|
|
1290
|
+
: { changedFiles: 0, compactedFiles: 0, removedSections: 0, files: [] };
|
|
1291
|
+
const truthEncoding = normalizeTruthMarkdownEncoding(project);
|
|
1292
|
+
const refresh = queueCompletionRefresh({
|
|
1293
|
+
cwd: project.projectRoot,
|
|
1294
|
+
taskName: "knowledge-capture",
|
|
1295
|
+
includeTaskRetention: false,
|
|
1296
|
+
statusLabel: "knowledge-capture",
|
|
1297
|
+
});
|
|
1298
|
+
return {
|
|
1299
|
+
ok: true,
|
|
1300
|
+
command: "knowledge.complete",
|
|
1301
|
+
source: "agent-memory",
|
|
1302
|
+
configFingerprint: prepared.configFingerprint,
|
|
1303
|
+
changedTruth: relativePaths,
|
|
1304
|
+
governance,
|
|
1305
|
+
truthEncoding,
|
|
1306
|
+
asyncRefresh: refresh.asyncRefresh,
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
function assertDirectKnowledgeSource(source) {
|
|
1310
|
+
if (source !== "agent-memory") {
|
|
1311
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", 'Manual knowledge capture supports only --source agent-memory.');
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
function relativeTruthPath(truthDir, candidate) {
|
|
1315
|
+
const root = path.resolve(truthDir);
|
|
1316
|
+
const target = path.resolve(candidate);
|
|
1317
|
+
const relative = path.relative(root, target);
|
|
1318
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative) || !/\.md$/iu.test(relative)) {
|
|
1319
|
+
throw new ClawError("KNOWLEDGE_DIRECT_PATH_INVALID", "Changed knowledge paths must be Markdown files inside the resolved truth directory.", { candidate, truthDir: root });
|
|
1320
|
+
}
|
|
1321
|
+
return relative.replaceAll("\\", "/");
|
|
1322
|
+
}
|
|
1323
|
+
function directKnowledgeConfigFingerprint(input) {
|
|
1324
|
+
const payload = {
|
|
1325
|
+
schemaVersion: 1,
|
|
1326
|
+
truthDir: path.resolve(input.project.truthDir),
|
|
1327
|
+
assignments: input.assignments.map((assignment) => ({
|
|
1328
|
+
kind: assignment.kind,
|
|
1329
|
+
skill: assignment.skill ?? null,
|
|
1330
|
+
datedSectionsToKeep: assignment.datedSectionsToKeep ?? null,
|
|
1331
|
+
})),
|
|
1332
|
+
externalDocPaths: input.docUpdate?.externalDocPaths ?? [],
|
|
1333
|
+
gitnexus: input.project.projectConfig?.gitnexus === true,
|
|
1334
|
+
memoryRefresh: input.project.projectConfig?.memory?.enabled !== false,
|
|
1335
|
+
};
|
|
1336
|
+
return `sha256:${createHash("sha256").update(JSON.stringify(payload)).digest("hex")}`;
|
|
1337
|
+
}
|
|
1203
1338
|
async function runPlan(args, effectiveHost) {
|
|
1204
1339
|
const subcommand = args.shift();
|
|
1205
1340
|
switch (subcommand) {
|
|
@@ -1217,7 +1352,9 @@ async function runPlan(args, effectiveHost) {
|
|
|
1217
1352
|
if (!title) {
|
|
1218
1353
|
throw new ClawError("PROJECT_CONFIG_INVALID", "plan create requires a title. Use `claw plan create \"<title>\"` or `claw plan create --title \"<title>\"`.");
|
|
1219
1354
|
}
|
|
1220
|
-
|
|
1355
|
+
const ownerSessionKey = resolveOwnerSessionKey();
|
|
1356
|
+
assertDirectRootPlanCreateAllowed(process.cwd(), ownerSessionKey, scope);
|
|
1357
|
+
await preparePlanCreateWorkflow(process.cwd(), ownerSessionKey, effectiveHost, scope);
|
|
1221
1358
|
const result = await writePlan({
|
|
1222
1359
|
cwd: process.cwd(),
|
|
1223
1360
|
scope,
|
|
@@ -1225,9 +1362,18 @@ async function runPlan(args, effectiveHost) {
|
|
|
1225
1362
|
templateFile: explicitTemplateFile ? path.resolve(process.cwd(), explicitTemplateFile) : undefined,
|
|
1226
1363
|
title,
|
|
1227
1364
|
goalText: readOptionalFlag(args, "--goal"),
|
|
1228
|
-
ownerSessionKey:
|
|
1365
|
+
ownerSessionKey: ownerSessionKey ?? undefined,
|
|
1229
1366
|
host: effectiveHost,
|
|
1230
1367
|
});
|
|
1368
|
+
if (ownerSessionKey && scope !== "session") {
|
|
1369
|
+
const sessionProject = resolveSessionWorkflowContext(ownerSessionKey);
|
|
1370
|
+
if (sessionProject) {
|
|
1371
|
+
const relativePlanPath = path.relative(sessionProject.clawDir, result.planPath);
|
|
1372
|
+
if (relativePlanPath.startsWith("..") || path.isAbsolute(relativePlanPath)) {
|
|
1373
|
+
unbindSession(sessionProject, ownerSessionKey);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1231
1377
|
assertNoRemainingArgs(args, "plan create");
|
|
1232
1378
|
printJson(compactPlanCommandResult("plan.create", result, effectiveHost));
|
|
1233
1379
|
return;
|
|
@@ -1253,8 +1399,8 @@ async function runPlan(args, effectiveHost) {
|
|
|
1253
1399
|
&& effectiveHost !== "cindy") {
|
|
1254
1400
|
throw new ClawError("PROJECT_CONFIG_INVALID", 'knowledgeWriter.executionPolicy "subagent" is supported only by the Codex or Cindy host.', { host: effectiveHost ?? null });
|
|
1255
1401
|
}
|
|
1256
|
-
const
|
|
1257
|
-
?
|
|
1402
|
+
const terminalRefresh = entersEndTerminal
|
|
1403
|
+
? preparePlanTerminalRefresh(process.cwd(), ownerSessionKey)
|
|
1258
1404
|
: undefined;
|
|
1259
1405
|
const result = await editPlan({
|
|
1260
1406
|
cwd: process.cwd(),
|
|
@@ -1276,7 +1422,7 @@ async function runPlan(args, effectiveHost) {
|
|
|
1276
1422
|
writer: effectiveWriter,
|
|
1277
1423
|
})
|
|
1278
1424
|
: undefined;
|
|
1279
|
-
const completionRefresh =
|
|
1425
|
+
const completionRefresh = queueTerminalRefreshIfEntered(result, terminalRefresh);
|
|
1280
1426
|
printJson(compactPlanCommandResult("plan.edit", result, effectiveHost, completionRefresh, false, knowledgeDispatch));
|
|
1281
1427
|
if (result.operationChain?.status === "partial")
|
|
1282
1428
|
process.exitCode = 1;
|
|
@@ -1306,6 +1452,9 @@ async function runPlan(args, effectiveHost) {
|
|
|
1306
1452
|
case "resume":
|
|
1307
1453
|
await runPlanStatusAlias(args, "process.active", "plan.resume", effectiveHost);
|
|
1308
1454
|
return;
|
|
1455
|
+
case "leave":
|
|
1456
|
+
await runPlanLeave(args, effectiveHost);
|
|
1457
|
+
return;
|
|
1309
1458
|
case "sync":
|
|
1310
1459
|
await runPlanSync(args, effectiveHost);
|
|
1311
1460
|
return;
|
|
@@ -1361,7 +1510,7 @@ async function runPlan(args, effectiveHost) {
|
|
|
1361
1510
|
&& effectiveHost !== "cindy") {
|
|
1362
1511
|
throw new ClawError("PROJECT_CONFIG_INVALID", 'knowledgeWriter.executionPolicy "subagent" is supported only by the Codex or Cindy host.', { host: effectiveHost ?? null });
|
|
1363
1512
|
}
|
|
1364
|
-
const
|
|
1513
|
+
const terminalRefresh = preparePlanTerminalRefresh(process.cwd(), ownerSessionKey);
|
|
1365
1514
|
const result = await editPlan({
|
|
1366
1515
|
cwd: process.cwd(),
|
|
1367
1516
|
...target,
|
|
@@ -1380,7 +1529,7 @@ async function runPlan(args, effectiveHost) {
|
|
|
1380
1529
|
writer: effectiveWriter,
|
|
1381
1530
|
})
|
|
1382
1531
|
: undefined;
|
|
1383
|
-
const completionRefresh =
|
|
1532
|
+
const completionRefresh = queueTerminalRefreshIfEntered(result, terminalRefresh);
|
|
1384
1533
|
printJson(compactPlanCommandResult("plan.done", result, effectiveHost, completionRefresh, false, knowledgeDispatch));
|
|
1385
1534
|
return;
|
|
1386
1535
|
}
|
|
@@ -1425,6 +1574,22 @@ async function runPlanStatusAlias(args, planStatus, command, effectiveHost) {
|
|
|
1425
1574
|
assertNoRemainingArgs(args, command);
|
|
1426
1575
|
printJson(compactPlanCommandResult(command, result, effectiveHost, undefined, true));
|
|
1427
1576
|
}
|
|
1577
|
+
async function runPlanLeave(args, effectiveHost) {
|
|
1578
|
+
const ownerSessionKey = resolveOwnerSessionKey() ?? undefined;
|
|
1579
|
+
const target = readPlanMutationTarget(args);
|
|
1580
|
+
assertNoRemainingArgs(args, "plan leave");
|
|
1581
|
+
const terminalRefresh = preparePlanTerminalRefresh(process.cwd(), ownerSessionKey);
|
|
1582
|
+
const result = await editPlan({
|
|
1583
|
+
cwd: process.cwd(),
|
|
1584
|
+
...target,
|
|
1585
|
+
planStatus: "end.leave",
|
|
1586
|
+
commandSource: "plan.edit",
|
|
1587
|
+
host: effectiveHost,
|
|
1588
|
+
ownerSessionKey,
|
|
1589
|
+
});
|
|
1590
|
+
const completionRefresh = queueTerminalRefreshIfEntered(result, terminalRefresh);
|
|
1591
|
+
printJson(compactPlanCommandResult("plan.leave", result, effectiveHost, completionRefresh, true));
|
|
1592
|
+
}
|
|
1428
1593
|
async function runPlanSync(args, effectiveHost) {
|
|
1429
1594
|
const ownerSessionKey = resolveOwnerSessionKey() ?? undefined;
|
|
1430
1595
|
const result = showPlan({ cwd: process.cwd(), ...readPlanMutationTarget(args), ownerSessionKey });
|
|
@@ -1618,7 +1783,10 @@ async function runContextCommand(args, cwd = process.cwd(), ownerSessionKey = re
|
|
|
1618
1783
|
let corrected = false;
|
|
1619
1784
|
let fixedPaths = [];
|
|
1620
1785
|
const sessionProject = resolveSessionWorkflowContext(ownerSessionKey ?? undefined);
|
|
1621
|
-
|
|
1786
|
+
const sessionPlanPath = sessionProject && ownerSessionKey
|
|
1787
|
+
? resolveSessionBoundPlan(sessionProject, ownerSessionKey)
|
|
1788
|
+
: null;
|
|
1789
|
+
if (sessionProject && sessionPlanPath) {
|
|
1622
1790
|
const maintenance = effectiveHost
|
|
1623
1791
|
? null
|
|
1624
1792
|
: runDailyMaintenance(sessionProject, {
|
|
@@ -2175,6 +2343,33 @@ async function preparePlanCreateWorkflow(cwd, ownerSessionKey, effectiveHost, re
|
|
|
2175
2343
|
}
|
|
2176
2344
|
await prepareProjectWorkflow(cwd, ownerSessionKey, effectiveHost, project);
|
|
2177
2345
|
}
|
|
2346
|
+
function assertDirectRootPlanCreateAllowed(cwd, ownerSessionKey, requestedScope) {
|
|
2347
|
+
if (!ownerSessionKey)
|
|
2348
|
+
return;
|
|
2349
|
+
const project = requestedScope === "session"
|
|
2350
|
+
? resolveSessionWorkflowContext(ownerSessionKey)
|
|
2351
|
+
: tryResolveHookProject(cwd);
|
|
2352
|
+
if (!project)
|
|
2353
|
+
return;
|
|
2354
|
+
const planPath = resolveSessionBoundPlan(project, ownerSessionKey);
|
|
2355
|
+
if (!planPath)
|
|
2356
|
+
return;
|
|
2357
|
+
const target = parseTaskPlanPath(project, planPath);
|
|
2358
|
+
if (!target) {
|
|
2359
|
+
throw new ClawError("PLAN_TRANSITION_CONFLICT", `Invalid session-bound plan path: ${planPath}`);
|
|
2360
|
+
}
|
|
2361
|
+
const current = showPlan({
|
|
2362
|
+
cwd,
|
|
2363
|
+
taskName: target.taskName,
|
|
2364
|
+
planFile: target.planFile,
|
|
2365
|
+
ownerSessionKey,
|
|
2366
|
+
});
|
|
2367
|
+
if (current.plan.status.startsWith("end.")) {
|
|
2368
|
+
unbindSession(project, ownerSessionKey);
|
|
2369
|
+
return;
|
|
2370
|
+
}
|
|
2371
|
+
assertRootPlanCreateAllowedForPlan(createPlanRef(project, current.taskName, current.planFile), current.plan);
|
|
2372
|
+
}
|
|
2178
2373
|
async function prepareProjectWorkflow(cwd, ownerSessionKey, effectiveHost, project = tryResolveHookProject(cwd)) {
|
|
2179
2374
|
const sessionProject = resolveSessionWorkflowContext(ownerSessionKey ?? undefined);
|
|
2180
2375
|
if (sessionProject) {
|
|
@@ -3268,11 +3463,24 @@ function readRepeatedIntegerFlag(args, flag) {
|
|
|
3268
3463
|
function failMissingNumericFlag(flag) {
|
|
3269
3464
|
throw new ClawError("PROJECT_CONFIG_INVALID", `Missing required flag ${flag}.`, { flag });
|
|
3270
3465
|
}
|
|
3271
|
-
function
|
|
3466
|
+
function preparePlanTerminalRefresh(cwd, ownerSessionKey) {
|
|
3272
3467
|
const workflowProject = resolveWorkflowProjectContext(cwd, ownerSessionKey);
|
|
3273
|
-
|
|
3468
|
+
const refreshProject = tryResolveHookProject(workflowProject.projectRoot);
|
|
3469
|
+
if (!refreshProject)
|
|
3274
3470
|
return undefined;
|
|
3275
|
-
return
|
|
3471
|
+
return {
|
|
3472
|
+
queue: (taskName) => queueCompletionRefresh({
|
|
3473
|
+
cwd: refreshProject.projectRoot,
|
|
3474
|
+
taskName,
|
|
3475
|
+
includeTaskRetention: workflowProject.scope !== "session",
|
|
3476
|
+
}),
|
|
3477
|
+
};
|
|
3478
|
+
}
|
|
3479
|
+
function queueTerminalRefreshIfEntered(result, terminalRefresh) {
|
|
3480
|
+
if (!terminalRefresh || result.previousPlanStatus.startsWith("end.") || !result.planStatus.startsWith("end.")) {
|
|
3481
|
+
return undefined;
|
|
3482
|
+
}
|
|
3483
|
+
return terminalRefresh.queue(result.taskName);
|
|
3276
3484
|
}
|
|
3277
3485
|
function queueCompletionRefresh(input) {
|
|
3278
3486
|
const project = resolveProjectContext(input.cwd);
|