@awak-app/simy-cli 0.5.8 → 0.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -0
- package/package.json +7 -3
- package/src/agent.js +70 -9
- package/src/auto-update.js +312 -35
- package/src/browser.js +24 -7
- package/src/cli-contract.js +1 -1
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/SKILL.md +227 -18
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/acceptance-evidence.md +131 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/change-boundary-matrix.md +20 -1
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/cross-repository-control.md +76 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/delivery-levels.md +80 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/minimum-completion.md +137 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/shared-system-specifications.md +138 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/state-and-receipts.md +18 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-acceptance.mjs +193 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs +221 -0
- package/src/console/app.js +21 -2
- package/src/console/commands.js +3 -0
- package/src/desktop-host.js +220 -0
- package/src/desktop-process-lock.js +231 -0
- package/src/desktop-status.js +263 -0
- package/src/direct-executor.js +6 -0
- package/src/index.js +37 -11
- package/src/install-update.js +494 -0
- package/src/orchestrator/audit.js +17 -2
- package/src/orchestrator/completion-contract.js +1 -1
- package/src/orchestrator/evidence.js +9 -1
- package/src/orchestrator/independent-audit.js +13 -1
- package/src/orchestrator/instruction.js +13 -1
- package/src/orchestrator/loop.js +34 -4
- package/src/orchestrator/minimum-completion.js +108 -0
- package/src/orchestrator/result.js +7 -0
package/src/orchestrator/loop.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { minimumCharter } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs";
|
|
1
2
|
import { auditAttempt, evaluatePrReadiness } from "./audit.js";
|
|
2
3
|
import {
|
|
3
4
|
buildIndependentAudit,
|
|
@@ -9,7 +10,7 @@ import { buildAttempt, mergeTokenUsage } from "./result.js";
|
|
|
9
10
|
import { evaluateRetryCircuit } from "./retry.js";
|
|
10
11
|
import { appendEvent, publish } from "./shared.js";
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
async function runCodingLoopOwned({
|
|
13
14
|
snapshot,
|
|
14
15
|
executeAttempt,
|
|
15
16
|
executeIndependentAudit,
|
|
@@ -21,6 +22,19 @@ export async function runCodingLoop({
|
|
|
21
22
|
shouldStop = () => false,
|
|
22
23
|
consumeHumanGuidance = () => "",
|
|
23
24
|
}) {
|
|
25
|
+
if (!resume && snapshot.attempts.length > 0) {
|
|
26
|
+
return recheckPrReadinessOwned({ snapshot, collectEvidence, checkSqm, onUpdate });
|
|
27
|
+
}
|
|
28
|
+
snapshot.implementation_gate_passed = false;
|
|
29
|
+
snapshot.done_gate_passed = false;
|
|
30
|
+
try { minimumCharter(snapshot.charter); } catch {
|
|
31
|
+
snapshot.final_audit = humanGate("Completion charter requires refresh before verification.", [{
|
|
32
|
+
code: "MINIMUM_CHARTER_REQUIRED", severity: "blocker", target: "completion_contract",
|
|
33
|
+
explanation: "Missing or unsupported completion charter. Preserve history, re-charter and collect current minimum evidence.", repairability: "manual",
|
|
34
|
+
}]);
|
|
35
|
+
await publish(snapshot, "waiting_human", onUpdate);
|
|
36
|
+
return snapshot;
|
|
37
|
+
}
|
|
24
38
|
if (!resume || snapshot.attempts.length === 0) {
|
|
25
39
|
appendEvent(snapshot, "risk_classifying", "PR risk classification completed.", {
|
|
26
40
|
risk: snapshot.charter.risk,
|
|
@@ -197,6 +211,7 @@ export async function runCodingLoop({
|
|
|
197
211
|
await publish(snapshot, "independent_auditing", onUpdate);
|
|
198
212
|
if (shouldStop()) return stopCodingLoop(snapshot, onUpdate);
|
|
199
213
|
const auditInstruction = buildIndependentAuditInstruction(snapshot.charter, attempt);
|
|
214
|
+
const reviewedMatrix = attempt.observed_evidence?.minimum_completion?.matrix_sha256;
|
|
200
215
|
const auditExecution = await safeExecution(() =>
|
|
201
216
|
executeIndependentAudit({
|
|
202
217
|
attemptNumber,
|
|
@@ -215,6 +230,8 @@ export async function runCodingLoop({
|
|
|
215
230
|
attempt.token_usage = mergeTokenUsage(attempt.token_usage, auditExecution.tokenUsage);
|
|
216
231
|
attempt.budget = refreshBudgetState(snapshot);
|
|
217
232
|
|
|
233
|
+
attempt.independent_audit.minimum_matrix_sha256 = reviewedMatrix;
|
|
234
|
+
|
|
218
235
|
// Re-collect after the read-only auditor to catch any mutated HEAD or working tree.
|
|
219
236
|
attempt.observed_evidence = await safeEvidence(collectEvidence, attempt);
|
|
220
237
|
attempt.sqm = await safeSqm(checkSqm, attempt, attempt.sqm);
|
|
@@ -276,9 +293,11 @@ async function stopCodingLoop(snapshot, onUpdate) {
|
|
|
276
293
|
return snapshot;
|
|
277
294
|
}
|
|
278
295
|
|
|
279
|
-
|
|
296
|
+
async function recheckPrReadinessOwned({ snapshot, collectEvidence, checkSqm = null, onUpdate }) {
|
|
280
297
|
const attempt = snapshot.attempts.at(-1);
|
|
281
|
-
|
|
298
|
+
snapshot.implementation_gate_passed = false;
|
|
299
|
+
snapshot.done_gate_passed = false;
|
|
300
|
+
if (!attempt) return snapshot;
|
|
282
301
|
appendEvent(snapshot, "checking_pr", "Refreshing GitHub review and CI evidence.", {
|
|
283
302
|
attempt_number: attempt.attempt_number,
|
|
284
303
|
});
|
|
@@ -296,7 +315,7 @@ export async function recheckPrReadiness({ snapshot, collectEvidence, checkSqm =
|
|
|
296
315
|
snapshot.final_audit = aggregateAudit(
|
|
297
316
|
attempt,
|
|
298
317
|
attempt.pr_readiness.ready,
|
|
299
|
-
attempt.independent_audit
|
|
318
|
+
attempt.independent_audit?.findings || [],
|
|
300
319
|
);
|
|
301
320
|
appendEvent(snapshot, attempt.pr_readiness.state, attempt.pr_readiness.summary, {
|
|
302
321
|
pr_url: attempt.pr_url,
|
|
@@ -583,3 +602,14 @@ function humanGate(summary, findings) {
|
|
|
583
602
|
release_gate: null,
|
|
584
603
|
};
|
|
585
604
|
}
|
|
605
|
+
|
|
606
|
+
const activeControllers = new Set();
|
|
607
|
+
async function withController(options, action) {
|
|
608
|
+
const owner = options.snapshot?.id;
|
|
609
|
+
if (typeof owner !== "string" || !owner) throw new Error("Delivery snapshot ID required");
|
|
610
|
+
if (activeControllers.has(owner)) throw new Error("Delivery controller is already active for this snapshot");
|
|
611
|
+
activeControllers.add(owner);
|
|
612
|
+
try { return await action(options); } finally { activeControllers.delete(owner); }
|
|
613
|
+
}
|
|
614
|
+
export const runCodingLoop = options => withController(options, runCodingLoopOwned);
|
|
615
|
+
export const recheckPrReadiness = options => withController(options, recheckPrReadinessOwned);
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { lstat, realpath } from "node:fs/promises";
|
|
3
|
+
import {
|
|
4
|
+
minimumCharter,
|
|
5
|
+
minimumContext,
|
|
6
|
+
checkMinimumCompletion,
|
|
7
|
+
loadMinimumJson,
|
|
8
|
+
} from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs";
|
|
9
|
+
import {
|
|
10
|
+
contextDigest,
|
|
11
|
+
sha256,
|
|
12
|
+
} from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-acceptance.mjs";
|
|
13
|
+
|
|
14
|
+
export function minimumCharterDigest(charter) {
|
|
15
|
+
return sha256(Buffer.from(JSON.stringify(minimumCharter(charter))));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function collectMinimumCompletion({
|
|
19
|
+
charter,
|
|
20
|
+
attempt,
|
|
21
|
+
repositoryPath,
|
|
22
|
+
local,
|
|
23
|
+
}) {
|
|
24
|
+
try {
|
|
25
|
+
if (!local.available || !local.working_tree_clean)
|
|
26
|
+
throw new Error("Clean current checkout required");
|
|
27
|
+
const root = await realpath(
|
|
28
|
+
charter.ui_evidence_root || path.join(repositoryPath, ".artifacts"),
|
|
29
|
+
);
|
|
30
|
+
const requested = attempt.raw_output?.delivery_evidence_path;
|
|
31
|
+
if (typeof requested !== "string") throw new Error("Matrix path missing");
|
|
32
|
+
const file = path.resolve(root, requested);
|
|
33
|
+
const relative = path.relative(root, file);
|
|
34
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative))
|
|
35
|
+
throw new Error("Outside evidence root");
|
|
36
|
+
let current = root;
|
|
37
|
+
for (const segment of relative.split(path.sep)) {
|
|
38
|
+
current = path.join(current, segment);
|
|
39
|
+
if ((await lstat(current)).isSymbolicLink())
|
|
40
|
+
throw new Error("Symlink evidence path");
|
|
41
|
+
}
|
|
42
|
+
const matrix = await loadMinimumJson(file);
|
|
43
|
+
const report = await checkMinimumCompletion({
|
|
44
|
+
charter,
|
|
45
|
+
matrix,
|
|
46
|
+
context: minimumContext(charter, local.head_sha),
|
|
47
|
+
evidenceRoot: path.dirname(file),
|
|
48
|
+
});
|
|
49
|
+
if (report.status !== "evidence_complete") return report;
|
|
50
|
+
// Check mapping paths without reading source contents or following links outside the checkout.
|
|
51
|
+
const repo = await realpath(repositoryPath);
|
|
52
|
+
for (const row of matrix.results) {
|
|
53
|
+
for (const ref of row.implementation_refs || []) {
|
|
54
|
+
if (typeof ref !== "string") continue;
|
|
55
|
+
const target = await realpath(path.resolve(repo, ref));
|
|
56
|
+
const rel = path.relative(repo, target);
|
|
57
|
+
if (
|
|
58
|
+
rel.startsWith("..") ||
|
|
59
|
+
path.isAbsolute(rel) ||
|
|
60
|
+
!(await lstat(target)).isFile()
|
|
61
|
+
)
|
|
62
|
+
throw new Error("Invalid implementation mapping");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (contextDigest(await loadMinimumJson(file)) !== report.matrix_sha256)
|
|
66
|
+
throw new Error("Matrix changed during verification");
|
|
67
|
+
return { ...report, evidence_path: file };
|
|
68
|
+
} catch {
|
|
69
|
+
return {
|
|
70
|
+
status: "evidence_incomplete",
|
|
71
|
+
errors: [
|
|
72
|
+
"Minimum completion evidence missing, invalid or stale; verify the actual operation, result, postcondition and integration for every AC-N.",
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function minimumCompletionCheck(charter, attempt) {
|
|
79
|
+
const report = attempt.observed_evidence?.minimum_completion;
|
|
80
|
+
const head = attempt.observed_evidence?.local?.head_sha;
|
|
81
|
+
let passed = false;
|
|
82
|
+
try {
|
|
83
|
+
passed =
|
|
84
|
+
report?.minimum_completion_version === 1 &&
|
|
85
|
+
report.status === "evidence_complete" &&
|
|
86
|
+
report.errors?.length === 0 &&
|
|
87
|
+
report.charter_sha256 === minimumCharterDigest(charter) &&
|
|
88
|
+
report.context_sha256 === contextDigest(minimumContext(charter, head)) &&
|
|
89
|
+
/^[a-f0-9]{64}$/.test(report.matrix_sha256) &&
|
|
90
|
+
report.head_sha === head &&
|
|
91
|
+
attempt.observed_evidence.local.working_tree_clean === true;
|
|
92
|
+
} catch {
|
|
93
|
+
/* Unsupported/missing charters never waive this gate. */
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
id: "minimum_completion",
|
|
97
|
+
label: "Every requested outcome has current operation and system evidence",
|
|
98
|
+
passed: Boolean(passed),
|
|
99
|
+
detail: passed
|
|
100
|
+
? "Current minimum evidence verified; independent coverage/oracle review and remaining gates still apply."
|
|
101
|
+
: (
|
|
102
|
+
report?.errors || [
|
|
103
|
+
"Minimum completion evidence has not been verified.",
|
|
104
|
+
]
|
|
105
|
+
).join("; "),
|
|
106
|
+
evidence_refs: report?.evidence_path ? [report.evidence_path] : [],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { minimumCharterDigest } from "./minimum-completion.js";
|
|
2
|
+
import { minimumContext } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs";
|
|
3
|
+
import { contextDigest } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-acceptance.mjs";
|
|
1
4
|
import { cleanString, stringArray } from "./shared.js";
|
|
2
5
|
import { normalizeProblemSolving } from "./problem-solving.js";
|
|
3
6
|
import {
|
|
@@ -15,6 +18,8 @@ export function buildAttempt({ attemptNumber, charter, instruction, promptInterv
|
|
|
15
18
|
const completed = execution.exitCode === 0 && !execution.error;
|
|
16
19
|
const now = new Date().toISOString();
|
|
17
20
|
return {
|
|
21
|
+
minimum_charter_sha256: safeDigest(() => minimumCharterDigest(charter)),
|
|
22
|
+
minimum_context_sha256: safeDigest(() => contextDigest(minimumContext(charter, cleanString(result.commit_sha)))),
|
|
18
23
|
attempt_number: attemptNumber,
|
|
19
24
|
backend: charter.backend,
|
|
20
25
|
base_branch: charter.base_branch,
|
|
@@ -112,3 +117,5 @@ function buildArtifactPreviews(result) {
|
|
|
112
117
|
function isUsageRecord(value) {
|
|
113
118
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
114
119
|
}
|
|
120
|
+
|
|
121
|
+
function safeDigest(compute) { try { return compute(); } catch { return null; } }
|