@veewo/claw 0.2.4 → 0.2.6
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 +131 -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,38 @@ 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
|
+
if (taskConclusions.length === 0) {
|
|
1015
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", "Cindy knowledge claim report input requires at least one task conclusion.");
|
|
1016
|
+
}
|
|
1017
|
+
return { sessionId, turnId, taskConclusions };
|
|
1018
|
+
}
|
|
980
1019
|
function runKnowledge(args) {
|
|
981
1020
|
const subcommand = args.shift();
|
|
982
1021
|
switch (subcommand) {
|
|
@@ -1039,9 +1078,68 @@ function runKnowledge(args) {
|
|
|
1039
1078
|
return;
|
|
1040
1079
|
}
|
|
1041
1080
|
case "claim": {
|
|
1042
|
-
const
|
|
1081
|
+
const explicitJobPath = readOptionalFlag(args, "--job");
|
|
1082
|
+
const projectRoot = readOptionalFlag(args, "--project-root");
|
|
1083
|
+
const finalizeId = readOptionalFlag(args, "--finalize-id");
|
|
1084
|
+
const captureCindyReport = readBooleanFlag(args, "--cindy-report-stdin");
|
|
1085
|
+
const cindyCapture = captureCindyReport ? readCindyKnowledgeClaimCaptureInput() : undefined;
|
|
1086
|
+
if (explicitJobPath && (projectRoot || finalizeId)) {
|
|
1087
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", "knowledge claim accepts either --job or --project-root with --finalize-id.");
|
|
1088
|
+
}
|
|
1089
|
+
if (!explicitJobPath && (!projectRoot || !finalizeId)) {
|
|
1090
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", "knowledge claim requires --job or both --project-root and --finalize-id.");
|
|
1091
|
+
}
|
|
1043
1092
|
assertNoRemainingArgs(args, "knowledge claim");
|
|
1044
|
-
const
|
|
1093
|
+
const jobPath = explicitJobPath ?? findKnowledgeFinalizationJobPath(resolveProjectContext(path.resolve(projectRoot)), finalizeId);
|
|
1094
|
+
if (!jobPath) {
|
|
1095
|
+
throw new Error(`Knowledge finalization ${finalizeId} is unavailable.`);
|
|
1096
|
+
}
|
|
1097
|
+
const job = claimKnowledgeFinalizationJob(jobPath, {
|
|
1098
|
+
prepare: (queued) => {
|
|
1099
|
+
if (queued.writer?.executionPolicy !== "subagent"
|
|
1100
|
+
|| queued.reportCapture?.mode !== "claim"
|
|
1101
|
+
|| queued.reportCapture.status === "captured") {
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
if (queued.host === "cindy") {
|
|
1105
|
+
if (!cindyCapture) {
|
|
1106
|
+
throw new Error(`Cindy report capture is unavailable for knowledge session ${queued.sessionId}.`);
|
|
1107
|
+
}
|
|
1108
|
+
if (cindyCapture.sessionId !== queued.sessionId) {
|
|
1109
|
+
throw new Error("Cindy report capture does not match the originating knowledge session.");
|
|
1110
|
+
}
|
|
1111
|
+
const capturedAt = new Date().toISOString();
|
|
1112
|
+
appendKnowledgeTaskConclusions(queued.reportPath, queued.sessionId, cindyCapture.taskConclusions, capturedAt);
|
|
1113
|
+
return {
|
|
1114
|
+
reportCapture: {
|
|
1115
|
+
...queued.reportCapture,
|
|
1116
|
+
status: "captured",
|
|
1117
|
+
capturedAt,
|
|
1118
|
+
messageCount: cindyCapture.taskConclusions.length,
|
|
1119
|
+
},
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
if (queued.host !== "codex") {
|
|
1123
|
+
throw new Error(`Claim-time report capture is unavailable for host ${queued.host ?? "unknown"}.`);
|
|
1124
|
+
}
|
|
1125
|
+
const transcriptPath = findCodexTranscriptPath(queued.sessionId);
|
|
1126
|
+
if (!transcriptPath) {
|
|
1127
|
+
throw new Error(`Codex transcript is unavailable for knowledge session ${queued.sessionId}.`);
|
|
1128
|
+
}
|
|
1129
|
+
const conclusions = extractTaskDoneConclusions(transcriptPath, undefined, queued.reportCapture.startedAt);
|
|
1130
|
+
const capturedAt = new Date().toISOString();
|
|
1131
|
+
appendKnowledgeTaskConclusions(queued.reportPath, queued.sessionId, conclusions, capturedAt);
|
|
1132
|
+
return {
|
|
1133
|
+
reportCapture: {
|
|
1134
|
+
...queued.reportCapture,
|
|
1135
|
+
status: "captured",
|
|
1136
|
+
capturedAt,
|
|
1137
|
+
transcriptPath,
|
|
1138
|
+
messageCount: conclusions.length,
|
|
1139
|
+
},
|
|
1140
|
+
};
|
|
1141
|
+
},
|
|
1142
|
+
});
|
|
1045
1143
|
const assignments = job ? buildKnowledgeWriterAssignments(job) : [];
|
|
1046
1144
|
const templatePath = job
|
|
1047
1145
|
? path.join(path.dirname(jobPath), `${job.finalizeId}.assignments.json`)
|
|
@@ -1059,6 +1157,7 @@ function runKnowledge(args) {
|
|
|
1059
1157
|
claimed: Boolean(job),
|
|
1060
1158
|
...(job ? {
|
|
1061
1159
|
finalizeId: job.finalizeId,
|
|
1160
|
+
jobPath,
|
|
1062
1161
|
claimToken: job.claimToken,
|
|
1063
1162
|
projectRoot: job.projectRoot,
|
|
1064
1163
|
writer: job.writer ?? null,
|
|
@@ -1139,14 +1238,15 @@ async function runPlan(args, effectiveHost) {
|
|
|
1139
1238
|
? showPlan({ cwd: process.cwd(), ...target, ownerSessionKey })
|
|
1140
1239
|
: undefined;
|
|
1141
1240
|
const project = entersEndTerminal ? tryResolveHookProject(process.cwd()) : null;
|
|
1142
|
-
const effectiveWriter = current && project
|
|
1241
|
+
const effectiveWriter = resolveKnowledgeWriterForHost(current && project
|
|
1143
1242
|
? resolvePlanEffectiveConfig(project.projectConfig, current.plan)?.knowledgeWriter
|
|
1144
|
-
: undefined;
|
|
1243
|
+
: undefined, effectiveHost);
|
|
1145
1244
|
if (current
|
|
1146
1245
|
&& !current.plan.parentPlan
|
|
1147
1246
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
1148
|
-
&& effectiveHost !== "codex"
|
|
1149
|
-
|
|
1247
|
+
&& effectiveHost !== "codex"
|
|
1248
|
+
&& effectiveHost !== "cindy") {
|
|
1249
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", 'knowledgeWriter.executionPolicy "subagent" is supported only by the Codex or Cindy host.', { host: effectiveHost ?? null });
|
|
1150
1250
|
}
|
|
1151
1251
|
const queuePlanEndFinalization = entersEndTerminal
|
|
1152
1252
|
? preparePlanEndFinalization(process.cwd(), ownerSessionKey)
|
|
@@ -1162,11 +1262,12 @@ async function runPlan(args, effectiveHost) {
|
|
|
1162
1262
|
const completionRefresh = queuePlanEndFinalization?.(result.taskName);
|
|
1163
1263
|
const knowledgeDispatch = (current
|
|
1164
1264
|
&& project
|
|
1165
|
-
&& effectiveHost === "codex"
|
|
1265
|
+
&& (effectiveHost === "codex" || effectiveHost === "cindy")
|
|
1166
1266
|
&& !current.plan.parentPlan
|
|
1167
1267
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
1168
1268
|
&& result.knowledgeFinalizeId)
|
|
1169
1269
|
? buildKnowledgeDispatch({
|
|
1270
|
+
host: effectiveHost,
|
|
1170
1271
|
finalizeId: result.knowledgeFinalizeId,
|
|
1171
1272
|
writer: effectiveWriter,
|
|
1172
1273
|
})
|
|
@@ -1245,13 +1346,14 @@ async function runPlan(args, effectiveHost) {
|
|
|
1245
1346
|
ownerSessionKey,
|
|
1246
1347
|
});
|
|
1247
1348
|
const project = tryResolveHookProject(process.cwd());
|
|
1248
|
-
const effectiveWriter = project
|
|
1349
|
+
const effectiveWriter = resolveKnowledgeWriterForHost(project
|
|
1249
1350
|
? resolvePlanEffectiveConfig(project.projectConfig, current.plan)?.knowledgeWriter
|
|
1250
|
-
: undefined;
|
|
1351
|
+
: undefined, effectiveHost);
|
|
1251
1352
|
if (!current.plan.parentPlan
|
|
1252
1353
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
1253
|
-
&& effectiveHost !== "codex"
|
|
1254
|
-
|
|
1354
|
+
&& effectiveHost !== "codex"
|
|
1355
|
+
&& effectiveHost !== "cindy") {
|
|
1356
|
+
throw new ClawError("PROJECT_CONFIG_INVALID", 'knowledgeWriter.executionPolicy "subagent" is supported only by the Codex or Cindy host.', { host: effectiveHost ?? null });
|
|
1255
1357
|
}
|
|
1256
1358
|
const queuePlanEndFinalization = preparePlanEndFinalization(process.cwd(), ownerSessionKey);
|
|
1257
1359
|
const result = await editPlan({
|
|
@@ -1263,11 +1365,12 @@ async function runPlan(args, effectiveHost) {
|
|
|
1263
1365
|
ownerSessionKey,
|
|
1264
1366
|
});
|
|
1265
1367
|
const completionRefresh = queuePlanEndFinalization?.(result.taskName);
|
|
1266
|
-
const knowledgeDispatch = (effectiveHost === "codex"
|
|
1368
|
+
const knowledgeDispatch = ((effectiveHost === "codex" || effectiveHost === "cindy")
|
|
1267
1369
|
&& !current.plan.parentPlan
|
|
1268
1370
|
&& effectiveWriter?.executionPolicy === "subagent"
|
|
1269
1371
|
&& result.knowledgeFinalizeId)
|
|
1270
1372
|
? buildKnowledgeDispatch({
|
|
1373
|
+
host: effectiveHost,
|
|
1271
1374
|
finalizeId: result.knowledgeFinalizeId,
|
|
1272
1375
|
writer: effectiveWriter,
|
|
1273
1376
|
})
|
|
@@ -1394,7 +1497,7 @@ async function runTask(args, effectiveHost) {
|
|
|
1394
1497
|
cwd: process.cwd(),
|
|
1395
1498
|
...target,
|
|
1396
1499
|
operations,
|
|
1397
|
-
commandSource: "
|
|
1500
|
+
commandSource: "task.add",
|
|
1398
1501
|
host: effectiveHost,
|
|
1399
1502
|
ownerSessionKey: resolveOwnerSessionKey() ?? undefined,
|
|
1400
1503
|
});
|
|
@@ -1410,7 +1513,7 @@ async function runTask(args, effectiveHost) {
|
|
|
1410
1513
|
cwd: process.cwd(),
|
|
1411
1514
|
...target,
|
|
1412
1515
|
operations,
|
|
1413
|
-
commandSource: "
|
|
1516
|
+
commandSource: "task.edit",
|
|
1414
1517
|
host: effectiveHost,
|
|
1415
1518
|
ownerSessionKey: resolveOwnerSessionKey() ?? undefined,
|
|
1416
1519
|
});
|
|
@@ -1426,7 +1529,7 @@ async function runTask(args, effectiveHost) {
|
|
|
1426
1529
|
cwd: process.cwd(),
|
|
1427
1530
|
...target,
|
|
1428
1531
|
operations,
|
|
1429
|
-
commandSource: "
|
|
1532
|
+
commandSource: "task.remove",
|
|
1430
1533
|
host: effectiveHost,
|
|
1431
1534
|
ownerSessionKey: resolveOwnerSessionKey() ?? undefined,
|
|
1432
1535
|
});
|
|
@@ -1442,6 +1545,7 @@ async function runTask(args, effectiveHost) {
|
|
|
1442
1545
|
cwd: process.cwd(),
|
|
1443
1546
|
...target,
|
|
1444
1547
|
operations,
|
|
1548
|
+
commandSource: "task.done",
|
|
1445
1549
|
host: effectiveHost,
|
|
1446
1550
|
ownerSessionKey: resolveOwnerSessionKey() ?? undefined,
|
|
1447
1551
|
});
|
|
@@ -2805,9 +2909,13 @@ function stripBom(content) {
|
|
|
2805
2909
|
return content.charCodeAt(0) === 0xfeff ? content.slice(1) : content;
|
|
2806
2910
|
}
|
|
2807
2911
|
function buildKnowledgeDispatch(input) {
|
|
2912
|
+
if (input.host === "cindy") {
|
|
2913
|
+
return buildKnowledgeAtomicDispatch(input);
|
|
2914
|
+
}
|
|
2808
2915
|
return buildKnowledgeDelegateDispatch({
|
|
2809
2916
|
policy: "subagent",
|
|
2810
|
-
|
|
2917
|
+
finalizeId: input.finalizeId,
|
|
2918
|
+
writer: input.writer,
|
|
2811
2919
|
});
|
|
2812
2920
|
}
|
|
2813
2921
|
function compactPlanCommandResult(command, result, effectiveHost, completionRefresh, forceProjectionSync = false, knowledgeDispatch) {
|