@awak-app/simy-cli 0.5.15 → 0.5.17

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.
Files changed (45) hide show
  1. package/README.md +78 -15
  2. package/package.json +2 -2
  3. package/src/agent.js +33 -1
  4. package/src/cli-contract.js +1 -1
  5. package/src/codex-plugins/simy/.codex-plugin/plugin.json +5 -6
  6. package/src/codex-plugins/simy/hooks/README.md +17 -0
  7. package/src/codex-plugins/simy/hooks/connection-reminder.mjs +184 -0
  8. package/src/codex-plugins/simy/hooks/hooks.json +27 -0
  9. package/src/connection-discovery.js +49 -0
  10. package/src/console/app.js +2 -2
  11. package/src/orchestrator/audit.js +47 -5
  12. package/src/orchestrator/budget.js +1 -1
  13. package/src/orchestrator/checklist-continuation.js +21 -0
  14. package/src/orchestrator/completion-contract.js +1 -1
  15. package/src/orchestrator/contract.js +2 -0
  16. package/src/{codex-plugins/simy/skills/agentic-delivery-loop/SKILL.md → orchestrator/delivery/WORKFLOW.md} +121 -13
  17. package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/references/acceptance-evidence.md +27 -3
  18. package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/references/change-boundary-matrix.md +1 -1
  19. package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/references/delivery-levels.md +78 -27
  20. package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/references/minimum-completion.md +3 -3
  21. package/src/orchestrator/delivery/references/pr-closure.md +203 -0
  22. package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/references/state-and-receipts.md +4 -1
  23. package/src/orchestrator/delivery/references/ux-specification.md +98 -0
  24. package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/scripts/production-contract.mjs +1 -1
  25. package/src/orchestrator/delivery-level.js +19 -0
  26. package/src/orchestrator/evidence.js +64 -5
  27. package/src/orchestrator/independent-audit.js +18 -0
  28. package/src/orchestrator/index.js +7 -0
  29. package/src/orchestrator/instruction.js +32 -3
  30. package/src/orchestrator/loop.js +4 -1
  31. package/src/orchestrator/minimum-completion.js +2 -2
  32. package/src/orchestrator/pr-closure.js +26 -0
  33. package/src/orchestrator/pr-preparation.js +420 -0
  34. package/src/orchestrator/presentation.js +2 -2
  35. package/src/orchestrator/result.js +8 -2
  36. package/src/orchestrator/ux-specification.js +20 -0
  37. package/src/runner.js +104 -1
  38. package/src/sqm/agent-skill.js +39 -7
  39. package/src/codex-plugins/simy/skills/agentic-delivery-loop/agents/openai.yaml +0 -5
  40. /package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/references/chrome-user-verification.md +0 -0
  41. /package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/references/cross-repository-control.md +0 -0
  42. /package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/references/local-sqm-evidence.md +0 -0
  43. /package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/references/shared-system-specifications.md +0 -0
  44. /package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/scripts/check-acceptance.mjs +0 -0
  45. /package/src/{codex-plugins/simy/skills/agentic-delivery-loop → orchestrator/delivery}/scripts/check-minimum-completion.mjs +0 -0
package/src/runner.js CHANGED
@@ -19,6 +19,7 @@ import {
19
19
  redactExecutionText,
20
20
  } from "./orchestrator/execution-io.js";
21
21
  import { summarizeCodingLoopEvent } from "./orchestrator/presentation.js";
22
+ import { PR_PREPARATION_CHECKS } from "./orchestrator/pr-preparation.js";
22
23
  import { increaseProviderTokenBudget, refreshBudgetState } from "./orchestrator/budget.js";
23
24
  import { appendEvent } from "./orchestrator/shared.js";
