@veewo/claw 0.2.2 → 0.2.3
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 +83 -83
- package/dist/cli.js +197 -35
- package/dist/cli.js.map +1 -1
- package/package.json +41 -41
package/README.md
CHANGED
|
@@ -1,83 +1,83 @@
|
|
|
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
|
-
Then run:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
claw init
|
|
29
|
-
claw search index --refresh
|
|
30
|
-
claw search "existing truth or ADR topic"
|
|
31
|
-
claw plan create --title "My task" --goal "Define the first task"
|
|
32
|
-
claw plan create "My templated task" --template default --goal "Route through the default template"
|
|
33
|
-
claw plan create "Ephemeral harness" --scope session --goal "Use plan and Goal workflows without project deposition"
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
`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>"`.
|
|
37
|
-
|
|
38
|
-
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
|
|
39
|
-
|
|
40
|
-
`--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/GitNexus refresh, and project retention. Use `claw session clean` for the current session or `claw session clean --expired` for the seven-day TTL sweep.
|
|
41
|
-
|
|
42
|
-
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.
|
|
43
|
-
|
|
44
|
-
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.
|
|
45
|
-
|
|
46
|
-
When `planning: false`, `claw plan create` seeds the smallest executable plan directly in `process.active`.
|
|
47
|
-
|
|
48
|
-
## Workflow shape
|
|
49
|
-
|
|
50
|
-
In a typical round, the CLI helps land this loop in a project:
|
|
51
|
-
|
|
52
|
-
`plan` -> `search and recall` -> `execute` -> `deposit truth / ADR` -> `close out`
|
|
53
|
-
|
|
54
|
-
That project-level plan structure helps agents carry longer-running work more cleanly than leaving the task in loose chat state alone.
|
|
55
|
-
|
|
56
|
-
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.
|
|
57
|
-
|
|
58
|
-
## Search and recall
|
|
59
|
-
|
|
60
|
-
`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.
|
|
61
|
-
|
|
62
|
-
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.
|
|
63
|
-
|
|
64
|
-
Typical setup:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
claw context
|
|
68
|
-
claw search index --refresh
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
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).
|
|
72
|
-
|
|
73
|
-
## Configuration
|
|
74
|
-
|
|
75
|
-
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.
|
|
76
|
-
|
|
77
|
-
`claw-kit` also stays usable alongside other harnesses or external skills, so the CLI does not assume a single host or investigation surface.
|
|
78
|
-
|
|
79
|
-
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.
|
|
80
|
-
|
|
81
|
-
## Repository
|
|
82
|
-
|
|
83
|
-
- [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
|
+
Then run:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
claw init
|
|
29
|
+
claw search index --refresh
|
|
30
|
+
claw search "existing truth or ADR topic"
|
|
31
|
+
claw plan create --title "My task" --goal "Define the first task"
|
|
32
|
+
claw plan create "My templated task" --template default --goal "Route through the default template"
|
|
33
|
+
claw plan create "Ephemeral harness" --scope session --goal "Use plan and Goal workflows without project deposition"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`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>"`.
|
|
37
|
+
|
|
38
|
+
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.
|
|
39
|
+
|
|
40
|
+
`--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/GitNexus refresh, and project retention. Use `claw session clean` for the current session or `claw session clean --expired` for the seven-day TTL sweep.
|
|
41
|
+
|
|
42
|
+
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.
|
|
43
|
+
|
|
44
|
+
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.
|
|
45
|
+
|
|
46
|
+
When `planning: false`, `claw plan create` seeds the smallest executable plan directly in `process.active`.
|
|
47
|
+
|
|
48
|
+
## Workflow shape
|
|
49
|
+
|
|
50
|
+
In a typical round, the CLI helps land this loop in a project:
|
|
51
|
+
|
|
52
|
+
`plan` -> `search and recall` -> `execute` -> `deposit truth / ADR` -> `close out`
|
|
53
|
+
|
|
54
|
+
That project-level plan structure helps agents carry longer-running work more cleanly than leaving the task in loose chat state alone.
|
|
55
|
+
|
|
56
|
+
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.
|
|
57
|
+
|
|
58
|
+
## Search and recall
|
|
59
|
+
|
|
60
|
+
`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.
|
|
61
|
+
|
|
62
|
+
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.
|
|
63
|
+
|
|
64
|
+
Typical setup:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
claw context
|
|
68
|
+
claw search index --refresh
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
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).
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
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.
|
|
76
|
+
|
|
77
|
+
`claw-kit` also stays usable alongside other harnesses or external skills, so the CLI does not assume a single host or investigation surface.
|
|
78
|
+
|
|
79
|
+
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.
|
|
80
|
+
|
|
81
|
+
## Repository
|
|
82
|
+
|
|
83
|
+
- [claw-kit](https://github.com/chanyuenpang/claw-kit)
|
package/dist/cli.js
CHANGED
|
@@ -394,6 +394,28 @@ const COMMAND_HELP = {
|
|
|
394
394
|
description: "Internal: warms the configured local persistent embedding session after context recovery without delaying SessionStart.",
|
|
395
395
|
options: [{ flag: "--cwd <dir>", detail: "(required) Project root." }],
|
|
396
396
|
},
|
|
397
|
+
"internal-daily-maintenance": {
|
|
398
|
+
usage: ["{script} internal-daily-maintenance --cwd <dir> [--session-key <key>] [--session-only]"],
|
|
399
|
+
description: "Internal: runs the lock-protected daily cleanup asynchronously after context recovery.",
|
|
400
|
+
options: [
|
|
401
|
+
{ flag: "--cwd <dir>", detail: "(required) Current workspace directory." },
|
|
402
|
+
{ flag: "--session-key <key>", detail: "Optional owner session key used for session workflow maintenance." },
|
|
403
|
+
{ flag: "--session-only", detail: "Only maintain the session workflow; do not touch project tasks." },
|
|
404
|
+
],
|
|
405
|
+
},
|
|
406
|
+
"internal-knowledge-sweep": {
|
|
407
|
+
usage: ["{script} internal-knowledge-sweep --cwd <dir>"],
|
|
408
|
+
description: "Internal: discovers retryable knowledge jobs and launches their detached finalizers.",
|
|
409
|
+
options: [{ flag: "--cwd <dir>", detail: "(required) Project root." }],
|
|
410
|
+
},
|
|
411
|
+
"internal-background-maintenance": {
|
|
412
|
+
usage: ["{script} internal-background-maintenance --cwd <dir> [--session-key <key>]"],
|
|
413
|
+
description: "Internal: runs non-blocking cleanup, embedding warmup, and knowledge job discovery in one worker.",
|
|
414
|
+
options: [
|
|
415
|
+
{ flag: "--cwd <dir>", detail: "(required) Current workspace directory." },
|
|
416
|
+
{ flag: "--session-key <key>", detail: "Optional owner session key used for session workflow maintenance." },
|
|
417
|
+
],
|
|
418
|
+
},
|
|
397
419
|
};
|
|
398
420
|
async function main() {
|
|
399
421
|
const args = process.argv.slice(2);
|
|
@@ -527,6 +549,15 @@ async function main() {
|
|
|
527
549
|
case "internal-embedding-warmup":
|
|
528
550
|
await runInternalEmbeddingWarmup(args);
|
|
529
551
|
return;
|
|
552
|
+
case "internal-daily-maintenance":
|
|
553
|
+
runInternalDailyMaintenance(args);
|
|
554
|
+
return;
|
|
555
|
+
case "internal-knowledge-sweep":
|
|
556
|
+
runInternalKnowledgeSweep(args);
|
|
557
|
+
return;
|
|
558
|
+
case "internal-background-maintenance":
|
|
559
|
+
await runInternalBackgroundMaintenance(args);
|
|
560
|
+
return;
|
|
530
561
|
default:
|
|
531
562
|
printTopLevelUsage();
|
|
532
563
|
process.exitCode = 1;
|
|
@@ -717,8 +748,6 @@ async function runPlan(args, effectiveHost) {
|
|
|
717
748
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
718
749
|
&& result.knowledgeFinalizeId)
|
|
719
750
|
? buildKnowledgeDispatch({
|
|
720
|
-
projectRoot: project.projectRoot,
|
|
721
|
-
taskName: result.taskName,
|
|
722
751
|
finalizeId: result.knowledgeFinalizeId,
|
|
723
752
|
writer: effectiveWriter,
|
|
724
753
|
})
|
|
@@ -820,8 +849,6 @@ async function runPlan(args, effectiveHost) {
|
|
|
820
849
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
821
850
|
&& result.knowledgeFinalizeId)
|
|
822
851
|
? buildKnowledgeDispatch({
|
|
823
|
-
projectRoot: project.projectRoot,
|
|
824
|
-
taskName: result.taskName,
|
|
825
852
|
finalizeId: result.knowledgeFinalizeId,
|
|
826
853
|
writer: effectiveWriter,
|
|
827
854
|
})
|
|
@@ -1057,7 +1084,15 @@ async function runContextCommand(args, cwd = process.cwd(), ownerSessionKey = re
|
|
|
1057
1084
|
let fixedPaths = [];
|
|
1058
1085
|
const sessionProject = resolveSessionWorkflowContext(ownerSessionKey ?? undefined);
|
|
1059
1086
|
if (sessionProject) {
|
|
1060
|
-
const maintenance =
|
|
1087
|
+
const maintenance = effectiveHost
|
|
1088
|
+
? null
|
|
1089
|
+
: runDailyMaintenance(sessionProject, {
|
|
1090
|
+
excludeSessionKey: ownerSessionKey ?? undefined,
|
|
1091
|
+
includeProject: false,
|
|
1092
|
+
});
|
|
1093
|
+
if (effectiveHost) {
|
|
1094
|
+
launchDailyMaintenance(cwd, ownerSessionKey, true);
|
|
1095
|
+
}
|
|
1061
1096
|
const activeWorkflow = !taskName && ownerSessionKey
|
|
1062
1097
|
? await tryResolveActiveWorkflowSnapshot(cwd, ownerSessionKey, effectiveHost)
|
|
1063
1098
|
: null;
|
|
@@ -1068,7 +1103,7 @@ async function runContextCommand(args, cwd = process.cwd(), ownerSessionKey = re
|
|
|
1068
1103
|
return {
|
|
1069
1104
|
project: sessionProject,
|
|
1070
1105
|
...(activeWorkflow ? { activeWorkflow } : {}),
|
|
1071
|
-
...(maintenance
|
|
1106
|
+
...(maintenance?.ran ? { maintenance } : {}),
|
|
1072
1107
|
...(codexRuntimeError ? { error: codexRuntimeError } : {}),
|
|
1073
1108
|
};
|
|
1074
1109
|
}
|
|
@@ -1084,7 +1119,13 @@ async function runContextCommand(args, cwd = process.cwd(), ownerSessionKey = re
|
|
|
1084
1119
|
initProject({ cwd, version: CLI_VERSION });
|
|
1085
1120
|
initialized = true;
|
|
1086
1121
|
}
|
|
1087
|
-
const
|
|
1122
|
+
const project = resolveProjectContext(cwd);
|
|
1123
|
+
const maintenance = effectiveHost
|
|
1124
|
+
? null
|
|
1125
|
+
: runDailyMaintenance(project, { excludeSessionKey: ownerSessionKey ?? undefined });
|
|
1126
|
+
if (effectiveHost) {
|
|
1127
|
+
launchDailyMaintenance(cwd, ownerSessionKey, false);
|
|
1128
|
+
}
|
|
1088
1129
|
let resolved = resolveContext(cwd, taskName);
|
|
1089
1130
|
const versionSync = syncProjectVersionWithCli(cwd, resolved.project);
|
|
1090
1131
|
if (versionSync.projectVersionUpdated) {
|
|
@@ -1104,7 +1145,7 @@ async function runContextCommand(args, cwd = process.cwd(), ownerSessionKey = re
|
|
|
1104
1145
|
launchProjectEmbeddingWarmup(resolved.project);
|
|
1105
1146
|
return {
|
|
1106
1147
|
...resolved,
|
|
1107
|
-
...(maintenance
|
|
1148
|
+
...(maintenance?.ran ? { maintenance } : {}),
|
|
1108
1149
|
...(activeWorkflow ? { activeWorkflow } : {}),
|
|
1109
1150
|
...(codexRuntimeError ? { error: codexRuntimeError } : {}),
|
|
1110
1151
|
protocolCheck: checkProjectProtocol(cwd),
|
|
@@ -1152,6 +1193,28 @@ function launchProjectEmbeddingWarmup(project) {
|
|
|
1152
1193
|
// Context recovery is authoritative; embedding warmup is fail-open latency work.
|
|
1153
1194
|
}
|
|
1154
1195
|
}
|
|
1196
|
+
function launchDailyMaintenance(cwd, ownerSessionKey, sessionOnly) {
|
|
1197
|
+
const args = [resolveCliEntryPath(), "internal-daily-maintenance", "--cwd", cwd];
|
|
1198
|
+
if (ownerSessionKey) {
|
|
1199
|
+
args.push("--session-key", ownerSessionKey);
|
|
1200
|
+
}
|
|
1201
|
+
if (sessionOnly) {
|
|
1202
|
+
args.push("--session-only");
|
|
1203
|
+
}
|
|
1204
|
+
try {
|
|
1205
|
+
const child = spawn(process.execPath, args, {
|
|
1206
|
+
cwd,
|
|
1207
|
+
detached: true,
|
|
1208
|
+
stdio: "ignore",
|
|
1209
|
+
windowsHide: true,
|
|
1210
|
+
env: withoutInvocationHost(),
|
|
1211
|
+
});
|
|
1212
|
+
child.unref();
|
|
1213
|
+
}
|
|
1214
|
+
catch {
|
|
1215
|
+
// Context recovery is authoritative; daily cleanup is fail-open latency work.
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1155
1218
|
function buildPublicContextOutput(context) {
|
|
1156
1219
|
const project = asJsonRecord(context.project);
|
|
1157
1220
|
const output = {};
|
|
@@ -1441,6 +1504,7 @@ async function runInternalKnowledgeCapture(args, effectiveHost) {
|
|
|
1441
1504
|
const sessionId = resolveOwnerSessionKey(payload);
|
|
1442
1505
|
const turnId = readHookString(payload, "turn_id");
|
|
1443
1506
|
const message = readHookString(payload, "message");
|
|
1507
|
+
const taskConclusions = readHookTaskConclusions(payload, turnId);
|
|
1444
1508
|
if (!hookCwd || !sessionId || !turnId || !message || !containsClawDir(hookCwd)) {
|
|
1445
1509
|
printJson({ ok: true, captured: false });
|
|
1446
1510
|
return;
|
|
@@ -1453,6 +1517,7 @@ async function runInternalKnowledgeCapture(args, effectiveHost) {
|
|
|
1453
1517
|
turnId,
|
|
1454
1518
|
message,
|
|
1455
1519
|
host: effectiveHost === "cindy" ? "cindy" : effectiveHost,
|
|
1520
|
+
taskConclusions,
|
|
1456
1521
|
});
|
|
1457
1522
|
printJson(result);
|
|
1458
1523
|
}
|
|
@@ -1583,6 +1648,86 @@ async function runInternalEmbeddingWarmup(args) {
|
|
|
1583
1648
|
...await warmProjectMemoryEmbedding({ cwd }),
|
|
1584
1649
|
});
|
|
1585
1650
|
}
|
|
1651
|
+
function runInternalDailyMaintenance(args) {
|
|
1652
|
+
const cwd = readRequiredFlag(args, "--cwd");
|
|
1653
|
+
const sessionKey = readOptionalFlag(args, "--session-key");
|
|
1654
|
+
const sessionOnly = readBooleanFlag(args, "--session-only");
|
|
1655
|
+
assertNoRemainingArgs(args, "internal-daily-maintenance");
|
|
1656
|
+
const project = sessionOnly
|
|
1657
|
+
? (sessionKey ? resolveSessionWorkflowContext(sessionKey) : null)
|
|
1658
|
+
: resolveProjectContext(cwd);
|
|
1659
|
+
if (!project) {
|
|
1660
|
+
printJson({ command: "internal-daily-maintenance", ok: true, ran: false, skipped: true });
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
printJson({
|
|
1664
|
+
command: "internal-daily-maintenance",
|
|
1665
|
+
ok: true,
|
|
1666
|
+
...runDailyMaintenance(project, {
|
|
1667
|
+
excludeSessionKey: sessionKey ?? undefined,
|
|
1668
|
+
includeProject: !sessionOnly,
|
|
1669
|
+
}),
|
|
1670
|
+
});
|
|
1671
|
+
}
|
|
1672
|
+
function runInternalKnowledgeSweep(args) {
|
|
1673
|
+
const cwd = readRequiredFlag(args, "--cwd");
|
|
1674
|
+
assertNoRemainingArgs(args, "internal-knowledge-sweep");
|
|
1675
|
+
const project = tryResolveHookProject(cwd);
|
|
1676
|
+
if (!project) {
|
|
1677
|
+
printJson({ command: "internal-knowledge-sweep", ok: true, launched: 0, skipped: true });
|
|
1678
|
+
return;
|
|
1679
|
+
}
|
|
1680
|
+
const jobs = listRetryableKnowledgeFinalizationJobs(project);
|
|
1681
|
+
let launched = 0;
|
|
1682
|
+
for (const jobPath of jobs) {
|
|
1683
|
+
try {
|
|
1684
|
+
launchKnowledgeFinalizationWorker(jobPath, project.projectRoot);
|
|
1685
|
+
launched += 1;
|
|
1686
|
+
}
|
|
1687
|
+
catch {
|
|
1688
|
+
// A later background sweep can retry a job that could not be launched.
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
printJson({ command: "internal-knowledge-sweep", ok: true, discovered: jobs.length, launched });
|
|
1692
|
+
}
|
|
1693
|
+
async function runInternalBackgroundMaintenance(args) {
|
|
1694
|
+
const cwd = readRequiredFlag(args, "--cwd");
|
|
1695
|
+
const sessionKey = readOptionalFlag(args, "--session-key");
|
|
1696
|
+
assertNoRemainingArgs(args, "internal-background-maintenance");
|
|
1697
|
+
const sessionProject = sessionKey ? resolveSessionWorkflowContext(sessionKey) : null;
|
|
1698
|
+
const project = sessionProject ? null : tryResolveHookProject(cwd);
|
|
1699
|
+
let maintenance = { ran: false, skipped: true };
|
|
1700
|
+
if (sessionProject) {
|
|
1701
|
+
maintenance = runDailyMaintenance(sessionProject, { excludeSessionKey: sessionKey ?? undefined, includeProject: false });
|
|
1702
|
+
}
|
|
1703
|
+
else if (project) {
|
|
1704
|
+
maintenance = runDailyMaintenance(project, { excludeSessionKey: sessionKey ?? undefined });
|
|
1705
|
+
}
|
|
1706
|
+
let embedding = { warmed: false, reason: "skipped" };
|
|
1707
|
+
try {
|
|
1708
|
+
embedding = await warmProjectMemoryEmbedding({ cwd });
|
|
1709
|
+
}
|
|
1710
|
+
catch (error) {
|
|
1711
|
+
embedding = { warmed: false, reason: "failed", error: error instanceof Error ? error.message : String(error) };
|
|
1712
|
+
}
|
|
1713
|
+
let discovered = 0;
|
|
1714
|
+
let launched = 0;
|
|
1715
|
+
const knowledgeProject = project ?? sessionProject;
|
|
1716
|
+
if (knowledgeProject) {
|
|
1717
|
+
const jobs = listRetryableKnowledgeFinalizationJobs(knowledgeProject);
|
|
1718
|
+
discovered = jobs.length;
|
|
1719
|
+
for (const jobPath of jobs) {
|
|
1720
|
+
try {
|
|
1721
|
+
launchKnowledgeFinalizationWorker(jobPath, knowledgeProject.projectRoot);
|
|
1722
|
+
launched += 1;
|
|
1723
|
+
}
|
|
1724
|
+
catch {
|
|
1725
|
+
// A later background sweep can retry a job that could not be launched.
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
printJson({ command: "internal-background-maintenance", ok: true, maintenance, embedding, discovered, launched });
|
|
1730
|
+
}
|
|
1586
1731
|
async function runInternalKnowledgeFinalize(args) {
|
|
1587
1732
|
const jobPath = readRequiredFlag(args, "--job");
|
|
1588
1733
|
const queued = readKnowledgeFinalizationJob(jobPath);
|
|
@@ -1640,8 +1785,6 @@ async function runInternalKnowledgeFinalize(args) {
|
|
|
1640
1785
|
async function runKnowledgeDelegateForJob(running) {
|
|
1641
1786
|
const dispatch = buildKnowledgeDelegateDispatch({
|
|
1642
1787
|
policy: "background",
|
|
1643
|
-
projectRoot: running.projectRoot,
|
|
1644
|
-
taskName: running.taskName,
|
|
1645
1788
|
finalizeId: running.finalizeId,
|
|
1646
1789
|
writer: running.writer,
|
|
1647
1790
|
});
|
|
@@ -1770,7 +1913,7 @@ async function runSessionStartHook(effectiveHost) {
|
|
|
1770
1913
|
try {
|
|
1771
1914
|
const context = await runContextCommand([], hookCwd, ownerSessionKey, effectiveHost);
|
|
1772
1915
|
const contextProject = asJsonRecord(context.project);
|
|
1773
|
-
const retryableJobs = contextProject?.scope !== "session" && !context.error
|
|
1916
|
+
const retryableJobs = effectiveHost !== "cindy" && contextProject?.scope !== "session" && !context.error
|
|
1774
1917
|
? listRetryableKnowledgeFinalizationJobs(resolveProjectContext(hookCwd))
|
|
1775
1918
|
: [];
|
|
1776
1919
|
if (contextProject?.scope !== "session"
|
|
@@ -1795,7 +1938,6 @@ async function runSessionStartHook(effectiveHost) {
|
|
|
1795
1938
|
hookSpecificOutput: {
|
|
1796
1939
|
hookEventName: "SessionStart",
|
|
1797
1940
|
additionalContext,
|
|
1798
|
-
...(effectiveHost === "cindy" ? { knowledgeJobs: retryableJobs } : {}),
|
|
1799
1941
|
},
|
|
1800
1942
|
})}\n`);
|
|
1801
1943
|
}
|
|
@@ -1829,6 +1971,21 @@ function readHookString(payload, key) {
|
|
|
1829
1971
|
const value = payload[key];
|
|
1830
1972
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
1831
1973
|
}
|
|
1974
|
+
function readHookTaskConclusions(payload, turnId) {
|
|
1975
|
+
if (!turnId || !payload || typeof payload !== "object")
|
|
1976
|
+
return [];
|
|
1977
|
+
const value = payload.task_conclusions;
|
|
1978
|
+
if (!Array.isArray(value))
|
|
1979
|
+
return [];
|
|
1980
|
+
return value.flatMap((item) => {
|
|
1981
|
+
if (!item || typeof item !== "object")
|
|
1982
|
+
return [];
|
|
1983
|
+
const message = item.message;
|
|
1984
|
+
return typeof message === "string" && message.trim()
|
|
1985
|
+
? [{ turnId, message: message.trim() }]
|
|
1986
|
+
: [];
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1832
1989
|
function containsClawDir(cwd) {
|
|
1833
1990
|
try {
|
|
1834
1991
|
const startDir = path.resolve(cwd);
|
|
@@ -1869,10 +2026,10 @@ function safeResolveTempDir() {
|
|
|
1869
2026
|
}
|
|
1870
2027
|
}
|
|
1871
2028
|
function buildSessionStartAdditionalContext(context, sessionCwd, effectiveHost) {
|
|
2029
|
+
const versionSyncPrompt = buildVersionSyncPrompt(context);
|
|
1872
2030
|
if (effectiveHost === "cindy") {
|
|
1873
|
-
return buildCindySessionStartContext(context, sessionCwd);
|
|
2031
|
+
return buildCindySessionStartContext(context, sessionCwd, versionSyncPrompt);
|
|
1874
2032
|
}
|
|
1875
|
-
const versionSyncPrompt = buildVersionSyncPrompt(context);
|
|
1876
2033
|
const searchGuidance = buildContextSearchGuidance(context);
|
|
1877
2034
|
const runtimeErrorPrompt = buildCodexRuntimeErrorPrompt(context);
|
|
1878
2035
|
const activeWorkflow = context.activeWorkflow;
|
|
@@ -1909,37 +2066,42 @@ function buildSessionStartAdditionalContext(context, sessionCwd, effectiveHost)
|
|
|
1909
2066
|
}
|
|
1910
2067
|
/**
|
|
1911
2068
|
* Cindy Agents use the Ghost Tool gateway, not shell commands or Host actions.
|
|
1912
|
-
*
|
|
1913
|
-
*
|
|
2069
|
+
* Match the Codex session-start wording and structure. Cindy's static entry
|
|
2070
|
+
* prompt supplies the shared skill and guidance lines; this dynamic context
|
|
2071
|
+
* supplies project identity or a recovered workflow snapshot. Goal Mode is
|
|
2072
|
+
* intentionally omitted because Cindy does not expose that Host surface.
|
|
1914
2073
|
*/
|
|
1915
|
-
function buildCindySessionStartContext(context, sessionCwd) {
|
|
2074
|
+
function buildCindySessionStartContext(context, sessionCwd, versionSyncPrompt) {
|
|
1916
2075
|
const activeWorkflow = asJsonRecord(context.activeWorkflow);
|
|
1917
2076
|
if (activeWorkflow) {
|
|
1918
|
-
|
|
1919
|
-
const planStatus = typeof activeWorkflow.planStatus === "string" ? activeWorkflow.planStatus.trim() : "unknown";
|
|
1920
|
-
const planSummary = typeof activeWorkflow.planSummary === "string" ? activeWorkflow.planSummary.trim() : "";
|
|
1921
|
-
const nextTask = asJsonRecord(activeWorkflow.workflowGuidance)?.nextTask;
|
|
1922
|
-
const nextTaskTitle = asJsonRecord(nextTask)?.title;
|
|
1923
|
-
const lines = [
|
|
1924
|
-
"claw-kit recovered a Cindy workflow.",
|
|
1925
|
-
`- task: ${taskName}`,
|
|
1926
|
-
`- plan status: ${planStatus}`,
|
|
1927
|
-
...(planSummary ? [`- plan summary: ${planSummary}`] : []),
|
|
1928
|
-
...(typeof nextTaskTitle === "string" && nextTaskTitle.trim() ? [`- next task: ${nextTaskTitle.trim()}`] : []),
|
|
1929
|
-
"Use the claw-kit Ghost tools to inspect or advance this workflow. Do not run claw shell commands or manage host/session/Goal state yourself.",
|
|
1930
|
-
];
|
|
1931
|
-
return lines.join("\n");
|
|
2077
|
+
return stripCindyGoalModeLines(buildRecoveredWorkflowAdditionalContext(activeWorkflow, versionSyncPrompt));
|
|
1932
2078
|
}
|
|
1933
2079
|
const project = asJsonRecord(context.project);
|
|
1934
2080
|
if (!project)
|
|
1935
2081
|
return null;
|
|
1936
2082
|
const projectName = typeof project.projectName === "string" && project.projectName.trim()
|
|
1937
2083
|
? project.projectName.trim()
|
|
1938
|
-
:
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
2084
|
+
: typeof project.projectId === "string" && project.projectId.trim()
|
|
2085
|
+
? project.projectId.trim()
|
|
2086
|
+
: path.basename(String(project.projectRoot ?? sessionCwd ?? "project"));
|
|
2087
|
+
const projectRoot = typeof project.projectRoot === "string" ? project.projectRoot : sessionCwd;
|
|
2088
|
+
const projectId = typeof project.projectId === "string" ? project.projectId : projectName;
|
|
2089
|
+
const clawDir = typeof project.clawDir === "string" ? project.clawDir : path.join(projectRoot, ".claw");
|
|
2090
|
+
const prompt = [
|
|
2091
|
+
`This session started inside a .claw project: ${projectName} (${projectId}).`,
|
|
2092
|
+
`.claw directory: ${clawDir}`,
|
|
1942
2093
|
].join("\n");
|
|
2094
|
+
if (!versionSyncPrompt)
|
|
2095
|
+
return prompt;
|
|
2096
|
+
return versionSyncPrompt.placement === "prefix"
|
|
2097
|
+
? `${versionSyncPrompt.lines.join("\n")}\n${prompt}`
|
|
2098
|
+
: `${prompt}\n${versionSyncPrompt.lines.join("\n")}`;
|
|
2099
|
+
}
|
|
2100
|
+
function stripCindyGoalModeLines(prompt) {
|
|
2101
|
+
return prompt
|
|
2102
|
+
.split("\n")
|
|
2103
|
+
.filter((line) => !/goal mode/i.test(line))
|
|
2104
|
+
.join("\n");
|
|
1943
2105
|
}
|
|
1944
2106
|
function buildCodexRuntimeErrorPrompt(context) {
|
|
1945
2107
|
const error = asJsonRecord(context.error);
|