@veewo/claw 0.2.4 → 0.2.5
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/dist/cli.js +128 -23
- package/dist/cli.js.map +1 -1
- package/dist/codex-transcript.d.ts +2 -1
- package/dist/codex-transcript.js +52 -2
- package/dist/codex-transcript.js.map +1 -1
- package/dist/command-service.js +16 -10
- package/dist/command-service.js.map +1 -1
- package/dist/knowledge-hook-preflight.js +6 -2
- package/dist/knowledge-hook-preflight.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -6,11 +6,11 @@ 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, 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, 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, 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";
|
|
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";
|
|
13
|
-
import { extractLatestFinalAssistantMessage, extractTaskDoneConclusions, } from "./codex-transcript.js";
|
|
13
|
+
import { extractLatestFinalAssistantMessage, extractTaskDoneConclusions, findCodexTranscriptPath, } from "./codex-transcript.js";
|
|
14
14
|
import { consumeBufferedHookInput } from "./knowledge-hook-preflight.js";
|
|
15
15
|
import { resolveInvocationHost, withoutInvocationHost } from "./invocation-host.js";
|
|
16
16
|
import { runOpencodeKnowledgeWriter } from "./opencode-runner.js";
|
|
@@ -283,7 +283,7 @@ const COMMAND_HELP = {
|
|
|
283
283
|
description: "Create a flat subplan file under the task directory. Uses explicit `--template` first, otherwise the project's configured `defaultPlanTemplate`, and finally falls back to the built-in `default`. The current session binding switches to the subplan and returns to its parent when the subplan ends.",
|
|
284
284
|
summary: "Create a subplan under a parent task's task item.",
|
|
285
285
|
options: [
|
|
286
|
-
{ flag: "--parent <task-name>", detail: "(required) Parent task name." },
|
|
286
|
+
{ flag: "--parent <task-name>", detail: "(required) Parent task directory name (`taskName`), not its plan title." },
|
|
287
287
|
{ flag: "--task-id <number>", detail: "(required) Parent task item id to split into a subplan." },
|
|
288
288
|
{ flag: "--template <name>", detail: "Optional plan template name. Overrides the project's configured default template." },
|
|
289
289
|
{ flag: "--template-file <path>", detail: "Exact plan template file. Mutually exclusive with --template." },
|
|
@@ -336,10 +336,17 @@ const COMMAND_HELP = {
|
|
|
336
336
|
],
|
|
337
337
|
},
|
|
338
338
|
claim: {
|
|
339
|
-
usage: [
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
339
|
+
usage: [
|
|
340
|
+
"{script} knowledge claim --job <path>",
|
|
341
|
+
"{script} knowledge claim --project-root <path> --finalize-id <id>",
|
|
342
|
+
],
|
|
343
|
+
description: "Claim a queued or retryable job. Codex subagent claims capture the existing task conclusions from the parent transcript before ownership is granted.",
|
|
344
|
+
summary: "Claim a ready finalization job and prepare its report.",
|
|
345
|
+
options: [
|
|
346
|
+
{ flag: "--job <path>", detail: "Exact finalization job JSON path." },
|
|
347
|
+
{ flag: "--project-root <path>", detail: "Project that owns a ready finalization job." },
|
|
348
|
+
{ flag: "--finalize-id <id>", detail: "Finalization id used with --project-root." },
|
|
349
|
+
],
|
|
343
350
|
},
|
|
344
351
|
done: {
|
|
345
352
|
usage: [
|
|
@@ -977,6 +984,35 @@ function serializeSessionError(error) {
|
|
|
977
984
|
}
|
|
978
985
|
return { code: "SESSION_COMMAND_FAILED", message: error instanceof Error ? error.message : String(error) };
|
|
979
986
|
}
|
|
987
|
+
function readCindyKnowledgeClaimCaptureInput() {
|
|
988
|
+
const raw = fs.readFileSync(0, "utf8").trim();
|
|
989
|
+
if (!raw) {
|
|
990
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", "Cindy knowledge claim report input is empty.");
|
|
991
|
+
}
|
|
992
|
+
let parsed;
|
|
993
|
+
try {
|
|
994
|
+
parsed = JSON.parse(raw);
|
|
995
|
+
}
|
|
996
|
+
catch {
|
|
997
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", "Cindy knowledge claim report input is invalid JSON.");
|
|
998
|
+
}
|
|
999
|
+
const sessionId = typeof parsed.session_id === "string" ? parsed.session_id.trim() : "";
|
|
1000
|
+
const turnId = typeof parsed.turn_id === "string" ? parsed.turn_id.trim() : "";
|
|
1001
|
+
const taskConclusions = Array.isArray(parsed.task_conclusions)
|
|
1002
|
+
? parsed.task_conclusions.flatMap((entry) => {
|
|
1003
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
1004
|
+
return [];
|
|
1005
|
+
const item = entry;
|
|
1006
|
+
const itemTurnId = typeof item.turnId === "string" ? item.turnId.trim() : "";
|
|
1007
|
+
const message = typeof item.message === "string" ? item.message.trim() : "";
|
|
1008
|
+
return itemTurnId && message ? [{ turnId: itemTurnId, message }] : [];
|
|
1009
|
+
})
|
|
1010
|
+
: [];
|
|
1011
|
+
if (!sessionId || !turnId) {
|
|
1012
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", "Cindy knowledge claim report input requires session_id and turn_id.");
|
|
1013
|
+
}
|
|
1014
|
+
return { sessionId, turnId, taskConclusions };
|
|
1015
|
+
}
|
|
980
1016
|
function runKnowledge(args) {
|
|
981
1017
|
const subcommand = args.shift();
|
|
982
1018
|
switch (subcommand) {
|
|
@@ -1039,9 +1075,68 @@ function runKnowledge(args) {
|
|
|
1039
1075
|
return;
|
|
1040
1076
|
}
|
|
1041
1077
|
case "claim": {
|
|
1042
|
-
const
|
|
1078
|
+
const explicitJobPath = readOptionalFlag(args, "--job");
|
|
1079
|
+
const projectRoot = readOptionalFlag(args, "--project-root");
|
|
1080
|
+
const finalizeId = readOptionalFlag(args, "--finalize-id");
|
|
1081
|
+
const captureCindyReport = readBooleanFlag(args, "--cindy-report-stdin");
|
|
1082
|
+
const cindyCapture = captureCindyReport ? readCindyKnowledgeClaimCaptureInput() : undefined;
|
|
1083
|
+
if (explicitJobPath && (projectRoot || finalizeId)) {
|
|
1084
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", "knowledge claim accepts either --job or --project-root with --finalize-id.");
|
|
1085
|
+
}
|
|
1086
|
+
if (!explicitJobPath && (!projectRoot || !finalizeId)) {
|
|
1087
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", "knowledge claim requires --job or both --project-root and --finalize-id.");
|
|
1088
|
+
}
|
|
1043
1089
|
assertNoRemainingArgs(args, "knowledge claim");
|
|
1044
|
-
const
|
|
1090
|
+
const jobPath = explicitJobPath ?? findKnowledgeFinalizationJobPath(resolveProjectContext(path.resolve(projectRoot)), finalizeId);
|
|
1091
|
+
if (!jobPath) {
|
|
1092
|
+
throw new Error(`Knowledge finalization ${finalizeId} is unavailable.`);
|
|
1093
|
+
}
|
|
1094
|
+
const job = claimKnowledgeFinalizationJob(jobPath, {
|
|
1095
|
+
prepare: (queued) => {
|
|
1096
|
+
if (queued.writer?.executionPolicy !== "subagent"
|
|
1097
|
+
|| queued.reportCapture?.mode !== "claim"
|
|
1098
|
+
|| queued.reportCapture.status === "captured") {
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
if (queued.host === "cindy") {
|
|
1102
|
+
if (!cindyCapture) {
|
|
1103
|
+
throw new Error(`Cindy report capture is unavailable for knowledge session ${queued.sessionId}.`);
|
|
1104
|
+
}
|
|
1105
|
+
if (cindyCapture.sessionId !== queued.sessionId) {
|
|
1106
|
+
throw new Error("Cindy report capture does not match the originating knowledge session.");
|
|
1107
|
+
}
|
|
1108
|
+
const capturedAt = new Date().toISOString();
|
|
1109
|
+
appendKnowledgeTaskConclusions(queued.reportPath, queued.sessionId, cindyCapture.taskConclusions, capturedAt);
|
|
1110
|
+
return {
|
|
1111
|
+
reportCapture: {
|
|
1112
|
+
...queued.reportCapture,
|
|
1113
|
+
status: "captured",
|
|
1114
|
+
capturedAt,
|
|
1115
|
+
messageCount: cindyCapture.taskConclusions.length,
|
|
1116
|
+
},
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
if (queued.host !== "codex") {
|
|
1120
|
+
throw new Error(`Claim-time report capture is unavailable for host ${queued.host ?? "unknown"}.`);
|
|
1121
|
+
}
|
|
1122
|
+
const transcriptPath = findCodexTranscriptPath(queued.sessionId);
|
|
1123
|
+
if (!transcriptPath) {
|
|
1124
|
+
throw new Error(`Codex transcript is unavailable for knowledge session ${queued.sessionId}.`);
|
|
1125
|
+
}
|
|
1126
|
+
const conclusions = extractTaskDoneConclusions(transcriptPath, undefined, queued.reportCapture.startedAt);
|
|
1127
|
+
const capturedAt = new Date().toISOString();
|
|
1128
|
+
appendKnowledgeTaskConclusions(queued.reportPath, queued.sessionId, conclusions, capturedAt);
|
|
1129
|
+
return {
|
|
1130
|
+
reportCapture: {
|
|
1131
|
+
...queued.reportCapture,
|
|
1132
|
+
status: "captured",
|
|
1133
|
+
capturedAt,
|
|
1134
|
+
transcriptPath,
|
|
1135
|
+
messageCount: conclusions.length,
|
|
1136
|
+
},
|
|
1137
|
+
};
|
|
1138
|
+
},
|
|
1139
|
+
});
|
|
1045
1140
|
const assignments = job ? buildKnowledgeWriterAssignments(job) : [];
|
|
1046
1141
|
const templatePath = job
|
|
1047
1142
|
? path.join(path.dirname(jobPath), `${job.finalizeId}.assignments.json`)
|
|
@@ -1059,6 +1154,7 @@ function runKnowledge(args) {
|
|
|
1059
1154
|
claimed: Boolean(job),
|
|
1060
1155
|
...(job ? {
|
|
1061
1156
|
finalizeId: job.finalizeId,
|
|
1157
|
+
jobPath,
|
|
1062
1158
|
claimToken: job.claimToken,
|
|
1063
1159
|
projectRoot: job.projectRoot,
|
|
1064
1160
|
writer: job.writer ?? null,
|
|
@@ -1139,14 +1235,15 @@ async function runPlan(args, effectiveHost) {
|
|
|
1139
1235
|
? showPlan({ cwd: process.cwd(), ...target, ownerSessionKey })
|
|
1140
1236
|
: undefined;
|
|
1141
1237
|
const project = entersEndTerminal ? tryResolveHookProject(process.cwd()) : null;
|
|
1142
|
-
const effectiveWriter = current && project
|
|
1238
|
+
const effectiveWriter = resolveKnowledgeWriterForHost(current && project
|
|
1143
1239
|
? resolvePlanEffectiveConfig(project.projectConfig, current.plan)?.knowledgeWriter
|
|
1144
|
-
: undefined;
|
|
1240
|
+
: undefined, effectiveHost);
|
|
1145
1241
|
if (current
|
|
1146
1242
|
&& !current.plan.parentPlan
|
|
1147
1243
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
1148
|
-
&& effectiveHost !== "codex"
|
|
1149
|
-
|
|
1244
|
+
&& effectiveHost !== "codex"
|
|
1245
|
+
&& effectiveHost !== "cindy") {
|
|
1246
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", 'knowledgeWriter.executionPolicy "subagent" is supported only by the Codex or Cindy host.', { host: effectiveHost ?? null });
|
|
1150
1247
|
}
|
|
1151
1248
|
const queuePlanEndFinalization = entersEndTerminal
|
|
1152
1249
|
? preparePlanEndFinalization(process.cwd(), ownerSessionKey)
|
|
@@ -1162,11 +1259,12 @@ async function runPlan(args, effectiveHost) {
|
|
|
1162
1259
|
const completionRefresh = queuePlanEndFinalization?.(result.taskName);
|
|
1163
1260
|
const knowledgeDispatch = (current
|
|
1164
1261
|
&& project
|
|
1165
|
-
&& effectiveHost === "codex"
|
|
1262
|
+
&& (effectiveHost === "codex" || effectiveHost === "cindy")
|
|
1166
1263
|
&& !current.plan.parentPlan
|
|
1167
1264
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
1168
1265
|
&& result.knowledgeFinalizeId)
|
|
1169
1266
|
? buildKnowledgeDispatch({
|
|
1267
|
+
host: effectiveHost,
|
|
1170
1268
|
finalizeId: result.knowledgeFinalizeId,
|
|
1171
1269
|
writer: effectiveWriter,
|
|
1172
1270
|
})
|
|
@@ -1245,13 +1343,14 @@ async function runPlan(args, effectiveHost) {
|
|
|
1245
1343
|
ownerSessionKey,
|
|
1246
1344
|
});
|
|
1247
1345
|
const project = tryResolveHookProject(process.cwd());
|
|
1248
|
-
const effectiveWriter = project
|
|
1346
|
+
const effectiveWriter = resolveKnowledgeWriterForHost(project
|
|
1249
1347
|
? resolvePlanEffectiveConfig(project.projectConfig, current.plan)?.knowledgeWriter
|
|
1250
|
-
: undefined;
|
|
1348
|
+
: undefined, effectiveHost);
|
|
1251
1349
|
if (!current.plan.parentPlan
|
|
1252
1350
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
1253
|
-
&& effectiveHost !== "codex"
|
|
1254
|
-
|
|
1351
|
+
&& effectiveHost !== "codex"
|
|
1352
|
+
&& effectiveHost !== "cindy") {
|
|
1353
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", 'knowledgeWriter.executionPolicy "subagent" is supported only by the Codex or Cindy host.', { host: effectiveHost ?? null });
|
|
1255
1354
|
}
|
|
1256
1355
|
const queuePlanEndFinalization = preparePlanEndFinalization(process.cwd(), ownerSessionKey);
|
|
1257
1356
|
const result = await editPlan({
|
|
@@ -1263,11 +1362,12 @@ async function runPlan(args, effectiveHost) {
|
|
|
1263
1362
|
ownerSessionKey,
|
|
1264
1363
|
});
|
|
1265
1364
|
const completionRefresh = queuePlanEndFinalization?.(result.taskName);
|
|
1266
|
-
const knowledgeDispatch = (effectiveHost === "codex"
|
|
1365
|
+
const knowledgeDispatch = ((effectiveHost === "codex" || effectiveHost === "cindy")
|
|
1267
1366
|
&& !current.plan.parentPlan
|
|
1268
1367
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
1269
1368
|
&& result.knowledgeFinalizeId)
|
|
1270
1369
|
? buildKnowledgeDispatch({
|
|
1370
|
+
host: effectiveHost,
|
|
1271
1371
|
finalizeId: result.knowledgeFinalizeId,
|
|
1272
1372
|
writer: effectiveWriter,
|
|
1273
1373
|
})
|
|
@@ -1394,7 +1494,7 @@ async function runTask(args, effectiveHost) {
|
|
|
1394
1494
|
cwd: process.cwd(),
|
|
1395
1495
|
...target,
|
|
1396
1496
|
operations,
|
|
1397
|
-
commandSource: "
|
|
1497
|
+
commandSource: "task.add",
|
|
1398
1498
|
host: effectiveHost,
|
|
1399
1499
|
ownerSessionKey: resolveOwnerSessionKey() ?? undefined,
|
|
1400
1500
|
});
|
|
@@ -1410,7 +1510,7 @@ async function runTask(args, effectiveHost) {
|
|
|
1410
1510
|
cwd: process.cwd(),
|
|
1411
1511
|
...target,
|
|
1412
1512
|
operations,
|
|
1413
|
-
commandSource: "
|
|
1513
|
+
commandSource: "task.edit",
|
|
1414
1514
|
host: effectiveHost,
|
|
1415
1515
|
ownerSessionKey: resolveOwnerSessionKey() ?? undefined,
|
|
1416
1516
|
});
|
|
@@ -1426,7 +1526,7 @@ async function runTask(args, effectiveHost) {
|
|
|
1426
1526
|
cwd: process.cwd(),
|
|
1427
1527
|
...target,
|
|
1428
1528
|
operations,
|
|
1429
|
-
commandSource: "
|
|
1529
|
+
commandSource: "task.remove",
|
|
1430
1530
|
host: effectiveHost,
|
|
1431
1531
|
ownerSessionKey: resolveOwnerSessionKey() ?? undefined,
|
|
1432
1532
|
});
|
|
@@ -1442,6 +1542,7 @@ async function runTask(args, effectiveHost) {
|
|
|
1442
1542
|
cwd: process.cwd(),
|
|
1443
1543
|
...target,
|
|
1444
1544
|
operations,
|
|
1545
|
+
commandSource: "task.done",
|
|
1445
1546
|
host: effectiveHost,
|
|
1446
1547
|
ownerSessionKey: resolveOwnerSessionKey() ?? undefined,
|
|
1447
1548
|
});
|
|
@@ -2805,9 +2906,13 @@ function stripBom(content) {
|
|
|
2805
2906
|
return content.charCodeAt(0) === 0xfeff ? content.slice(1) : content;
|
|
2806
2907
|
}
|
|
2807
2908
|
function buildKnowledgeDispatch(input) {
|
|
2909
|
+
if (input.host === "cindy") {
|
|
2910
|
+
return buildKnowledgeAtomicDispatch(input);
|
|
2911
|
+
}
|
|
2808
2912
|
return buildKnowledgeDelegateDispatch({
|
|
2809
2913
|
policy: "subagent",
|
|
2810
|
-
|
|
2914
|
+
finalizeId: input.finalizeId,
|
|
2915
|
+
writer: input.writer,
|
|
2811
2916
|
});
|
|
2812
2917
|
}
|
|
2813
2918
|
function compactPlanCommandResult(command, result, effectiveHost, completionRefresh, forceProjectionSync = false, knowledgeDispatch) {
|