@tea-agent/loop-agent 0.35.1-beta.0 → 0.35.1-beta.2
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.md +110 -108
- package/CHANGELOG.md +24 -26
- package/README.md +165 -165
- package/bin/agent-worker.js +0 -0
- package/bin/loop-agent.js +57 -21
- package/dist/application/task-lifecycle/advance.js +0 -1
- package/dist/build-stamp.json +6 -0
- package/dist/cli/program.js +2 -2
- package/dist/commands/cursor-prompt.js +6 -6
- package/dist/commands/init-upgrade.js +19 -351
- package/dist/commands/init.js +67 -14
- package/dist/commands/loop-benchmark.js +11 -11
- package/dist/commands/pi-reuse-benchmark.js +16 -16
- package/dist/commands/run-dag-progress.js +0 -14
- package/dist/commands/task-advance.js +3 -33
- package/dist/executors/dag-pi-executor.js +44 -0
- package/dist/shared/operator/capabilities.js +1 -38
- package/dist/shared/package-metadata.js +42 -0
- package/dist/sidecars/cursor-prompt/executor.js +1 -1
- package/dist/worker/console/chat/pi-runtime.js +25 -41
- package/dist/worker/console/chat/routes.js +4 -27
- package/dist/worker/console/operation-runner.js +0 -24
- package/dist/worker/console/operator-actions.js +0 -58
- package/dist/worker/console/static/assets/index-CvsQgALl.js +56 -0
- package/dist/worker/console/static/assets/{index-Dups4sSM.css → index-hJqCPs_g.css} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +5 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -13
- package/dist/worker/console/static-src/operator-chat/useComposer.js +7 -30
- package/dist/worker/loop-agent/loop-agent-client.js +17 -3
- package/dist/worker/observability/read-model.js +20 -0
- package/dist/worker/observe/static/copy.js +67 -67
- package/dist/worker/observe/static/dag-layout.d.ts +36 -36
- package/dist/worker/observe/static/dom.js +220 -220
- package/dist/worker/observe/static/relations.js +133 -133
- package/dist/worker/observe/static/run-processing.js +148 -148
- package/dist/worker/observe/static/views/batch.js +227 -227
- package/dist/worker/observe/static/views/failures.js +143 -143
- package/dist/worker/observe/static/views/feature.js +492 -492
- package/dist/worker/observe/static/views/run.js +453 -453
- package/dist/worker/observe/static/views/shell.js +7 -7
- package/dist/worker/observe/static/views/timeline.js +163 -163
- package/dist/worker/preflight.js +2 -1
- package/dist/workflows/dag/backend-test-scenario-param.js +33 -23
- package/dist/workflows/dag/canvas-observer.js +275 -275
- package/dist/workflows/dag/contract-output-registry.js +14 -0
- package/dist/workflows/dag/contract-validator-registrations.js +8 -0
- package/dist/workflows/dag/dynamic-runtime/shared.js +9 -1
- package/dist/workflows/dag/frontend-implementation-contract.js +233 -39
- package/dist/workflows/dag/frontend-prewrite-gate.js +364 -61
- package/dist/workflows/dag/frontend-recovery-plan.js +73 -0
- package/dist/workflows/dag/frontend-recovery-root-manifest.js +123 -0
- package/dist/workflows/dag/frontend-recovery-run.js +539 -0
- package/dist/workflows/dag/frontend-repair.js +219 -18
- package/dist/workflows/dag/frontend-verification-trace.js +47 -32
- package/dist/workflows/dag/frontend-writer-recovery.js +106 -0
- package/dist/workflows/dag/frontend-writer-rollback.js +821 -0
- package/dist/workflows/dag/init-hybrid.js +41 -24
- package/dist/workflows/dag/node-execution.js +89 -0
- package/dist/workflows/dag/recovery-recommendation.js +58 -0
- package/dist/workflows/dag/runner.js +245 -11
- package/dist/workflows/dag/scheduler.js +257 -3
- package/dist/workflows/dag/types.js +130 -2
- package/docs/architecture/evolution.md +73 -73
- package/docs/architecture/system-overview.md +100 -100
- package/docs/architecture/worker-and-feature.md +122 -122
- package/docs/skills/README.md +7 -7
- package/docs/templates/adr.md +60 -60
- package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
- package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
- package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
- package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
- package/docs/templates/agent-dag-report.schema.json +473 -473
- package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
- package/docs/templates/backend-test-result.schema.json +99 -99
- package/docs/templates/evaluation/agents-map-slim-v1.md +87 -87
- package/docs/templates/evaluation/agents-map-verbose-v0.md +153 -153
- package/docs/templates/feature-spec.md +53 -53
- package/docs/templates/frontend-design-contract.md +42 -42
- package/docs/templates/frontend-eval/fixtures/failures/01-type-build-error.md +17 -17
- package/docs/templates/frontend-eval/fixtures/failures/02-unit-component-test-fail.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/03-fixture-schema-drift.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/04-missing-loading-empty-error-state.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/05-forbidden-write-writeset-expansion.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/06-unapproved-dependency-add.md +16 -16
- package/docs/templates/frontend-eval/fixtures/failures/07-mock-production-on.md +21 -21
- package/docs/templates/frontend-eval/fixtures/functional/01-simple-component-style.md +29 -29
- package/docs/templates/frontend-eval/fixtures/functional/02-form-validation.md +28 -28
- package/docs/templates/frontend-eval/fixtures/functional/03-list-detail-page.md +28 -28
- package/docs/templates/frontend-eval/fixtures/functional/04-api-mock.md +29 -29
- package/docs/templates/frontend-eval/fixtures/functional/05-permission-auth-gated-ui.md +27 -27
- package/docs/templates/frontend-eval/fixtures/functional/06-ssr-server-client-boundary.md +28 -28
- package/docs/templates/frontend-eval/fixtures/functional/07-shared-public-component-api.md +28 -28
- package/docs/templates/frontend-eval/fixtures/functional/08-pure-local-no-remote.md +27 -27
- package/docs/templates/frontend-eval/metrics.md +138 -138
- package/docs/templates/frontend-eval/smoke-targets.md +53 -53
- package/docs/templates/frontend-task-constraints.md +35 -35
- package/docs/templates/frontend-task-requirement.md +70 -70
- package/docs/templates/init-evolution-review.md +35 -35
- package/docs/templates/init-managed-agents.md +154 -156
- package/docs/templates/interactive-ui-round2-experiment.md +66 -66
- package/docs/templates/knowledge-graph-bootstrap-dag.json +118 -118
- package/docs/templates/knowledge-sync-dag.json +178 -178
- package/docs/templates/knowledge-sync-draft.schema.json +71 -71
- package/docs/templates/product-line/closeout.yaml +9 -9
- package/docs/templates/product-line/design.md +13 -13
- package/docs/templates/product-line/links.md +10 -10
- package/docs/templates/product-line/requirement.md +17 -17
- package/docs/templates/product-line/test-plan.md +7 -7
- package/docs/templates/project-start-checklist.md +9 -9
- package/docs/templates/qa-report.md +48 -48
- package/docs/templates/sprint-contract.md +29 -29
- package/docs/templates/worker-dogfood-evidence.md +80 -80
- package/docs/templates/worker-dogfood-setup.md +68 -68
- package/harness.json +2 -5
- package/package.json +2 -2
- package/scripts/kb-bootstrap-init-skeleton.sh +0 -0
- package/scripts/kb-graph-incremental-prepare.mjs +0 -0
- package/scripts/kb-graph-materialize.mjs +105 -105
- package/scripts/kb-graph-promote.mjs +164 -164
- package/scripts/kb-query.mjs +554 -554
- package/skills/agent-worker/SKILL.md +48 -48
- package/skills/agent-worker/references/agent-worker-operator.md +159 -159
- package/skills/ai-engineering-context/SKILL.md +48 -48
- package/skills/analyze-product-dependencies/scripts/test-validators.mjs +0 -0
- package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +0 -0
- package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +0 -0
- package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +0 -0
- package/skills/analyze-product-requirements/scripts/compute-source-identity.mjs +0 -0
- package/skills/analyze-product-requirements/scripts/test-validators.mjs +0 -0
- package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +0 -0
- package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +0 -0
- package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +0 -0
- package/skills/browser-tools/browser-content.js +103 -103
- package/skills/browser-tools/browser-cookies.js +35 -35
- package/skills/browser-tools/browser-eval.js +53 -53
- package/skills/browser-tools/browser-hn-scraper.js +108 -108
- package/skills/browser-tools/browser-nav.js +44 -44
- package/skills/browser-tools/browser-pick.js +162 -162
- package/skills/browser-tools/browser-screenshot.js +34 -34
- package/skills/browser-tools/browser-start.js +86 -86
- package/skills/browser-tools/package-lock.json +2556 -2556
- package/skills/browser-tools/package.json +19 -19
- package/skills/code-review-core/SKILL.md +20 -20
- package/skills/codebase-scout/SKILL.md +19 -19
- package/skills/grill-me/SKILL.md +10 -10
- package/skills/local-jacoco-coverage/scripts/run-coverage-analysis.sh +0 -0
- package/skills/local-jacoco-coverage/scripts/start-jacoco-agent.sh +0 -0
- package/skills/loop-agent/SKILL.md +0 -1
- package/skills/loop-agent/references/command-reference.md +639 -641
- package/skills/loop-agent/references/docs-converge.md +126 -126
- package/skills/loop-agent/references/learned/README.md +21 -21
- package/skills/loop-agent/references/pi-prompt.md +23 -23
- package/skills/loop-agent/references/pi-subagent-assisted-mode.md +84 -84
- package/skills/playwright-cli/references/element-attributes.md +23 -23
- package/skills/playwright-cli/references/playwright-tests.md +39 -39
- package/skills/playwright-cli/references/request-mocking.md +87 -87
- package/skills/playwright-cli/references/running-code.md +241 -241
- package/skills/playwright-cli/references/session-management.md +225 -225
- package/skills/playwright-cli/references/storage-state.md +275 -275
- package/skills/playwright-cli/references/test-generation.md +433 -433
- package/skills/requesting-code-review/SKILL.md +101 -101
- package/skills/requesting-code-review/code-reviewer.md +168 -168
- package/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/skills/systematic-debugging/find-polluter.sh +63 -63
- package/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/skills/systematic-debugging/test-academic.md +14 -14
- package/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/skills/using-git-worktrees/SKILL.md +215 -215
- package/skills/verification-before-completion/SKILL.md +154 -154
- package/skills/webapp-testing/SKILL.md +19 -19
- package/dist/worker/console/operation-wait.js +0 -241
- package/dist/worker/console/static/assets/index-SjjjZnV3.js +0 -56
- package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +0 -141
|
@@ -46,60 +46,6 @@ function isHomeFingerprint(value) {
|
|
|
46
46
|
keys[1] === "sha256" &&
|
|
47
47
|
isSha256(value.sha256));
|
|
48
48
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Shape guard for the controller-owned gitignore migration assessment.
|
|
51
|
-
* `assessGitignoreMigration` is the single schema fact source; status/report
|
|
52
|
-
* reads fail closed on any shape that the writer could not have produced
|
|
53
|
-
* (AC-005). `queryError` may be absent and arrays may be empty; extra keys are
|
|
54
|
-
* tolerated for forward compatibility.
|
|
55
|
-
*/
|
|
56
|
-
function isGitignoreMigrationAssessment(value) {
|
|
57
|
-
if (!isRecord(value))
|
|
58
|
-
return false;
|
|
59
|
-
const assessment = value;
|
|
60
|
-
if (assessment.schemaVersion !== 1)
|
|
61
|
-
return false;
|
|
62
|
-
if (typeof assessment.managedBlockRefreshed !== "boolean")
|
|
63
|
-
return false;
|
|
64
|
-
if (typeof assessment.needsAgentsReview !== "boolean")
|
|
65
|
-
return false;
|
|
66
|
-
if (!isRecord(assessment.git))
|
|
67
|
-
return false;
|
|
68
|
-
const git = assessment.git;
|
|
69
|
-
if (typeof git.isRepo !== "boolean")
|
|
70
|
-
return false;
|
|
71
|
-
if (git.queryError !== undefined && typeof git.queryError !== "string") {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
if (!Array.isArray(assessment.harnessTracked) ||
|
|
75
|
-
!assessment.harnessTracked.every((entry) => typeof entry === "string")) {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
if (!Array.isArray(assessment.agentsTracked) ||
|
|
79
|
-
!assessment.agentsTracked.every((entry) => typeof entry === "string")) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
if (!Array.isArray(assessment.stagedRisk) ||
|
|
83
|
-
!assessment.stagedRisk.every((entry) => typeof entry === "string")) {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
if (!Array.isArray(assessment.followUp) ||
|
|
87
|
-
!assessment.followUp.every((entry) => typeof entry === "string")) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
if (!Array.isArray(assessment.recommendedCommands))
|
|
91
|
-
return false;
|
|
92
|
-
for (const entry of assessment.recommendedCommands) {
|
|
93
|
-
if (!isRecord(entry))
|
|
94
|
-
return false;
|
|
95
|
-
if (typeof entry.command !== "string" || typeof entry.note !== "string") {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return (assessment.status === "clean" ||
|
|
100
|
-
assessment.status === "recommended" ||
|
|
101
|
-
assessment.status === "blocked");
|
|
102
|
-
}
|
|
103
49
|
function cloneJson(value) {
|
|
104
50
|
return JSON.parse(JSON.stringify(value));
|
|
105
51
|
}
|
|
@@ -225,143 +171,6 @@ function assertTerminalCoherence(state) {
|
|
|
225
171
|
throw new Error("invalid init upgrade status/phase coherence");
|
|
226
172
|
}
|
|
227
173
|
}
|
|
228
|
-
/** Read-only git query; never mutates the user index (no status refresh, no write). */
|
|
229
|
-
function runGitQuery(cwd, args) {
|
|
230
|
-
return new Promise((resolve) => {
|
|
231
|
-
const child = spawn("git", ["-C", cwd, ...args], {
|
|
232
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
233
|
-
});
|
|
234
|
-
const stdoutChunks = [];
|
|
235
|
-
const stderrChunks = [];
|
|
236
|
-
child.stdout?.on("data", (chunk) => stdoutChunks.push(chunk));
|
|
237
|
-
child.stderr?.on("data", (chunk) => stderrChunks.push(chunk));
|
|
238
|
-
child.on("error", (error) => {
|
|
239
|
-
resolve({ ok: false, stdout: "", stderr: error.message });
|
|
240
|
-
});
|
|
241
|
-
child.on("close", (code) => {
|
|
242
|
-
resolve({
|
|
243
|
-
ok: code === 0,
|
|
244
|
-
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
245
|
-
stderr: Buffer.concat(stderrChunks).toString("utf8"),
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
function splitNulPaths(output) {
|
|
251
|
-
return output.split("\0").filter((entry) => entry.length > 0);
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Gitignore migration assessment (PRD 2026-08-13): inventories tracked
|
|
255
|
-
* `.harness/**` / `.agents/**` with read-only git queries after the managed
|
|
256
|
-
* block has converged, and recommends index-only untrack commands. The
|
|
257
|
-
* controller never mutates the user Git index and never deletes local files.
|
|
258
|
-
*/
|
|
259
|
-
export async function assessGitignoreMigration(repoRoot, input) {
|
|
260
|
-
const base = {
|
|
261
|
-
schemaVersion: 1,
|
|
262
|
-
managedBlockRefreshed: input.managedBlockRefreshed,
|
|
263
|
-
harnessTracked: [],
|
|
264
|
-
agentsTracked: [],
|
|
265
|
-
stagedRisk: [],
|
|
266
|
-
needsAgentsReview: false,
|
|
267
|
-
followUp: [
|
|
268
|
-
"run `git status --short` and confirm only the intended untrack changes",
|
|
269
|
-
"confirm the .harness/ and .agents/ directories still exist locally after untracking",
|
|
270
|
-
"run `loop-agent init doctor` to re-check the gitignore loop-agent block",
|
|
271
|
-
],
|
|
272
|
-
};
|
|
273
|
-
const inside = await runGitQuery(repoRoot, ["rev-parse", "--is-inside-work-tree"]);
|
|
274
|
-
if (!inside.ok) {
|
|
275
|
-
return {
|
|
276
|
-
...base,
|
|
277
|
-
git: {
|
|
278
|
-
isRepo: false,
|
|
279
|
-
queryError: inside.stderr.trim() || "not inside a Git work tree",
|
|
280
|
-
},
|
|
281
|
-
recommendedCommands: [],
|
|
282
|
-
status: "blocked",
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
const tracked = await runGitQuery(repoRoot, [
|
|
286
|
-
"ls-files",
|
|
287
|
-
"-z",
|
|
288
|
-
"--cached",
|
|
289
|
-
"--",
|
|
290
|
-
".harness",
|
|
291
|
-
".agents",
|
|
292
|
-
]);
|
|
293
|
-
if (!tracked.ok) {
|
|
294
|
-
return {
|
|
295
|
-
...base,
|
|
296
|
-
git: {
|
|
297
|
-
isRepo: true,
|
|
298
|
-
queryError: tracked.stderr.trim() || "git ls-files query failed",
|
|
299
|
-
},
|
|
300
|
-
recommendedCommands: [],
|
|
301
|
-
status: "blocked",
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
const staged = await runGitQuery(repoRoot, [
|
|
305
|
-
"diff",
|
|
306
|
-
"--cached",
|
|
307
|
-
"--name-only",
|
|
308
|
-
"-z",
|
|
309
|
-
]);
|
|
310
|
-
if (!staged.ok) {
|
|
311
|
-
return {
|
|
312
|
-
...base,
|
|
313
|
-
git: {
|
|
314
|
-
isRepo: true,
|
|
315
|
-
queryError: staged.stderr.trim() || "git diff --cached query failed",
|
|
316
|
-
},
|
|
317
|
-
recommendedCommands: [],
|
|
318
|
-
status: "blocked",
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
const trackedPaths = splitNulPaths(tracked.stdout);
|
|
322
|
-
const harnessTracked = trackedPaths.filter((entry) => entry.startsWith(".harness/"));
|
|
323
|
-
const agentsTracked = trackedPaths.filter((entry) => entry.startsWith(".agents/"));
|
|
324
|
-
const stagedRisk = splitNulPaths(staged.stdout);
|
|
325
|
-
const needsAgentsReview = agentsTracked.length > 0;
|
|
326
|
-
if (stagedRisk.length > 0) {
|
|
327
|
-
// Fail closed: staged entries make any untrack advice ambiguous.
|
|
328
|
-
return {
|
|
329
|
-
...base,
|
|
330
|
-
git: { isRepo: true },
|
|
331
|
-
harnessTracked,
|
|
332
|
-
agentsTracked,
|
|
333
|
-
stagedRisk,
|
|
334
|
-
needsAgentsReview,
|
|
335
|
-
recommendedCommands: [],
|
|
336
|
-
status: "blocked",
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
const recommendedCommands = [];
|
|
340
|
-
if (harnessTracked.length > 0) {
|
|
341
|
-
recommendedCommands.push({
|
|
342
|
-
command: "git rm -r --cached --ignore-unmatch .harness",
|
|
343
|
-
note: "untracks tracked .harness runtime facts; index-only, working-tree files are kept",
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
if (agentsTracked.length > 0) {
|
|
347
|
-
recommendedCommands.push({
|
|
348
|
-
command: "git rm -r --cached --ignore-unmatch .agents",
|
|
349
|
-
note: "untracks tracked .agents local skills; index-only, working-tree files are kept; review team-shareable customizations first",
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
return {
|
|
353
|
-
...base,
|
|
354
|
-
git: { isRepo: true },
|
|
355
|
-
harnessTracked,
|
|
356
|
-
agentsTracked,
|
|
357
|
-
stagedRisk,
|
|
358
|
-
needsAgentsReview,
|
|
359
|
-
recommendedCommands,
|
|
360
|
-
status: harnessTracked.length > 0 || agentsTracked.length > 0
|
|
361
|
-
? "recommended"
|
|
362
|
-
: "clean",
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
174
|
function runRoot(repoRoot) {
|
|
366
175
|
return path.join(repoRoot, RUN_ROOT);
|
|
367
176
|
}
|
|
@@ -431,7 +240,6 @@ async function writeControllerAnchor(input) {
|
|
|
431
240
|
throw new Error("init upgrade controller authority anchor path escapes Git directory");
|
|
432
241
|
}
|
|
433
242
|
let authoritativeHomeFingerprint;
|
|
434
|
-
let authoritativeGitignoreMigrationSha256;
|
|
435
243
|
if (input.initialize) {
|
|
436
244
|
if (await exists(location.file)) {
|
|
437
245
|
throw new Error("init upgrade controller authority anchor already exists");
|
|
@@ -444,14 +252,6 @@ async function writeControllerAnchor(input) {
|
|
|
444
252
|
else {
|
|
445
253
|
const current = await readControllerAnchor(location.repoRoot, input.state);
|
|
446
254
|
authoritativeHomeFingerprint = current.homeFingerprint;
|
|
447
|
-
// Preserve the gitignore migration artifact binding across later
|
|
448
|
-
// mergeAuthority/completion writes; fail closed on a corrupt or
|
|
449
|
-
// non-SHA-256 binding instead of silently dropping or propagating it.
|
|
450
|
-
const digest = input.gitignoreMigrationSha256 ?? current.gitignoreMigrationSha256;
|
|
451
|
-
if (digest !== undefined && !isSha256(digest)) {
|
|
452
|
-
throw new Error("init upgrade controller authority gitignore migration digest binding is invalid");
|
|
453
|
-
}
|
|
454
|
-
authoritativeGitignoreMigrationSha256 = digest;
|
|
455
255
|
}
|
|
456
256
|
await writeJsonAtomic(location.file, {
|
|
457
257
|
schemaVersion: 1,
|
|
@@ -459,9 +259,6 @@ async function writeControllerAnchor(input) {
|
|
|
459
259
|
runId: input.state.runId,
|
|
460
260
|
controllerIdentity: input.state.controllerIdentity,
|
|
461
261
|
homeFingerprint: authoritativeHomeFingerprint,
|
|
462
|
-
...(authoritativeGitignoreMigrationSha256 !== undefined
|
|
463
|
-
? { gitignoreMigrationSha256: authoritativeGitignoreMigrationSha256 }
|
|
464
|
-
: {}),
|
|
465
262
|
...(input.mergeAuthority ? { mergeAuthority: input.mergeAuthority } : {}),
|
|
466
263
|
...(input.completion ? { completion: input.completion } : {}),
|
|
467
264
|
});
|
|
@@ -654,7 +451,7 @@ async function saveState(directory, state) {
|
|
|
654
451
|
state.updatedAt = new Date().toISOString();
|
|
655
452
|
await writeJsonAtomic(path.join(directory, "state.json"), state);
|
|
656
453
|
}
|
|
657
|
-
function toResult(state, verification
|
|
454
|
+
function toResult(state, verification) {
|
|
658
455
|
return {
|
|
659
456
|
runId: state.runId,
|
|
660
457
|
status: state.status,
|
|
@@ -665,10 +462,9 @@ function toResult(state, verification, gitignoreMigration) {
|
|
|
665
462
|
humanDecisions: state.humanDecisions,
|
|
666
463
|
nextAction: state.nextAction,
|
|
667
464
|
...(verification ? { verification } : {}),
|
|
668
|
-
...(gitignoreMigration ? { gitignoreMigration } : {}),
|
|
669
465
|
};
|
|
670
466
|
}
|
|
671
|
-
function renderReport(state, verification
|
|
467
|
+
function renderReport(state, verification) {
|
|
672
468
|
const lines = [
|
|
673
469
|
"# loop-agent init upgrade report",
|
|
674
470
|
"",
|
|
@@ -684,47 +480,6 @@ function renderReport(state, verification, gitignoreMigration) {
|
|
|
684
480
|
`- retired path actions: ${state.actionReceipts.filter((action) => action.type === "migrate-owned-file" || action.type === "remove-owned-file" || action.type === "remove-empty-directory").length}`,
|
|
685
481
|
`- remaining model merge tasks: ${state.mergeTasks.length}`,
|
|
686
482
|
`- remaining human decisions: ${state.humanDecisions.length}`,
|
|
687
|
-
`- gitignore migration assessment: \`.harness/init-upgrades/${state.runId}/gitignore-migration.json\` (index-only untrack guidance; the controller never modifies the Git index)`,
|
|
688
|
-
...(gitignoreMigration
|
|
689
|
-
? [
|
|
690
|
-
"",
|
|
691
|
-
"## Gitignore migration assessment",
|
|
692
|
-
"",
|
|
693
|
-
`- status: \`${gitignoreMigration.status}\``,
|
|
694
|
-
`- managed block refreshed: \`${gitignoreMigration.managedBlockRefreshed}\``,
|
|
695
|
-
`- tracked \`.harness\` inventory: ${gitignoreMigration.harnessTracked.length > 0
|
|
696
|
-
? gitignoreMigration.harnessTracked
|
|
697
|
-
.map((entry) => `\`${entry}\``)
|
|
698
|
-
.join(", ")
|
|
699
|
-
: "(none)"}`,
|
|
700
|
-
`- tracked \`.agents\` inventory: ${gitignoreMigration.agentsTracked.length > 0
|
|
701
|
-
? gitignoreMigration.agentsTracked
|
|
702
|
-
.map((entry) => `\`${entry}\``)
|
|
703
|
-
.join(", ")
|
|
704
|
-
: "(none)"}`,
|
|
705
|
-
...(gitignoreMigration.stagedRisk.length > 0
|
|
706
|
-
? [
|
|
707
|
-
`- staged risk: ${gitignoreMigration.stagedRisk
|
|
708
|
-
.map((entry) => `\`${entry}\``)
|
|
709
|
-
.join(", ")}`,
|
|
710
|
-
]
|
|
711
|
-
: []),
|
|
712
|
-
...(gitignoreMigration.git.queryError
|
|
713
|
-
? [
|
|
714
|
-
`- git query blocker: \`${gitignoreMigration.git.queryError}\``,
|
|
715
|
-
]
|
|
716
|
-
: []),
|
|
717
|
-
`- \`.agents\` review required: \`${gitignoreMigration.needsAgentsReview}\``,
|
|
718
|
-
"- recommended commands:",
|
|
719
|
-
...(gitignoreMigration.recommendedCommands.length > 0
|
|
720
|
-
? gitignoreMigration.recommendedCommands.map((entry) => ` - \`${entry.command}\` — ${entry.note}`)
|
|
721
|
-
: [" - (none)"]),
|
|
722
|
-
"- follow-up:",
|
|
723
|
-
...(gitignoreMigration.followUp.length > 0
|
|
724
|
-
? gitignoreMigration.followUp.map((entry) => ` - ${entry}`)
|
|
725
|
-
: [" - (none)"]),
|
|
726
|
-
]
|
|
727
|
-
: []),
|
|
728
483
|
"",
|
|
729
484
|
"## Next action",
|
|
730
485
|
"",
|
|
@@ -746,8 +501,8 @@ function renderReport(state, verification, gitignoreMigration) {
|
|
|
746
501
|
];
|
|
747
502
|
return `${lines.join("\n")}\n`;
|
|
748
503
|
}
|
|
749
|
-
async function writeReport(directory, state, verification
|
|
750
|
-
await writeFile(path.join(directory, "final-report.md"), renderReport(state, verification
|
|
504
|
+
async function writeReport(directory, state, verification) {
|
|
505
|
+
await writeFile(path.join(directory, "final-report.md"), renderReport(state, verification), "utf-8");
|
|
751
506
|
}
|
|
752
507
|
async function assertInactive(input) {
|
|
753
508
|
let activity;
|
|
@@ -2548,62 +2303,14 @@ async function readValidatedStatusState(repoRoot, runId) {
|
|
|
2548
2303
|
throw new Error("Controller identity drift detected for persisted init upgrade state");
|
|
2549
2304
|
}
|
|
2550
2305
|
}
|
|
2551
|
-
return { state, directory
|
|
2552
|
-
}
|
|
2553
|
-
/**
|
|
2554
|
-
* Read-only projection of the controller-owned gitignore migration assessment
|
|
2555
|
-
* for status/report reads. The artifact is written by executeUpgrade after the
|
|
2556
|
-
* managed block has converged; a missing artifact is tolerated only while the
|
|
2557
|
-
* run has not yet reached that write point (DISCOVER/VERSION_GATE). Every
|
|
2558
|
-
* other missing, malformed, or shape-invalid artifact fails closed so
|
|
2559
|
-
* status/report never trust mutable or incomplete content (AC-005).
|
|
2560
|
-
*/
|
|
2561
|
-
async function readGitignoreMigrationProjection(directory, state, gitignoreMigrationSha256) {
|
|
2562
|
-
const file = path.join(directory, "gitignore-migration.json");
|
|
2563
|
-
let rawBytes;
|
|
2564
|
-
let raw;
|
|
2565
|
-
try {
|
|
2566
|
-
rawBytes = await readFile(file);
|
|
2567
|
-
raw = rawBytes.toString("utf-8");
|
|
2568
|
-
}
|
|
2569
|
-
catch (error) {
|
|
2570
|
-
const cause = error;
|
|
2571
|
-
if (cause.code === "ENOENT") {
|
|
2572
|
-
if (state.phase === "DISCOVER" || state.phase === "VERSION_GATE") {
|
|
2573
|
-
return undefined;
|
|
2574
|
-
}
|
|
2575
|
-
throw new Error(`init upgrade integrity error: gitignore migration artifact is missing for run ${state.runId} (phase ${state.phase}); refusing to trust an incomplete run`);
|
|
2576
|
-
}
|
|
2577
|
-
throw error;
|
|
2578
|
-
}
|
|
2579
|
-
let parsed;
|
|
2580
|
-
try {
|
|
2581
|
-
parsed = JSON.parse(raw);
|
|
2582
|
-
}
|
|
2583
|
-
catch {
|
|
2584
|
-
throw new Error(`init upgrade integrity error: gitignore migration artifact is malformed JSON for run ${state.runId} (${file})`);
|
|
2585
|
-
}
|
|
2586
|
-
if (!isGitignoreMigrationAssessment(parsed)) {
|
|
2587
|
-
throw new Error(`init upgrade integrity error: gitignore migration artifact has an invalid shape for run ${state.runId} (${file})`);
|
|
2588
|
-
}
|
|
2589
|
-
// The artifact exists, so this run has generated an assessment; the
|
|
2590
|
-
// controller authority binding must exist, be a legal SHA-256, and match
|
|
2591
|
-
// the raw artifact bytes on disk (fail closed otherwise).
|
|
2592
|
-
if (gitignoreMigrationSha256 === undefined || !isSha256(gitignoreMigrationSha256)) {
|
|
2593
|
-
throw new Error(`init upgrade integrity error: gitignore migration artifact digest binding is missing or invalid for run ${state.runId}`);
|
|
2594
|
-
}
|
|
2595
|
-
if (sha256(rawBytes) !== gitignoreMigrationSha256) {
|
|
2596
|
-
throw new Error(`init upgrade integrity error: gitignore migration artifact digest does not match the controller authority binding for run ${state.runId}`);
|
|
2597
|
-
}
|
|
2598
|
-
return parsed;
|
|
2306
|
+
return { state, directory };
|
|
2599
2307
|
}
|
|
2600
2308
|
async function readStatusResult(repoRoot, runId) {
|
|
2601
|
-
const { state
|
|
2602
|
-
if (state.status !== "completed")
|
|
2603
|
-
return toResult(state
|
|
2604
|
-
}
|
|
2309
|
+
const { state } = await readValidatedStatusState(repoRoot, runId);
|
|
2310
|
+
if (state.status !== "completed")
|
|
2311
|
+
return toResult(state);
|
|
2605
2312
|
const authenticated = await readFreshCompletedVerification(repoRoot, state);
|
|
2606
|
-
return toResult(state, authenticated.verification
|
|
2313
|
+
return toResult(state, authenticated.verification);
|
|
2607
2314
|
}
|
|
2608
2315
|
async function executeUpgrade(directory, state, input) {
|
|
2609
2316
|
const identity = await readIdentity();
|
|
@@ -2738,50 +2445,17 @@ async function executeUpgrade(directory, state, input) {
|
|
|
2738
2445
|
}
|
|
2739
2446
|
}
|
|
2740
2447
|
state.humanDecisions = post.humanDecisions;
|
|
2741
|
-
// Gitignore migration assessment: after the managed block has converged,
|
|
2742
|
-
// inventory tracked .harness/.agents paths with read-only git queries and
|
|
2743
|
-
// recommend index-only untrack commands. The controller never mutates the
|
|
2744
|
-
// user Git index; suggested commands only change the index and keep the
|
|
2745
|
-
// working tree intact.
|
|
2746
|
-
const gitignoreMigration = await assessGitignoreMigration(state.repoRoot, {
|
|
2747
|
-
managedBlockRefreshed: !post.deterministicActions.some((action) => action.type === "refresh-managed-block" &&
|
|
2748
|
-
action.path === ".gitignore"),
|
|
2749
|
-
});
|
|
2750
|
-
await writeJsonAtomic(path.join(directory, "gitignore-migration.json"), gitignoreMigration);
|
|
2751
|
-
// Bind the raw on-disk artifact bytes to the Git-dir controller authority
|
|
2752
|
-
// before any needs-human-decision/model-merge/completed return; later
|
|
2753
|
-
// mergeAuthority/completion anchor writes preserve this binding.
|
|
2754
|
-
await writeControllerAnchor({
|
|
2755
|
-
state,
|
|
2756
|
-
gitignoreMigrationSha256: sha256(await readFile(path.join(directory, "gitignore-migration.json"))),
|
|
2757
|
-
});
|
|
2758
|
-
if (gitignoreMigration.status === "blocked" ||
|
|
2759
|
-
gitignoreMigration.needsAgentsReview) {
|
|
2760
|
-
// Route through the existing needs-human-decision pause: `.agents`
|
|
2761
|
-
// tracked content must be reviewed (PRD §7) and staged blockers must be
|
|
2762
|
-
// resolved before safe untrack guidance can be given (PRD §8).
|
|
2763
|
-
post.humanDecisions.push(gitignoreMigration.status === "blocked"
|
|
2764
|
-
? {
|
|
2765
|
-
path: ".harness/** (gitignore migration)",
|
|
2766
|
-
reason: "staged changes or a failed git query block safe untrack guidance; resolve the blocker, then rerun the migration assessment",
|
|
2767
|
-
}
|
|
2768
|
-
: {
|
|
2769
|
-
path: ".agents/** (gitignore migration)",
|
|
2770
|
-
reason: "tracked .agents content may include team-shareable customizations; review before running the suggested untrack commands",
|
|
2771
|
-
});
|
|
2772
|
-
}
|
|
2773
|
-
state.humanDecisions = post.humanDecisions;
|
|
2774
2448
|
if (post.humanDecisions.length > 0) {
|
|
2775
2449
|
state.mergeTasks = [];
|
|
2776
2450
|
state.mergeGuard = undefined;
|
|
2777
2451
|
state.status = "needs-human-decision";
|
|
2778
2452
|
state.phase = "MODEL_MERGE";
|
|
2779
2453
|
state.nextAction =
|
|
2780
|
-
"Resolve the recorded destructive, credential, or ambiguous decisions; the controller will not overwrite uncertain user intent.
|
|
2454
|
+
"Resolve the recorded destructive, credential, or ambiguous decisions; the controller will not overwrite uncertain user intent.";
|
|
2781
2455
|
await writeJsonAtomic(path.join(directory, "merge-tasks.json"), state.mergeTasks);
|
|
2782
2456
|
await saveState(directory, state);
|
|
2783
|
-
await writeReport(directory, state
|
|
2784
|
-
return toResult(state
|
|
2457
|
+
await writeReport(directory, state);
|
|
2458
|
+
return toResult(state);
|
|
2785
2459
|
}
|
|
2786
2460
|
if (post.modelMergeTasks.length > 0) {
|
|
2787
2461
|
const activeTask = post.modelMergeTasks[0];
|
|
@@ -2813,8 +2487,8 @@ async function executeUpgrade(directory, state, input) {
|
|
|
2813
2487
|
state.nextAction = `Complete only task ${activeTask.taskId} within allowedPaths=[${activeTask.allowedPaths.join(", ")}], then call init upgrade --continue. The controller will reject every other workspace change and all symlink/realpath escapes.`;
|
|
2814
2488
|
await writeJsonAtomic(path.join(directory, "merge-tasks.json"), state.mergeTasks);
|
|
2815
2489
|
await saveState(directory, state);
|
|
2816
|
-
await writeReport(directory, state
|
|
2817
|
-
return toResult(state
|
|
2490
|
+
await writeReport(directory, state);
|
|
2491
|
+
return toResult(state);
|
|
2818
2492
|
}
|
|
2819
2493
|
state.mergeTasks = [];
|
|
2820
2494
|
state.mergeGuard = undefined;
|
|
@@ -2830,7 +2504,7 @@ async function executeUpgrade(directory, state, input) {
|
|
|
2830
2504
|
state.nextAction =
|
|
2831
2505
|
"Init upgrade completed; reload the host session so updated AGENTS, skills, and recovery extensions are discovered.";
|
|
2832
2506
|
// The report is controller-produced before its exact bytes are anchored.
|
|
2833
|
-
await writeReport(directory, state, verification
|
|
2507
|
+
await writeReport(directory, state, verification);
|
|
2834
2508
|
const finalReportSha256 = sha256(await readFile(path.join(directory, "final-report.md")));
|
|
2835
2509
|
await writeControllerAnchor({
|
|
2836
2510
|
state,
|
|
@@ -2855,8 +2529,8 @@ async function executeUpgrade(directory, state, input) {
|
|
|
2855
2529
|
: "Verification failed. Inspect verification.json; repair only the controller-returned concrete merge path or address the reported external blocker, then use --continue.";
|
|
2856
2530
|
}
|
|
2857
2531
|
await saveState(directory, state);
|
|
2858
|
-
await writeReport(directory, state, verification
|
|
2859
|
-
return toResult(state, verification
|
|
2532
|
+
await writeReport(directory, state, verification);
|
|
2533
|
+
return toResult(state, verification);
|
|
2860
2534
|
}
|
|
2861
2535
|
export async function runInitUpgrade(input) {
|
|
2862
2536
|
const repoRoot = path.resolve(input.repoRoot);
|
|
@@ -2867,20 +2541,14 @@ export async function runInitUpgrade(input) {
|
|
|
2867
2541
|
if (mode === "status")
|
|
2868
2542
|
return await readStatusResult(repoRoot, input.runId);
|
|
2869
2543
|
if (mode === "report") {
|
|
2870
|
-
const { state
|
|
2544
|
+
const { state } = await readValidatedStatusState(repoRoot, input.runId);
|
|
2871
2545
|
if (state.status === "completed") {
|
|
2872
2546
|
const authenticated = await readFreshCompletedVerification(repoRoot, state);
|
|
2873
|
-
// Completed report bytes are anchored by finalReportSha256; still
|
|
2874
|
-
// verify the gitignore migration artifact binding so shape-valid
|
|
2875
|
-
// tampering fails closed here as well.
|
|
2876
|
-
await readGitignoreMigrationProjection(directory, state, anchor.gitignoreMigrationSha256);
|
|
2877
2547
|
return { markdown: authenticated.reportMarkdown };
|
|
2878
2548
|
}
|
|
2879
2549
|
// Non-completed reports are projections of the validated state, never an
|
|
2880
2550
|
// unauthenticated read of a mutable run-local report file.
|
|
2881
|
-
return {
|
|
2882
|
-
markdown: renderReport(state, undefined, await readGitignoreMigrationProjection(directory, state, anchor.gitignoreMigrationSha256)),
|
|
2883
|
-
};
|
|
2551
|
+
return { markdown: renderReport(state) };
|
|
2884
2552
|
}
|
|
2885
2553
|
const runId = mode === "continue"
|
|
2886
2554
|
? input.runId
|
package/dist/commands/init.js
CHANGED
|
@@ -846,19 +846,55 @@ function mergeGitignoreManagedBlock(existing, block) {
|
|
|
846
846
|
return `${block}\n`;
|
|
847
847
|
return `${existing.trimEnd()}\n\n${block}\n`;
|
|
848
848
|
}
|
|
849
|
-
/**
|
|
850
|
-
* Shared ignore rules for loop-agent runtime facts. The four directories are
|
|
851
|
-
* local, rebuildable runtime surface: every developer runs loop-agent init
|
|
852
|
-
* after cloning, so nothing inside them is team-shareable by default.
|
|
853
|
-
* `scripts/` and `ai_workspace/loop-agent/` stay on the shared commit surface.
|
|
854
|
-
*/
|
|
849
|
+
/** Shared ignore rules for loop-agent runtime facts; keep prompts/ and directory structure shareable. */
|
|
855
850
|
export function buildManagedGitignoreBlock() {
|
|
856
851
|
return [
|
|
857
852
|
GITIGNORE_BLOCK_START,
|
|
858
|
-
"# loop-agent runtime:
|
|
859
|
-
"
|
|
860
|
-
"
|
|
853
|
+
"# loop-agent runtime: ignore personal/session facts; keep prompts and directory placeholders shareable",
|
|
854
|
+
"",
|
|
855
|
+
"# tasks (source + runtime state per developer/session)",
|
|
856
|
+
".harness/tasks/*",
|
|
857
|
+
"!.harness/tasks/.gitkeep",
|
|
858
|
+
"",
|
|
859
|
+
"# DAG runs",
|
|
860
|
+
".harness/dag-runs/active/*",
|
|
861
|
+
"!.harness/dag-runs/active/.gitkeep",
|
|
862
|
+
".harness/dag-runs/completed/*",
|
|
863
|
+
"!.harness/dag-runs/completed/.gitkeep",
|
|
864
|
+
".harness/dag-runs/paused/*",
|
|
865
|
+
"!.harness/dag-runs/paused/.gitkeep",
|
|
866
|
+
"",
|
|
867
|
+
"# one-shot executor runs",
|
|
868
|
+
".harness/runs/*",
|
|
869
|
+
"!.harness/runs/.gitkeep",
|
|
870
|
+
"!.harness/runs/active/",
|
|
871
|
+
"!.harness/runs/active/.gitkeep",
|
|
872
|
+
"!.harness/runs/completed/",
|
|
873
|
+
"!.harness/runs/completed/.gitkeep",
|
|
874
|
+
"!.harness/runs/failed/",
|
|
875
|
+
"!.harness/runs/failed/.gitkeep",
|
|
876
|
+
"",
|
|
877
|
+
"# session / cache / logs / recomputable surface state",
|
|
878
|
+
".harness/live/",
|
|
879
|
+
".harness/cache/",
|
|
880
|
+
".harness/*.log",
|
|
881
|
+
".harness/init-surface.json",
|
|
882
|
+
".harness/init-upgrades/",
|
|
883
|
+
"",
|
|
884
|
+
"# Eval Lab runtime (candidates, campaigns, scorecards, dogfood scratch)",
|
|
885
|
+
".harness/evaluation/",
|
|
886
|
+
"",
|
|
887
|
+
"# fullstack / worker dogfood evidence (local campaign scratch)",
|
|
888
|
+
".harness/dogfood-evidence/",
|
|
889
|
+
"",
|
|
890
|
+
"# worker task pool",
|
|
891
|
+
".harness/task-pool/*",
|
|
861
892
|
".task-pool/",
|
|
893
|
+
"",
|
|
894
|
+
"# repo-local skill dependencies installed inside projected skills",
|
|
895
|
+
".agents/skills/*/node_modules/",
|
|
896
|
+
"",
|
|
897
|
+
"# multi-worktree parallel mode",
|
|
862
898
|
".worktrees/",
|
|
863
899
|
GITIGNORE_BLOCK_END,
|
|
864
900
|
].join("\n");
|
|
@@ -1051,8 +1087,26 @@ async function ensureHarnessDirs(repoRoot, written) {
|
|
|
1051
1087
|
await mkdir(path.join(repoRoot, dir), { recursive: true });
|
|
1052
1088
|
written.push(dir);
|
|
1053
1089
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1090
|
+
const placeholders = [
|
|
1091
|
+
".harness/tasks/.gitkeep",
|
|
1092
|
+
".harness/dag-runs/active/.gitkeep",
|
|
1093
|
+
".harness/dag-runs/completed/.gitkeep",
|
|
1094
|
+
".harness/dag-runs/paused/.gitkeep",
|
|
1095
|
+
".harness/runs/.gitkeep",
|
|
1096
|
+
".harness/runs/active/.gitkeep",
|
|
1097
|
+
".harness/runs/completed/.gitkeep",
|
|
1098
|
+
".harness/runs/failed/.gitkeep",
|
|
1099
|
+
];
|
|
1100
|
+
for (const relativePath of placeholders) {
|
|
1101
|
+
const target = path.join(repoRoot, relativePath);
|
|
1102
|
+
try {
|
|
1103
|
+
await access(target);
|
|
1104
|
+
}
|
|
1105
|
+
catch {
|
|
1106
|
+
await writeFile(target, "", "utf8");
|
|
1107
|
+
written.push(relativePath);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1056
1110
|
}
|
|
1057
1111
|
async function writeCompatPrompts(input) {
|
|
1058
1112
|
for (const [name, content] of Object.entries(COMPAT_PROMPTS)) {
|
|
@@ -2436,7 +2490,6 @@ export function buildInitInstructions(input) {
|
|
|
2436
2490
|
"When the user says `loop-agent初始化更新`, `loop-agent 初始化更新`, `更新 loop-agent 初始化内容`, or an equivalent write request, run `loop-agent init upgrade --repo-root . --json` as the single controller-owned entry. Complete returned single-file allowedPaths merge tasks and call `--continue` until a stable terminal result; do not stop at check-update, needs-safe-update, needs-model-merge, or verification-pending.",
|
|
2437
2491
|
"Explicit `检查初始化更新`, `初始化更新校验`, or `只检查,不要修改` stays strictly read-only: run only `loop-agent init check-update --repo-root . --markdown` and do not create an upgrade run.",
|
|
2438
2492
|
"Upgrade manages project `.opencode/plugins/`, `.pi/extensions/`, and `.pi/settings.json` by nested merge. Pi must trust the project before loading these settings; do not read or write `~/.pi/agent/settings.json` by default.",
|
|
2439
|
-
"The upgrade also writes a read-only gitignore migration assessment (`.harness/init-upgrades/<run-id>/gitignore-migration.json`): tracked `.harness/**` and `.agents/**` get index-only `git rm -r --cached --ignore-unmatch` guidance (working-tree files are kept). Pause for human review when `.agents` content is tracked or when staged changes / git query failures block safe guidance; never run git rm yourself.",
|
|
2440
2493
|
"",
|
|
2441
2494
|
"## Apply Defaults",
|
|
2442
2495
|
"",
|
|
@@ -2452,7 +2505,7 @@ export function buildInitInstructions(input) {
|
|
|
2452
2505
|
"- Enrich the root `README.md`: keep the deterministic project title and the loop-agent managed block intact, and fill the human-authored sections (项目概览, 技术栈与目录结构, 开发与验证) from the target project's actual files. The root README must serve both as a human-first project entry and as an agent work entry; replace the initialization-model supplement comments when the project files provide the information.",
|
|
2453
2506
|
`- Populate \`${governanceRoot}/verification-matrix.md\` with the target project's actual quick, standard, and full verification commands derived from its real language and toolchain, keeping the governance rows intact.`,
|
|
2454
2507
|
"- Project repo-local skills live in `.agents/skills/`. Do not create a root `skills/` directory in the target project; the package's bundled `skills/` remains the built-in fallback.",
|
|
2455
|
-
"- Merge a loop-agent managed block into `.gitignore` that ignores
|
|
2508
|
+
"- Merge a loop-agent managed block into `.gitignore` that ignores harness runtime facts (tasks, dag-runs, runs, evaluation, dogfood-evidence, live, cache, init-surface.json, .harness/task-pool, legacy .task-pool residue) while keeping prompts and directory placeholders shareable.",
|
|
2456
2509
|
"- Do not copy examples by default; examples stay bundled in the tool and are available through `loop-agent examples`.",
|
|
2457
2510
|
"- Add or update a loop-agent managed block in AGENTS.md.",
|
|
2458
2511
|
"- The generated AGENTS.md must include documentation convergence and structured DAG write-boundary rules so target projects keep the same working discipline as this repository.",
|
|
@@ -3329,7 +3382,7 @@ export async function runInitDoctor(input) {
|
|
|
3329
3382
|
? await readFile(gitignorePath, "utf-8")
|
|
3330
3383
|
: "";
|
|
3331
3384
|
add("gitignore loop-agent block", gitignoreContent.includes(GITIGNORE_BLOCK_START) &&
|
|
3332
|
-
gitignoreContent.includes(".harness/"), ".gitignore managed runtime ignores");
|
|
3385
|
+
gitignoreContent.includes(".harness/tasks/*"), ".gitignore managed runtime ignores");
|
|
3333
3386
|
const requiredScripts = Object.keys(INIT_SCRIPT_FILES);
|
|
3334
3387
|
const missingScripts = [];
|
|
3335
3388
|
for (const script of requiredScripts) {
|
|
@@ -37,17 +37,17 @@ export function parseLoopBenchmarkArgs(args) {
|
|
|
37
37
|
return { json, markdown, outputPath };
|
|
38
38
|
}
|
|
39
39
|
export function printLoopBenchmarkUsage() {
|
|
40
|
-
console.log(`usage: loop-benchmark [options]
|
|
41
|
-
|
|
42
|
-
Deterministic loop-agent loop benchmark baseline (no live Pi/Cursor calls).
|
|
43
|
-
|
|
44
|
-
Options:
|
|
45
|
-
--json Emit JSON (default when no format flag is set)
|
|
46
|
-
--markdown Emit Markdown report
|
|
47
|
-
--output <path> Write Markdown report to a repo-relative or absolute path
|
|
48
|
-
-h, --help Show this help
|
|
49
|
-
|
|
50
|
-
Control groups: single-repair, 3-pass-convergence, 3-pass-convergence+quota.
|
|
40
|
+
console.log(`usage: loop-benchmark [options]
|
|
41
|
+
|
|
42
|
+
Deterministic loop-agent loop benchmark baseline (no live Pi/Cursor calls).
|
|
43
|
+
|
|
44
|
+
Options:
|
|
45
|
+
--json Emit JSON (default when no format flag is set)
|
|
46
|
+
--markdown Emit Markdown report
|
|
47
|
+
--output <path> Write Markdown report to a repo-relative or absolute path
|
|
48
|
+
-h, --help Show this help
|
|
49
|
+
|
|
50
|
+
Control groups: single-repair, 3-pass-convergence, 3-pass-convergence+quota.
|
|
51
51
|
Recommendation never changes convergence.enabled default.`);
|
|
52
52
|
}
|
|
53
53
|
export async function runLoopBenchmark(repoRoot, rawArgs) {
|