ultimate-pi 0.19.1 → 0.22.0
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/.agents/skills/harness-decisions/SKILL.md +68 -2
- package/.agents/skills/harness-git-commit/SKILL.md +72 -0
- package/.agents/skills/harness-governor/SKILL.md +2 -2
- package/.agents/skills/harness-ls-lint-setup/SKILL.md +59 -0
- package/.agents/skills/harness-plan/SKILL.md +13 -11
- package/.agents/skills/harness-review/SKILL.md +1 -1
- package/.agents/skills/harness-sentrux-repair/SKILL.md +48 -0
- package/.agents/skills/sentrux/SKILL.md +4 -2
- package/.agents/skills/wiki-save/SKILL.md +1 -1
- package/.pi/PACKAGING.md +6 -0
- package/.pi/SYSTEM.md +21 -3
- package/.pi/agents/harness/ls-lint-steward.md +49 -0
- package/.pi/agents/harness/planning/decompose.md +4 -4
- package/.pi/agents/harness/reviewing/evaluator.md +1 -1
- package/.pi/agents/harness/running/executor.md +43 -2
- package/.pi/agents/harness/sentrux-repair-advisor.md +50 -0
- package/.pi/agents/pi-pi/prompt-expert.md +17 -2
- package/.pi/auto-commit.json +9 -2
- package/.pi/extensions/debate-orchestrator.ts +3 -0
- package/.pi/extensions/harness-anchored-edit.ts +139 -0
- package/.pi/extensions/harness-ask-user.ts +13 -34
- package/.pi/extensions/harness-debate-tools.ts +43 -4
- package/.pi/extensions/harness-live-widget.ts +28 -19
- package/.pi/extensions/harness-run-context.ts +278 -115
- package/.pi/extensions/harness-web-tools.ts +598 -471
- package/.pi/extensions/ls-lint-rules-sync.ts +103 -0
- package/.pi/extensions/observation-bus.ts +4 -0
- package/.pi/extensions/policy-gate.ts +270 -229
- package/.pi/extensions/sentrux-rules-sync.ts +2 -0
- package/.pi/extensions/soundboard.ts +48 -48
- package/.pi/harness/README.md +4 -0
- package/.pi/harness/agents.manifest.json +15 -7
- package/.pi/harness/agents.policy.yaml +47 -81
- package/.pi/harness/docs/adrs/0051-hash-anchored-executor-edits.md +41 -0
- package/.pi/harness/docs/adrs/0052-ls-lint-naming-lifecycle.md +45 -0
- package/.pi/harness/docs/adrs/0052-sentrux-structured-repair.md +38 -0
- package/.pi/harness/docs/adrs/0053-plan-task-clarification-gate.md +39 -0
- package/.pi/harness/docs/adrs/0054-harness-native-ask-user.md +40 -0
- package/.pi/harness/docs/adrs/0055-auto-commit-coauthor-lifecycle.md +40 -0
- package/.pi/harness/docs/adrs/README.md +7 -0
- package/.pi/harness/docs/practice-map.md +21 -5
- package/.pi/harness/evals/smoke/ls-lint-stub.json +10 -0
- package/.pi/harness/evolution/self-healing-rules.json +16 -0
- package/.pi/harness/ls-lint/naming.manifest.json +128 -0
- package/.pi/harness/sentrux/architecture.manifest.json +1 -1
- package/.pi/harness/specs/auto-commit.schema.json +63 -0
- package/.pi/harness/specs/ls-lint-manifest-proposal.schema.json +80 -0
- package/.pi/harness/specs/ls-lint-signal.schema.json +47 -0
- package/.pi/harness/specs/naming-manifest.schema.json +54 -0
- package/.pi/harness/specs/plan-task-clarification.schema.json +88 -0
- package/.pi/harness/specs/sentrux-diagnostics.schema.json +173 -0
- package/.pi/harness/specs/sentrux-repair-plan.schema.json +133 -0
- package/.pi/harness/specs/sentrux-report.schema.json +119 -0
- package/.pi/harness/specs/sentrux-signal.schema.json +34 -1
- package/.pi/lib/agents-policy.d.mts +26 -47
- package/.pi/lib/agents-policy.mjs +84 -29
- package/.pi/lib/agents-policy.ts +1 -0
- package/.pi/lib/agt/build-evaluation-context.ts +136 -64
- package/.pi/lib/ask-user/constants.mjs +3 -0
- package/.pi/lib/ask-user/constants.ts +4 -0
- package/.pi/lib/ask-user/contracts/glimpse-parse.ts +56 -0
- package/.pi/lib/ask-user/contracts/glimpse-payload-build.ts +58 -0
- package/.pi/lib/ask-user/contracts/glimpse-payload.ts +38 -0
- package/.pi/lib/ask-user/core/questionnaire.ts +74 -0
- package/.pi/lib/ask-user/dialog.ts +2 -314
- package/.pi/lib/ask-user/fallback.ts +2 -78
- package/.pi/lib/ask-user/format.ts +85 -0
- package/.pi/lib/ask-user/glimpseui.d.ts +10 -0
- package/.pi/lib/ask-user/index.ts +114 -0
- package/.pi/lib/ask-user/merge-task-clarification.ts +98 -0
- package/.pi/lib/ask-user/policy.mjs +43 -0
- package/.pi/lib/ask-user/policy.ts +104 -0
- package/.pi/lib/ask-user/presenters/glimpse.ts +130 -0
- package/.pi/lib/ask-user/presenters/headless.ts +131 -0
- package/.pi/lib/ask-user/presenters/select.ts +60 -0
- package/.pi/lib/ask-user/presenters/tui.ts +373 -0
- package/.pi/lib/ask-user/presenters/types.ts +13 -0
- package/.pi/lib/ask-user/render.ts +40 -9
- package/.pi/lib/ask-user/schema.ts +66 -13
- package/.pi/lib/ask-user/types.ts +60 -3
- package/.pi/lib/ask-user/validate-core.mjs +193 -7
- package/.pi/lib/ask-user/validate.ts +53 -34
- package/.pi/lib/harness-anchored-edit/.hash_anchors +1721 -0
- package/.pi/lib/harness-anchored-edit/anchor-state.ts +320 -0
- package/.pi/lib/harness-anchored-edit/apply-anchored-edits.ts +161 -0
- package/.pi/lib/harness-anchored-edit/edit-executor.ts +146 -0
- package/.pi/lib/harness-anchored-edit/index.ts +9 -0
- package/.pi/lib/harness-anchored-edit/line-protocol.ts +38 -0
- package/.pi/lib/harness-anchored-edit/package.json +3 -0
- package/.pi/lib/harness-anchored-edit/settings.ts +1 -0
- package/.pi/lib/harness-anchored-edit/task-id.ts +8 -0
- package/.pi/lib/harness-anchored-edit/types.ts +19 -0
- package/.pi/lib/harness-artifact-gate.ts +75 -21
- package/.pi/lib/harness-auto-commit-config.mjs +321 -0
- package/.pi/lib/harness-lens/clients/anchored-edit-autopatch.ts +158 -0
- package/.pi/lib/harness-lens/clients/lsp/client.ts +62 -39
- package/.pi/lib/harness-lens/clients/tool-policy.ts +73 -181
- package/.pi/lib/harness-lens/index.ts +246 -96
- package/.pi/lib/harness-lens/tools/lsp-navigation.ts +10 -8
- package/.pi/lib/harness-repair-brief.ts +84 -25
- package/.pi/lib/harness-run-context.ts +42 -52
- package/.pi/lib/harness-sentrux-parse.mjs +272 -0
- package/.pi/lib/harness-sentrux-root.mjs +78 -0
- package/.pi/lib/harness-slash-completions.ts +116 -0
- package/.pi/lib/harness-spawn-topology.ts +121 -87
- package/.pi/lib/harness-subagent-submit-registry.ts +10 -0
- package/.pi/lib/harness-subagents-bridge.ts +11 -6
- package/.pi/lib/harness-ui-state.ts +95 -48
- package/.pi/lib/plan-approval/dialog.ts +5 -0
- package/.pi/lib/plan-approval/validate.ts +1 -1
- package/.pi/lib/plan-approval-readiness.ts +32 -0
- package/.pi/lib/plan-debate-gate.ts +154 -114
- package/.pi/lib/plan-task-clarification.ts +158 -0
- package/.pi/prompts/harness-auto.md +2 -2
- package/.pi/prompts/harness-ls-lint-steward.md +43 -0
- package/.pi/prompts/harness-plan.md +58 -8
- package/.pi/prompts/harness-review.md +40 -6
- package/.pi/prompts/harness-run.md +33 -11
- package/.pi/prompts/harness-setup.md +72 -3
- package/.pi/prompts/harness-steer.md +3 -2
- package/.pi/prompts/wiki-save.md +5 -4
- package/.pi/scripts/README.md +8 -0
- package/.pi/scripts/generate-agents-policy-yaml.mjs +14 -2
- package/.pi/scripts/harness-anchored-edit-smoke.mjs +45 -0
- package/.pi/scripts/harness-auto-commit-bootstrap.mjs +96 -0
- package/.pi/scripts/harness-cli-verify.sh +47 -0
- package/.pi/scripts/harness-git-churn.mjs +77 -0
- package/.pi/scripts/harness-git-commit.mjs +173 -0
- package/.pi/scripts/harness-ls-lint-bootstrap.mjs +142 -0
- package/.pi/scripts/harness-ls-lint-cli.mjs +184 -0
- package/.pi/scripts/harness-seed-project-contracts.mjs +47 -0
- package/.pi/scripts/harness-sentrux-diagnostics.mjs +230 -0
- package/.pi/scripts/harness-sentrux-report.mjs +256 -0
- package/.pi/scripts/harness-verify.mjs +347 -117
- package/.pi/scripts/ls-lint-rules-sync.mjs +265 -0
- package/.pi/scripts/run-tests.mjs +65 -0
- package/.pi/settings.example.json +1 -0
- package/.sentrux/rules.toml +1 -1
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +31 -0
- package/README.md +13 -4
- package/THIRD_PARTY_NOTICES.md +7 -0
- package/package.json +8 -3
- package/vendor/pi-subagents/src/agents.ts +5 -0
- package/vendor/pi-subagents/src/subagents.ts +22 -3
- package/vendor/pi-vcc/src/hooks/before-compact.ts +86 -60
- package/.pi/scripts/release.sh +0 -338
|
@@ -80,8 +80,12 @@ import {
|
|
|
80
80
|
} from "../lib/harness-yaml.js";
|
|
81
81
|
import { isReviewRoundArtifactPath } from "../lib/plan-debate-gate.js";
|
|
82
82
|
import { isReviewRoundYamlWriteAllowed } from "../lib/plan-debate-write-guard.js";
|
|
83
|
+
import {
|
|
84
|
+
assertTaskClarificationReadyForPlanWrite,
|
|
85
|
+
readTaskClarificationDoc,
|
|
86
|
+
TASK_CLARIFICATION_ARTIFACT,
|
|
87
|
+
} from "../lib/plan-task-clarification.js";
|
|
83
88
|
|
|
84
|
-
// @ts-expect-error pi extensions run as ESM
|
|
85
89
|
const MODULE_URL = import.meta.url;
|
|
86
90
|
|
|
87
91
|
interface SessionEntryLike {
|
|
@@ -113,6 +117,7 @@ const PLAN_REVISION_ARTIFACT_FILES = new Set([
|
|
|
113
117
|
"plan-phase-status.yaml",
|
|
114
118
|
"plan-phase-waiver.yaml",
|
|
115
119
|
"sentrux-manifest-proposal.yaml",
|
|
120
|
+
"ls-lint-manifest-proposal.yaml",
|
|
116
121
|
]);
|
|
117
122
|
|
|
118
123
|
const PLAN_REVISION_ARTIFACT_PREFIXES = [
|
|
@@ -455,8 +460,14 @@ async function maybeHandleClarificationFollowUp(input: {
|
|
|
455
460
|
false,
|
|
456
461
|
);
|
|
457
462
|
persistContext(input.pi, input.activeCtx);
|
|
463
|
+
const amendHint = packet
|
|
464
|
+
? "Reply with clarification answers; the harness will treat this as plan amend."
|
|
465
|
+
: `Reply with clarification answers; the harness will merge them into ${TASK_CLARIFICATION_ARTIFACT} and continue Phase 0 (task contract), not full planning yet.`;
|
|
466
|
+
const planBlock = packet
|
|
467
|
+
? formatActivePlanBlock(input.activeCtx, "revise", summary)
|
|
468
|
+
: `[HarnessTaskClarification] status=needs_user — complete ${TASK_CLARIFICATION_ARTIFACT} before reconnaissance.`;
|
|
458
469
|
return {
|
|
459
|
-
systemPrompt: `${input.systemPrompt}\n\n${formatPlanContextBlock(input.activeCtx)}\n\n${
|
|
470
|
+
systemPrompt: `${input.systemPrompt}\n\n${formatPlanContextBlock(input.activeCtx)}\n\n${planBlock}\n\n${amendHint}`,
|
|
460
471
|
};
|
|
461
472
|
}
|
|
462
473
|
|
|
@@ -1212,6 +1223,115 @@ async function resolveCommandRunContext(input: {
|
|
|
1212
1223
|
return { activeCtx, resolved, response: null };
|
|
1213
1224
|
}
|
|
1214
1225
|
|
|
1226
|
+
async function handlePreResolvedHarnessCommand(args: {
|
|
1227
|
+
pi: ExtensionAPI;
|
|
1228
|
+
activeCtx: HarnessRunContext | null;
|
|
1229
|
+
command: string;
|
|
1230
|
+
parsedArgs: string;
|
|
1231
|
+
userPrompt: string;
|
|
1232
|
+
systemPrompt: string;
|
|
1233
|
+
sessionId: string;
|
|
1234
|
+
projectRoot: string;
|
|
1235
|
+
entries: unknown[];
|
|
1236
|
+
driftActive: boolean;
|
|
1237
|
+
}): Promise<{
|
|
1238
|
+
activeCtx: HarnessRunContext | null;
|
|
1239
|
+
response: any;
|
|
1240
|
+
handled: boolean;
|
|
1241
|
+
}> {
|
|
1242
|
+
const {
|
|
1243
|
+
pi,
|
|
1244
|
+
activeCtx,
|
|
1245
|
+
command,
|
|
1246
|
+
parsedArgs,
|
|
1247
|
+
userPrompt,
|
|
1248
|
+
systemPrompt,
|
|
1249
|
+
sessionId,
|
|
1250
|
+
projectRoot,
|
|
1251
|
+
entries,
|
|
1252
|
+
driftActive,
|
|
1253
|
+
} = args;
|
|
1254
|
+
if (
|
|
1255
|
+
!isHarnessBootstrapPrompt(userPrompt) &&
|
|
1256
|
+
!hasHarnessAbortSignal(userPrompt)
|
|
1257
|
+
) {
|
|
1258
|
+
const policyBlock = getPolicyTransitionBlock(userPrompt, entries);
|
|
1259
|
+
if (policyBlock.blocked) {
|
|
1260
|
+
return {
|
|
1261
|
+
activeCtx,
|
|
1262
|
+
response: blockRunContextMessage(
|
|
1263
|
+
policyBlock.message ?? "Harness command blocked by policy phase.",
|
|
1264
|
+
),
|
|
1265
|
+
handled: true,
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
if (command === "harness-new-run") {
|
|
1270
|
+
const next = createNewRunContextForCommand({
|
|
1271
|
+
pi,
|
|
1272
|
+
activeCtx,
|
|
1273
|
+
sessionId,
|
|
1274
|
+
projectRoot,
|
|
1275
|
+
args: parsedArgs,
|
|
1276
|
+
userPrompt,
|
|
1277
|
+
systemPrompt,
|
|
1278
|
+
});
|
|
1279
|
+
return {
|
|
1280
|
+
activeCtx: next.activeCtx,
|
|
1281
|
+
response: next.response,
|
|
1282
|
+
handled: true,
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
if (command === "harness-use-run") {
|
|
1286
|
+
const next = await bindExistingRunForCommand({
|
|
1287
|
+
pi,
|
|
1288
|
+
sessionId,
|
|
1289
|
+
projectRoot,
|
|
1290
|
+
entries,
|
|
1291
|
+
args: parsedArgs,
|
|
1292
|
+
systemPrompt,
|
|
1293
|
+
});
|
|
1294
|
+
return {
|
|
1295
|
+
activeCtx: next.activeCtx ?? activeCtx,
|
|
1296
|
+
response: next.response,
|
|
1297
|
+
handled: true,
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
if (command === "harness-run-status") {
|
|
1301
|
+
return { activeCtx, response: undefined, handled: true };
|
|
1302
|
+
}
|
|
1303
|
+
if (
|
|
1304
|
+
command === "harness-plan" &&
|
|
1305
|
+
activeCtx &&
|
|
1306
|
+
isNewTaskPlanBlocked(activeCtx, userPrompt) &&
|
|
1307
|
+
!isAmendPlanAllowed(activeCtx, userPrompt, driftActive)
|
|
1308
|
+
) {
|
|
1309
|
+
return {
|
|
1310
|
+
activeCtx,
|
|
1311
|
+
response: blockRunContextMessage(
|
|
1312
|
+
"Active harness run in progress. Use /harness-abort or /harness-new-run before starting a new task plan.",
|
|
1313
|
+
),
|
|
1314
|
+
handled: true,
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
return { activeCtx, response: null, handled: false };
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
function blockingRunCommandReason(
|
|
1321
|
+
command: string,
|
|
1322
|
+
activeCtx: HarnessRunContext,
|
|
1323
|
+
): string | null {
|
|
1324
|
+
if (command !== "harness-run") return null;
|
|
1325
|
+
if (!activeCtx.plan_ready) return "Plan not ready. Run /harness-plan first.";
|
|
1326
|
+
if (
|
|
1327
|
+
activeCtx.last_completed_step === "execute" &&
|
|
1328
|
+
activeCtx.last_outcome === "completed"
|
|
1329
|
+
) {
|
|
1330
|
+
return "Execute already completed for this run. Next: /harness-review (same session), or /harness-abort to replan.";
|
|
1331
|
+
}
|
|
1332
|
+
return null;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1215
1335
|
async function handleBeforeAgentStart(input: {
|
|
1216
1336
|
pi: ExtensionAPI;
|
|
1217
1337
|
event: any;
|
|
@@ -1260,52 +1380,22 @@ async function handleBeforeAgentStart(input: {
|
|
|
1260
1380
|
}
|
|
1261
1381
|
if (!parsed) return undefined;
|
|
1262
1382
|
const { command, args } = parsed;
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
projectRoot,
|
|
1280
|
-
args,
|
|
1281
|
-
userPrompt,
|
|
1282
|
-
systemPrompt: input.event.systemPrompt,
|
|
1283
|
-
});
|
|
1284
|
-
input.active.set(next.activeCtx);
|
|
1285
|
-
return next.response;
|
|
1286
|
-
}
|
|
1287
|
-
if (command === "harness-use-run") {
|
|
1288
|
-
const next = await bindExistingRunForCommand({
|
|
1289
|
-
pi: input.pi,
|
|
1290
|
-
sessionId,
|
|
1291
|
-
projectRoot,
|
|
1292
|
-
entries,
|
|
1293
|
-
args,
|
|
1294
|
-
systemPrompt: input.event.systemPrompt,
|
|
1295
|
-
});
|
|
1296
|
-
if (next.activeCtx) input.active.set(next.activeCtx);
|
|
1297
|
-
return next.response;
|
|
1298
|
-
}
|
|
1299
|
-
if (command === "harness-run-status") return undefined;
|
|
1300
|
-
if (
|
|
1301
|
-
command === "harness-plan" &&
|
|
1302
|
-
activeCtx &&
|
|
1303
|
-
isNewTaskPlanBlocked(activeCtx, userPrompt) &&
|
|
1304
|
-
!isAmendPlanAllowed(activeCtx, userPrompt, driftActive)
|
|
1305
|
-
) {
|
|
1306
|
-
return blockRunContextMessage(
|
|
1307
|
-
"Active harness run in progress. Use /harness-abort or /harness-new-run before starting a new task plan.",
|
|
1308
|
-
);
|
|
1383
|
+
const preResolved = await handlePreResolvedHarnessCommand({
|
|
1384
|
+
pi: input.pi,
|
|
1385
|
+
activeCtx,
|
|
1386
|
+
command,
|
|
1387
|
+
parsedArgs: args,
|
|
1388
|
+
userPrompt,
|
|
1389
|
+
systemPrompt: input.event.systemPrompt,
|
|
1390
|
+
sessionId,
|
|
1391
|
+
projectRoot,
|
|
1392
|
+
entries,
|
|
1393
|
+
driftActive,
|
|
1394
|
+
});
|
|
1395
|
+
activeCtx = preResolved.activeCtx;
|
|
1396
|
+
if (preResolved.handled) {
|
|
1397
|
+
input.active.set(activeCtx);
|
|
1398
|
+
return preResolved.response;
|
|
1309
1399
|
}
|
|
1310
1400
|
const prepared = await resolveCommandRunContext({
|
|
1311
1401
|
pi: input.pi,
|
|
@@ -1343,18 +1433,8 @@ async function handleBeforeAgentStart(input: {
|
|
|
1343
1433
|
return blockRunContextMessage(check.reason ?? "Invalid --plan override");
|
|
1344
1434
|
activeCtx.plan_packet_path = resolved.planPath;
|
|
1345
1435
|
}
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
if (
|
|
1349
|
-
command === "harness-run" &&
|
|
1350
|
-
activeCtx.plan_ready &&
|
|
1351
|
-
activeCtx.last_completed_step === "execute" &&
|
|
1352
|
-
activeCtx.last_outcome === "completed"
|
|
1353
|
-
) {
|
|
1354
|
-
return blockRunContextMessage(
|
|
1355
|
-
"Execute already completed for this run. Next: /harness-review (same session), or /harness-abort to replan.",
|
|
1356
|
-
);
|
|
1357
|
-
}
|
|
1436
|
+
const runBlockReason = blockingRunCommandReason(command, activeCtx);
|
|
1437
|
+
if (runBlockReason) return blockRunContextMessage(runBlockReason);
|
|
1358
1438
|
const { planSummary, planPacketForSpawn } =
|
|
1359
1439
|
await readPlanSpawnState(activeCtx);
|
|
1360
1440
|
const { activePlanBlock, planMode, contextSpawnOpts } =
|
|
@@ -1490,57 +1570,10 @@ async function handleAgentEnd(input: {
|
|
|
1490
1570
|
}
|
|
1491
1571
|
}
|
|
1492
1572
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
get: () => activeCtx,
|
|
1498
|
-
set: (ctx) => {
|
|
1499
|
-
activeCtx = ctx;
|
|
1500
|
-
},
|
|
1501
|
-
};
|
|
1502
|
-
|
|
1503
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
1504
|
-
const entries = getEntries(ctx);
|
|
1505
|
-
activeCtx = hydrateFromSession(entries);
|
|
1506
|
-
const booted = await bootstrapHarnessSubprocessFromEnv(pi, ctx);
|
|
1507
|
-
if (booted) activeCtx = booted;
|
|
1508
|
-
if (!booted) await offerCrossSessionResume(pi, ctx);
|
|
1509
|
-
});
|
|
1510
|
-
|
|
1511
|
-
pi.on("input", async (event) => {
|
|
1512
|
-
if (event.source === "extension") {
|
|
1513
|
-
return { action: "continue" as const };
|
|
1514
|
-
}
|
|
1515
|
-
const parsed = parseHarnessSlashInput(event.text);
|
|
1516
|
-
if (!parsed) {
|
|
1517
|
-
return { action: "continue" as const };
|
|
1518
|
-
}
|
|
1519
|
-
appendHarnessTurn(pi, {
|
|
1520
|
-
schema_version: "1.0.0",
|
|
1521
|
-
command: parsed.command,
|
|
1522
|
-
args: parsed.args,
|
|
1523
|
-
source: "slash",
|
|
1524
|
-
invoked_at: nowIso(),
|
|
1525
|
-
});
|
|
1526
|
-
return { action: "continue" as const };
|
|
1527
|
-
});
|
|
1528
|
-
|
|
1529
|
-
pi.on("before_agent_start", async (event, ctx) =>
|
|
1530
|
-
handleBeforeAgentStart({ pi, event, ctx, active: activeAccess }),
|
|
1531
|
-
);
|
|
1532
|
-
|
|
1533
|
-
pi.on("agent_end", async (_event, ctx) => {
|
|
1534
|
-
await handleAgentEnd({ pi, ctx, active: activeAccess });
|
|
1535
|
-
});
|
|
1536
|
-
|
|
1537
|
-
registerPlanApprovalCapture(pi, activeAccess);
|
|
1538
|
-
registerHarnessToolCallGuards(pi, activeAccess);
|
|
1539
|
-
registerHarnessRunStatusCommand(pi, activeAccess);
|
|
1540
|
-
registerHarnessNewRunCommand(pi, activeAccess);
|
|
1541
|
-
|
|
1542
|
-
registerHarnessPlanCommitCommand(pi, activeAccess);
|
|
1543
|
-
|
|
1573
|
+
function registerHarnessRunContextTool1(
|
|
1574
|
+
pi: ExtensionAPI,
|
|
1575
|
+
active: ActiveContextAccess,
|
|
1576
|
+
) {
|
|
1544
1577
|
pi.registerTool({
|
|
1545
1578
|
name: "write_harness_yaml",
|
|
1546
1579
|
label: "Write Harness YAML",
|
|
@@ -1566,7 +1599,7 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1566
1599
|
}),
|
|
1567
1600
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1568
1601
|
const entries = getEntries(ctx);
|
|
1569
|
-
const runCtx = getLatestRunContext(entries) ??
|
|
1602
|
+
const runCtx = getLatestRunContext(entries) ?? active.get();
|
|
1570
1603
|
if (!runCtx?.run_id) {
|
|
1571
1604
|
return {
|
|
1572
1605
|
content: [
|
|
@@ -1665,6 +1698,24 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1665
1698
|
isError: true,
|
|
1666
1699
|
};
|
|
1667
1700
|
}
|
|
1701
|
+
const runRootWrite = join(
|
|
1702
|
+
projectRoot,
|
|
1703
|
+
".pi",
|
|
1704
|
+
"harness",
|
|
1705
|
+
"runs",
|
|
1706
|
+
runCtx.run_id,
|
|
1707
|
+
);
|
|
1708
|
+
const clarWrite = await assertTaskClarificationReadyForPlanWrite(
|
|
1709
|
+
runRootWrite,
|
|
1710
|
+
relForGate,
|
|
1711
|
+
);
|
|
1712
|
+
if (!clarWrite.ok) {
|
|
1713
|
+
return {
|
|
1714
|
+
content: [{ type: "text", text: clarWrite.message ?? "Blocked." }],
|
|
1715
|
+
details: { path: pathArg },
|
|
1716
|
+
isError: true,
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1668
1719
|
let doc: unknown;
|
|
1669
1720
|
try {
|
|
1670
1721
|
doc = parseStructuredDocument(content, pathArg);
|
|
@@ -1678,6 +1729,16 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1678
1729
|
}
|
|
1679
1730
|
await mkdir(dirname(absPath), { recursive: true });
|
|
1680
1731
|
await writeYamlFile(absPath, doc);
|
|
1732
|
+
if (relForGate === TASK_CLARIFICATION_ARTIFACT) {
|
|
1733
|
+
const clarDoc = doc as Record<string, unknown>;
|
|
1734
|
+
if (String(clarDoc.status ?? "").toLowerCase() === "ready") {
|
|
1735
|
+
const clarified = String(clarDoc.clarified_task ?? "").trim();
|
|
1736
|
+
if (clarified) {
|
|
1737
|
+
runCtx.task_summary = clarified;
|
|
1738
|
+
persistContext(pi, runCtx);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1681
1742
|
return {
|
|
1682
1743
|
content: [
|
|
1683
1744
|
{
|
|
@@ -1689,7 +1750,12 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1689
1750
|
};
|
|
1690
1751
|
},
|
|
1691
1752
|
});
|
|
1753
|
+
}
|
|
1692
1754
|
|
|
1755
|
+
function registerHarnessRunContextTool2(
|
|
1756
|
+
pi: ExtensionAPI,
|
|
1757
|
+
active: ActiveContextAccess,
|
|
1758
|
+
) {
|
|
1693
1759
|
pi.registerTool({
|
|
1694
1760
|
name: "merge_harness_yaml",
|
|
1695
1761
|
label: "Merge Harness YAML",
|
|
@@ -1720,7 +1786,7 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1720
1786
|
}),
|
|
1721
1787
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1722
1788
|
const entries = getEntries(ctx);
|
|
1723
|
-
const runCtx = getLatestRunContext(entries) ??
|
|
1789
|
+
const runCtx = getLatestRunContext(entries) ?? active.get();
|
|
1724
1790
|
if (!runCtx?.run_id) {
|
|
1725
1791
|
return {
|
|
1726
1792
|
content: [{ type: "text", text: "No active harness run." }],
|
|
@@ -1767,6 +1833,18 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1767
1833
|
"runs",
|
|
1768
1834
|
runCtx.run_id,
|
|
1769
1835
|
);
|
|
1836
|
+
const relMerge = pathArg.replace(/\\/g, "/");
|
|
1837
|
+
const clarMerge = await assertTaskClarificationReadyForPlanWrite(
|
|
1838
|
+
runRoot,
|
|
1839
|
+
relMerge,
|
|
1840
|
+
);
|
|
1841
|
+
if (!clarMerge.ok) {
|
|
1842
|
+
return {
|
|
1843
|
+
content: [{ type: "text", text: clarMerge.message ?? "Blocked." }],
|
|
1844
|
+
details: { path: pathArg },
|
|
1845
|
+
isError: true,
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1770
1848
|
let existing: Record<string, unknown> = {};
|
|
1771
1849
|
try {
|
|
1772
1850
|
const { readYamlFile } = await import("../lib/harness-yaml.js");
|
|
@@ -1825,7 +1903,12 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1825
1903
|
};
|
|
1826
1904
|
},
|
|
1827
1905
|
});
|
|
1906
|
+
}
|
|
1828
1907
|
|
|
1908
|
+
function registerHarnessRunContextTool3(
|
|
1909
|
+
pi: ExtensionAPI,
|
|
1910
|
+
active: ActiveContextAccess,
|
|
1911
|
+
) {
|
|
1829
1912
|
pi.registerTool({
|
|
1830
1913
|
name: "harness_synthesize_repair_brief",
|
|
1831
1914
|
label: "Synthesize Repair Brief",
|
|
@@ -1850,7 +1933,7 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1850
1933
|
}),
|
|
1851
1934
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1852
1935
|
const entries = getEntries(ctx);
|
|
1853
|
-
const runCtx = getLatestRunContext(entries) ??
|
|
1936
|
+
const runCtx = getLatestRunContext(entries) ?? active.get();
|
|
1854
1937
|
if (!runCtx?.run_id) {
|
|
1855
1938
|
return {
|
|
1856
1939
|
content: [{ type: "text", text: "No active harness run." }],
|
|
@@ -1920,7 +2003,12 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1920
2003
|
};
|
|
1921
2004
|
},
|
|
1922
2005
|
});
|
|
2006
|
+
}
|
|
1923
2007
|
|
|
2008
|
+
function registerHarnessRunContextTool4(
|
|
2009
|
+
pi: ExtensionAPI,
|
|
2010
|
+
active: ActiveContextAccess,
|
|
2011
|
+
) {
|
|
1924
2012
|
pi.registerTool({
|
|
1925
2013
|
name: "harness_artifact_ready",
|
|
1926
2014
|
label: "Harness Artifact Ready",
|
|
@@ -1935,7 +2023,7 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1935
2023
|
}),
|
|
1936
2024
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
1937
2025
|
const entries = getEntries(ctx);
|
|
1938
|
-
const runCtx = getLatestRunContext(entries) ??
|
|
2026
|
+
const runCtx = getLatestRunContext(entries) ?? active.get();
|
|
1939
2027
|
if (!runCtx?.run_id) {
|
|
1940
2028
|
return {
|
|
1941
2029
|
content: [{ type: "text", text: "No active harness run." }],
|
|
@@ -1957,6 +2045,17 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1957
2045
|
"../lib/harness-artifact-gate.js"
|
|
1958
2046
|
);
|
|
1959
2047
|
const gate = await validateHarnessArtifactPaths(runRoot, paths, specsDir);
|
|
2048
|
+
if (
|
|
2049
|
+
gate.ok &&
|
|
2050
|
+
paths.some((p) => p.replace(/\\/g, "/") === TASK_CLARIFICATION_ARTIFACT)
|
|
2051
|
+
) {
|
|
2052
|
+
const clarDoc = await readTaskClarificationDoc(runRoot);
|
|
2053
|
+
const clarified = String(clarDoc?.clarified_task ?? "").trim();
|
|
2054
|
+
if (clarified && runCtx.task_summary !== clarified) {
|
|
2055
|
+
runCtx.task_summary = clarified;
|
|
2056
|
+
persistContext(pi, runCtx);
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
1960
2059
|
const text = gate.ok
|
|
1961
2060
|
? `All ${gate.present.length} artifact(s) present and valid.`
|
|
1962
2061
|
: [
|
|
@@ -1980,6 +2079,70 @@ export default function harnessRunContext(pi: ExtensionAPI) {
|
|
|
1980
2079
|
};
|
|
1981
2080
|
},
|
|
1982
2081
|
});
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
function registerHarnessRunContextTools(
|
|
2085
|
+
pi: ExtensionAPI,
|
|
2086
|
+
active: ActiveContextAccess,
|
|
2087
|
+
) {
|
|
2088
|
+
registerHarnessRunContextTool1(pi, active);
|
|
2089
|
+
registerHarnessRunContextTool2(pi, active);
|
|
2090
|
+
registerHarnessRunContextTool3(pi, active);
|
|
2091
|
+
registerHarnessRunContextTool4(pi, active);
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
export default function harnessRunContext(pi: ExtensionAPI) {
|
|
2095
|
+
if (!claimHarnessGovernanceLoad("harness-run-context", MODULE_URL)) return;
|
|
2096
|
+
let activeCtx: HarnessRunContext | null = null;
|
|
2097
|
+
const activeAccess: ActiveContextAccess = {
|
|
2098
|
+
get: () => activeCtx,
|
|
2099
|
+
set: (ctx) => {
|
|
2100
|
+
activeCtx = ctx;
|
|
2101
|
+
},
|
|
2102
|
+
};
|
|
2103
|
+
|
|
2104
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
2105
|
+
const entries = getEntries(ctx);
|
|
2106
|
+
activeCtx = hydrateFromSession(entries);
|
|
2107
|
+
const booted = await bootstrapHarnessSubprocessFromEnv(pi, ctx);
|
|
2108
|
+
if (booted) activeCtx = booted;
|
|
2109
|
+
if (!booted) await offerCrossSessionResume(pi, ctx);
|
|
2110
|
+
});
|
|
2111
|
+
|
|
2112
|
+
pi.on("input", async (event) => {
|
|
2113
|
+
if (event.source === "extension") {
|
|
2114
|
+
return { action: "continue" as const };
|
|
2115
|
+
}
|
|
2116
|
+
const parsed = parseHarnessSlashInput(event.text);
|
|
2117
|
+
if (!parsed) {
|
|
2118
|
+
return { action: "continue" as const };
|
|
2119
|
+
}
|
|
2120
|
+
appendHarnessTurn(pi, {
|
|
2121
|
+
schema_version: "1.0.0",
|
|
2122
|
+
command: parsed.command,
|
|
2123
|
+
args: parsed.args,
|
|
2124
|
+
source: "slash",
|
|
2125
|
+
invoked_at: nowIso(),
|
|
2126
|
+
});
|
|
2127
|
+
return { action: "continue" as const };
|
|
2128
|
+
});
|
|
2129
|
+
|
|
2130
|
+
pi.on("before_agent_start", async (event, ctx) =>
|
|
2131
|
+
handleBeforeAgentStart({ pi, event, ctx, active: activeAccess }),
|
|
2132
|
+
);
|
|
2133
|
+
|
|
2134
|
+
pi.on("agent_end", async (_event, ctx) => {
|
|
2135
|
+
await handleAgentEnd({ pi, ctx, active: activeAccess });
|
|
2136
|
+
});
|
|
2137
|
+
|
|
2138
|
+
registerPlanApprovalCapture(pi, activeAccess);
|
|
2139
|
+
registerHarnessToolCallGuards(pi, activeAccess);
|
|
2140
|
+
registerHarnessRunStatusCommand(pi, activeAccess);
|
|
2141
|
+
registerHarnessNewRunCommand(pi, activeAccess);
|
|
2142
|
+
|
|
2143
|
+
registerHarnessPlanCommitCommand(pi, activeAccess);
|
|
2144
|
+
|
|
2145
|
+
registerHarnessRunContextTools(pi, activeAccess);
|
|
1983
2146
|
|
|
1984
2147
|
registerHarnessUseRunCommand(pi, activeAccess);
|
|
1985
2148
|
}
|