24
25
  import {
@@ -73,6 +74,7 @@ const INTERRUPTED_STATES = new Set([
73
74
  "re_instructing",
74
75
  ]);
75
76
  const RESTORABLE_STATES = new Set([...RESUMABLE_STATES, ...INTERRUPTED_STATES]);
77
+ const PR_PREPARATION_IDS = new Set(PR_PREPARATION_CHECKS.map((row) => row.id));
76
78
 
77
79
  export { LocalRunRegistry };
78
80
 
@@ -530,6 +532,18 @@ async function runLocalCodingRun(
530
532
 
531
533
  markAttachmentsDelivered(run.request.attachments);
532
534
 
535
+ // All collectors and the executor must use the same root. Bind a missing
536
+ // default only after resolving the authorized checkout, including on resume.
537
+ if (!run.snapshot.charter.ui_evidence_root) {
538
+ const evidenceRoot = path.join(repositoryPath, ".artifacts");
539
+ run.snapshot.charter.ui_evidence_root = evidenceRoot;
540
+ run.request.ui_evidence_root = evidenceRoot;
541
+ appendEvent(run.snapshot, run.status, "Local evidence root bound to the verified checkout.", {
542
+ code: "local_evidence_root_bound",
543
+ });
544
+ await updateRun(run, run.status);
545
+ }
546
+
533
547
  const executor =
534
548
  executeAttempt ||
535
549
  ((context) =>
@@ -1007,9 +1021,90 @@ function redactedAttemptForLedger(attempt, attachments) {
1007
1021
  },
1008
1022
  raw_output: structuredResultForLedger(attempt.raw_output),
1009
1023
  observed_evidence: observedEvidenceForLedger(attempt.observed_evidence),
1024
+ pr_preparation: prPreparationForLedger(attempt.pr_preparation),
1025
+ skipped_checks: skippedChecksForLedger(attempt.skipped_checks),
1010
1026
  };
1011
1027
  }
1012
1028
 
1029
+ function prPreparationForLedger(value) {
1030
+ return (Array.isArray(value) ? value : []).map((row) => ({
1031
+ id: PR_PREPARATION_IDS.has(row?.id) ? row.id : "unrecognized",
1032
+ applicability: row?.applicability || null,
1033
+ passed: row?.passed === true,
1034
+ observation_present: Boolean(row?.observation),
1035
+ reason_present: Boolean(row?.reason),
1036
+ authoritative_source_present: Boolean(row?.authoritative_source),
1037
+ evidence_ref_count: Array.isArray(row?.evidence_refs) ? row.evidence_refs.length : 0,
1038
+ bound_revisions: validatedHashesForLedger(row?.bound_revisions, 40),
1039
+ companion_revisions: (Array.isArray(row?.companion_revisions) ? row.companion_revisions : [])
1040
+ .map((item) => ({
1041
+ repository_present: Boolean(item?.repository),
1042
+ sha: validatedHashForLedger(item?.sha, 40),
1043
+ })),
1044
+ manifest_revisions: (Array.isArray(row?.manifest_revisions) ? row.manifest_revisions : [])
1045
+ .map((item) => ({
1046
+ manifest_present: Boolean(item?.manifest),
1047
+ sha256: validatedHashForLedger(item?.sha256, 64),
1048
+ })),
1049
+ cleanup_residual_count: Number.isInteger(row?.cleanup_residual_count)
1050
+ ? row.cleanup_residual_count
1051
+ : null,
1052
+ security_privacy_check_count: Array.isArray(row?.security_privacy_checks)
1053
+ ? row.security_privacy_checks.length
1054
+ : 0,
1055
+ browser_artifact_count: Array.isArray(row?.browser_artifacts)
1056
+ ? row.browser_artifacts.length
1057
+ : 0,
1058
+ locale_count: Array.isArray(row?.locales_checked) ? row.locales_checked.length : 0,
1059
+ console_error_count: Number.isInteger(row?.console_error_count)
1060
+ ? row.console_error_count
1061
+ : null,
1062
+ network_failure_count: Number.isInteger(row?.network_failure_count)
1063
+ ? row.network_failure_count
1064
+ : null,
1065
+ heading_levels_checked: (Array.isArray(row?.heading_levels_checked)
1066
+ ? row.heading_levels_checked
1067
+ : []).filter((item) => Number.isInteger(item) && item >= 1 && item <= 6),
1068
+ leading_space_checked: row?.leading_space_checked === true,
1069
+ trailing_hash_checked: row?.trailing_hash_checked === true,
1070
+ single_official_checklist: row?.single_official_checklist === true,
1071
+ unverified_model_output_labeled: row?.unverified_model_output_labeled === true,
1072
+ deployment_target_present: Boolean(row?.deployment_target),
1073
+ deployment_target_source_present: Boolean(row?.deployment_target_source),
1074
+ revision_observation_method_present: Boolean(row?.revision_observation_method),
1075
+ live_write_policy: ["no_persistence", "scoped_fixture", "authorized_production_write"]
1076
+ .includes(row?.live_write_policy) ? row.live_write_policy : null,
1077
+ resume_paths_checked: (Array.isArray(row?.resume_paths_checked)
1078
+ ? row.resume_paths_checked
1079
+ : []).filter((item) => ["normal", "paid", "checkpoint"].includes(item)),
1080
+ paid_resume_support: ["supported", "not_supported"].includes(row?.paid_resume_support)
1081
+ ? row.paid_resume_support
1082
+ : null,
1083
+ paid_resume_support_source_present: Boolean(row?.paid_resume_support_source),
1084
+ derived_views_recomputed: row?.derived_views_recomputed === true,
1085
+ artifact_content_preserved: row?.artifact_content_preserved === true,
1086
+ }));
1087
+ }
1088
+
1089
+ function skippedChecksForLedger(value) {
1090
+ return (Array.isArray(value) ? value : []).map((row) => ({
1091
+ name_present: Boolean(row?.name),
1092
+ reason_present: Boolean(row?.reason),
1093
+ impact_present: Boolean(row?.impact),
1094
+ }));
1095
+ }
1096
+
1097
+ function validatedHashesForLedger(value, length) {
1098
+ return stringArrayForLedger(value)
1099
+ .map((item) => validatedHashForLedger(item, length))
1100
+ .filter(Boolean);
1101
+ }
1102
+
1103
+ function validatedHashForLedger(value, length) {
1104
+ const candidate = typeof value === "string" ? value.trim().toLowerCase() : "";
1105
+ return new RegExp(`^[a-f0-9]{${length}}$`).test(candidate) ? candidate : null;
1106
+ }
1107
+
1013
1108
  function redactedEventDetail(value, lifecycleState, attachments) {
1014
1109
  const detail = value && typeof value === "object" ? value : {};
1015
1110
  const result = {};
@@ -1070,7 +1165,7 @@ function observedEvidenceForLedger(value) {
1070
1165
  head_branch: github.head_branch || null,
1071
1166
  head_sha: github.head_sha || null,
1072
1167
  base_branch: github.base_branch || null,
1073
- checks: Array.isArray(github.checks) ? github.checks : [],
1168
+ checks: githubChecksForLedger(github.checks),
1074
1169
  checks_present: github.checks_present === true,
1075
1170
  checks_passing: github.checks_passing === true,
1076
1171
  required_checks_present: github.required_checks_present === true,
@@ -1082,6 +1177,14 @@ function stringArrayForLedger(value) {
1082
1177
  return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
1083
1178
  }
1084
1179
 
1180
+ function githubChecksForLedger(value) {
1181
+ const allowedStates = new Set(["success", "skipped", "failure", "pending"]);
1182
+ return (Array.isArray(value) ? value : []).map((item) => ({
1183
+ name_present: Boolean(item?.name),
1184
+ state: allowedStates.has(item?.state) ? item.state : "pending",
1185
+ }));
1186
+ }
1187
+
1085
1188
  export function toCompatibleCodingLoopState(state) {
1086
1189
  switch (state) {
1087
1190
  case "risk_classifying":
@@ -104,8 +104,12 @@ export async function installSqmAgentSkill({ home = homedir(), platforms = Objec
104
104
  }
105
105
 
106
106
  export async function inspectCodexPlugin({ home = homedir() } = {}) {
107
- const manifest = await bundledPluginManifest();
108
- const expectedDigest = await directoryDigest(BUNDLED_CODEX_PLUGIN_ROOT, { manifest });
107
+ const overrides = await installedPluginOverrides();
108
+ const manifest = await bundledPluginManifest({ overrides });
109
+ const expectedDigest = await directoryDigest(BUNDLED_CODEX_PLUGIN_ROOT, {
110
+ manifest,
111
+ overrides,
112
+ });
109
113
  const target = codexPluginPath(home);
110
114
  const installedDigest = await directoryDigest(target, { missing: null });
111
115
  const marketplacePath = codexMarketplacePath(home);
@@ -152,8 +156,12 @@ async function installCodexPlugin({ home }) {
152
156
  await rm(staged, { recursive: true, force: true });
153
157
  await rm(backup, { recursive: true, force: true });
154
158
  await cp(BUNDLED_CODEX_PLUGIN_ROOT, staged, { recursive: true, errorOnExist: true });
159
+ const overrides = await installedPluginOverrides();
160
+ for (const [relative, content] of overrides) {
161
+ await writeFile(path.join(staged, relative), content);
162
+ }
155
163
  await writeFile(path.join(staged, ".codex-plugin", "plugin.json"),
156
- `${JSON.stringify(await bundledPluginManifest(), null, 2)}\n`);
164
+ `${JSON.stringify(await bundledPluginManifest({ overrides }), null, 2)}\n`);
157
165
  let backedUp = false;
158
166
  try {
159
167
  if (await pathExists(target)) {
@@ -303,14 +311,36 @@ async function fileDigest(target) {
303
311
  }
304
312
  }
305
313
 
306
- async function bundledPluginManifest() {
314
+ async function bundledPluginManifest({ overrides = new Map() } = {}) {
307
315
  const manifest = JSON.parse(await readFile(path.join(BUNDLED_CODEX_PLUGIN_ROOT, ".codex-plugin", "plugin.json"), "utf8"));
308
316
  // A stable content-derived version refreshes Codex's cache only when the bundle changes.
309
- const digest = await directoryDigest(BUNDLED_CODEX_PLUGIN_ROOT);
317
+ const digest = await directoryDigest(BUNDLED_CODEX_PLUGIN_ROOT, { overrides });
310
318
  return { ...manifest, version: `${manifest.version.split("+")[0]}+codex.${digest}` };
311
319
  }
312
320
 
313
- async function directoryDigest(root, { missing = "throw", manifest } = {}) {
321
+ async function installedPluginOverrides() {
322
+ const relative = "hooks/hooks.json";
323
+ const source = JSON.parse(await readFile(path.join(BUNDLED_CODEX_PLUGIN_ROOT, relative), "utf8"));
324
+ const commandPrefix = "node ";
325
+ const runtime = shellQuote(process.execPath);
326
+ for (const groups of Object.values(source.hooks || {})) {
327
+ for (const group of groups || []) {
328
+ for (const hook of group.hooks || []) {
329
+ if (typeof hook.command === "string" && hook.command.startsWith(commandPrefix)) {
330
+ hook.command = `${runtime} ${hook.command.slice(commandPrefix.length)}`;
331
+ }
332
+ }
333
+ }
334
+ }
335
+ return new Map([[relative, `${JSON.stringify(source, null, 2)}\n`]]);
336
+ }
337
+
338
+ function shellQuote(value) {
339
+ if (process.platform === "win32") return `"${value.replaceAll('"', '""')}"`;
340
+ return `'${value.replaceAll("'", "'\\''")}'`;
341
+ }
342
+
343
+ async function directoryDigest(root, { missing = "throw", manifest, overrides = new Map() } = {}) {
314
344
  let rootStat;
315
345
  try {
316
346
  rootStat = await lstat(root);
@@ -336,7 +366,9 @@ async function directoryDigest(root, { missing = "throw", manifest } = {}) {
336
366
  if (!entry.isFile()) throw new Error(`${target} must be a regular file.`);
337
367
  const content = manifest && relative === ".codex-plugin/plugin.json"
338
368
  ? `${JSON.stringify(manifest, null, 2)}\n`
339
- : await readFile(target);
369
+ : overrides.has(relative)
370
+ ? overrides.get(relative)
371
+ : await readFile(target);
340
372
  hash.update(relative).update("\0").update(content).update("\0");
341
373
  }
342
374
  };
@@ -1,5 +0,0 @@
1
- interface:
2
- display_name: "Agentic Delivery Loop"
3
- short_description: "Converge code changes through real live proof"
4
- default_prompt: "Use $agentic-delivery-loop to take this change from reproduction through verified delivery."
5
-