@lamentis/naome 1.3.0 → 1.3.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.
Files changed (149) hide show
  1. package/Cargo.lock +2 -2
  2. package/README.md +11 -2
  3. package/bin/naome.js +62 -24
  4. package/crates/naome-cli/Cargo.toml +1 -1
  5. package/crates/naome-cli/src/context_commands.rs +47 -0
  6. package/crates/naome-cli/src/dispatcher.rs +6 -0
  7. package/crates/naome-cli/src/main.rs +43 -6
  8. package/crates/naome-cli/src/quality_commands.rs +31 -46
  9. package/crates/naome-cli/src/quality_output.rs +34 -0
  10. package/crates/naome-cli/src/quality_reconcile_command.rs +45 -0
  11. package/crates/naome-cli/src/repository_model_commands.rs +84 -0
  12. package/crates/naome-cli/src/task_commands.rs +62 -0
  13. package/crates/naome-cli/src/workflow_commands.rs +100 -3
  14. package/crates/naome-core/Cargo.toml +1 -1
  15. package/crates/naome-core/src/context/helpers.rs +75 -0
  16. package/crates/naome-core/src/context/select.rs +134 -0
  17. package/crates/naome-core/src/context/types.rs +43 -0
  18. package/crates/naome-core/src/context.rs +6 -0
  19. package/crates/naome-core/src/decision/states.rs +1 -1
  20. package/crates/naome-core/src/decision.rs +4 -1
  21. package/crates/naome-core/src/install_plan.rs +18 -0
  22. package/crates/naome-core/src/intent/resolver_catalog/active.rs +38 -0
  23. package/crates/naome-core/src/intent/resolver_catalog/baseline.rs +44 -0
  24. package/crates/naome-core/src/intent/resolver_catalog/completed.rs +56 -0
  25. package/crates/naome-core/src/intent/resolver_catalog/dirty.rs +32 -0
  26. package/crates/naome-core/src/intent/resolver_catalog/ready.rs +32 -0
  27. package/crates/naome-core/src/intent/resolver_catalog/system.rs +20 -0
  28. package/crates/naome-core/src/intent/resolver_catalog.rs +12 -166
  29. package/crates/naome-core/src/journal.rs +2 -7
  30. package/crates/naome-core/src/lib.rs +33 -10
  31. package/crates/naome-core/src/quality/adapter_ios.rs +131 -0
  32. package/crates/naome-core/src/quality/adapter_support.rs +67 -0
  33. package/crates/naome-core/src/quality/adapters.rs +81 -18
  34. package/crates/naome-core/src/quality/cache.rs +7 -9
  35. package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +4 -7
  36. package/crates/naome-core/src/quality/config.rs +21 -3
  37. package/crates/naome-core/src/quality/mod.rs +138 -7
  38. package/crates/naome-core/src/quality/reconcile.rs +138 -0
  39. package/crates/naome-core/src/quality/reconcile_anchors.rs +64 -0
  40. package/crates/naome-core/src/quality/scanner/analysis.rs +20 -5
  41. package/crates/naome-core/src/quality/scanner.rs +62 -17
  42. package/crates/naome-core/src/quality/semantic/checks.rs +17 -0
  43. package/crates/naome-core/src/quality/semantic/route.rs +1 -1
  44. package/crates/naome-core/src/quality/structure/adapter_ios.rs +149 -0
  45. package/crates/naome-core/src/quality/structure/adapters.rs +60 -42
  46. package/crates/naome-core/src/quality/structure/checks/directory.rs +6 -4
  47. package/crates/naome-core/src/quality/structure/classify/roles.rs +51 -5
  48. package/crates/naome-core/src/quality/structure/config.rs +24 -3
  49. package/crates/naome-core/src/quality/structure/mod.rs +3 -0
  50. package/crates/naome-core/src/quality/types.rs +20 -1
  51. package/crates/naome-core/src/repository_model/detect.rs +188 -0
  52. package/crates/naome-core/src/repository_model/explain.rs +121 -0
  53. package/crates/naome-core/src/repository_model/path_scan.rs +67 -0
  54. package/crates/naome-core/src/repository_model/path_support.rs +59 -0
  55. package/crates/naome-core/src/repository_model/types.rs +152 -0
  56. package/crates/naome-core/src/repository_model/world.rs +48 -0
  57. package/crates/naome-core/src/repository_model/world_adapters.rs +145 -0
  58. package/crates/naome-core/src/repository_model/world_path_facts.rs +55 -0
  59. package/crates/naome-core/src/repository_model/world_paths.rs +168 -0
  60. package/crates/naome-core/src/repository_model.rs +164 -0
  61. package/crates/naome-core/src/route/builtin_checks.rs +40 -1
  62. package/crates/naome-core/src/task_ledger/import.rs +142 -0
  63. package/crates/naome-core/src/task_ledger/model.rs +13 -0
  64. package/crates/naome-core/src/task_ledger/proof_record.rs +52 -0
  65. package/crates/naome-core/src/task_ledger/read.rs +118 -0
  66. package/crates/naome-core/src/task_ledger/render.rs +55 -0
  67. package/crates/naome-core/src/task_ledger/write.rs +38 -0
  68. package/crates/naome-core/src/task_ledger.rs +48 -0
  69. package/crates/naome-core/src/task_state/api.rs +4 -2
  70. package/crates/naome-core/src/task_state/completed_refresh.rs +5 -16
  71. package/crates/naome-core/src/task_state/diff.rs +2 -2
  72. package/crates/naome-core/src/task_state/evidence.rs +8 -3
  73. package/crates/naome-core/src/task_state/mod.rs +1 -1
  74. package/crates/naome-core/src/task_state/progress.rs +13 -0
  75. package/crates/naome-core/src/task_state/proof_model.rs +8 -8
  76. package/crates/naome-core/src/task_state/repair.rs +2 -2
  77. package/crates/naome-core/src/task_state/task_diff_api.rs +9 -18
  78. package/crates/naome-core/src/task_state/types.rs +24 -0
  79. package/crates/naome-core/src/verification.rs +29 -18
  80. package/crates/naome-core/src/workflow/agent/capability.rs +194 -0
  81. package/crates/naome-core/src/workflow/agent/context_delta.rs +42 -0
  82. package/crates/naome-core/src/workflow/agent/decision.rs +32 -0
  83. package/crates/naome-core/src/workflow/agent/execution.rs +80 -0
  84. package/crates/naome-core/src/workflow/agent/proof.rs +24 -0
  85. package/crates/naome-core/src/workflow/agent/support.rs +58 -0
  86. package/crates/naome-core/src/workflow/agent/watchdog.rs +47 -0
  87. package/crates/naome-core/src/workflow/agent.rs +34 -0
  88. package/crates/naome-core/src/workflow/agent_types.rs +105 -0
  89. package/crates/naome-core/src/workflow/doctor.rs +39 -0
  90. package/crates/naome-core/src/workflow/mod.rs +11 -0
  91. package/crates/naome-core/src/workflow/output.rs +8 -2
  92. package/crates/naome-core/src/workflow/phase_inference.rs +1 -1
  93. package/crates/naome-core/tests/context.rs +99 -0
  94. package/crates/naome-core/tests/harness_health.rs +33 -40
  95. package/crates/naome-core/tests/install_plan.rs +12 -0
  96. package/crates/naome-core/tests/quality.rs +178 -2
  97. package/crates/naome-core/tests/quality_performance.rs +39 -2
  98. package/crates/naome-core/tests/quality_structure_adapters.rs +39 -0
  99. package/crates/naome-core/tests/repo_support/mod.rs +7 -1
  100. package/crates/naome-core/tests/repo_support/verification_values.rs +148 -1
  101. package/crates/naome-core/tests/repository_model.rs +281 -0
  102. package/crates/naome-core/tests/route_user_diff.rs +49 -1
  103. package/crates/naome-core/tests/semantic_legacy.rs +72 -38
  104. package/crates/naome-core/tests/task_ledger.rs +328 -0
  105. package/crates/naome-core/tests/task_state.rs +34 -14
  106. package/crates/naome-core/tests/task_state_support/mod.rs +2 -1
  107. package/crates/naome-core/tests/task_state_support/states.rs +28 -11
  108. package/crates/naome-core/tests/verification.rs +14 -39
  109. package/crates/naome-core/tests/verification_contract.rs +6 -52
  110. package/crates/naome-core/tests/workflow_agent.rs +233 -0
  111. package/crates/naome-core/tests/workflow_agent_support/mod.rs +159 -0
  112. package/crates/naome-core/tests/workflow_doctor.rs +21 -0
  113. package/crates/naome-core/tests/workflow_integrity.rs +2 -20
  114. package/crates/naome-core/tests/workflow_support/mod.rs +59 -20
  115. package/installer/codex-hooks.js +121 -0
  116. package/installer/context.js +10 -0
  117. package/installer/filesystem.js +4 -0
  118. package/installer/flows.js +8 -4
  119. package/installer/harness-files.js +6 -0
  120. package/installer/install-plan.js +4 -0
  121. package/installer/main.js +1 -1
  122. package/installer/native.js +1 -1
  123. package/native/darwin-arm64/naome +0 -0
  124. package/native/linux-x64/naome +0 -0
  125. package/package.json +1 -1
  126. package/templates/naome-root/.codex/config.toml +2 -0
  127. package/templates/naome-root/.codex/hooks.json +70 -0
  128. package/templates/naome-root/.naome/bin/check-harness-health.js +8 -6
  129. package/templates/naome-root/.naome/bin/check-task-state.js +12 -7
  130. package/templates/naome-root/.naome/bin/codex-hook-io.js +122 -0
  131. package/templates/naome-root/.naome/bin/codex-hook-policy.js +180 -0
  132. package/templates/naome-root/.naome/bin/codex-hook-runtime.js +174 -0
  133. package/templates/naome-root/.naome/bin/codex-hook.js +6 -0
  134. package/templates/naome-root/.naome/bin/naome.js +35 -4
  135. package/templates/naome-root/.naome/manifest.json +12 -6
  136. package/templates/naome-root/.naome/repository-model.json +6 -0
  137. package/templates/naome-root/.naome/repository-quality.json +3 -1
  138. package/templates/naome-root/.naome/verification.json +15 -1
  139. package/templates/naome-root/AGENTS.md +38 -83
  140. package/templates/naome-root/docs/naome/agent-workflow.md +54 -18
  141. package/templates/naome-root/docs/naome/codex-hooks.md +82 -0
  142. package/templates/naome-root/docs/naome/context-economy.md +73 -0
  143. package/templates/naome-root/docs/naome/first-run.md +25 -14
  144. package/templates/naome-root/docs/naome/index.md +18 -10
  145. package/templates/naome-root/docs/naome/repository-model.md +92 -0
  146. package/templates/naome-root/docs/naome/repository-quality.md +47 -7
  147. package/templates/naome-root/docs/naome/repository-structure.md +10 -3
  148. package/templates/naome-root/docs/naome/task-ledger.md +71 -0
  149. package/templates/naome-root/docs/naome/testing.md +16 -3
@@ -30,6 +30,10 @@ export function copyTemplateFile(ctx, sourcePath) {
30
30
  const relativePath = relative(ctx.templateRoot, sourcePath);
31
31
  const targetPath = join(ctx.targetRoot, relativePath);
32
32
 
33
+ if (ctx.optionalCodexHookPaths.includes(relativePath) && !ctx.codexHooksEnabled) {
34
+ return;
35
+ }
36
+
33
37
  if (hasSymlinkInTargetPath(ctx, relativePath)) {
34
38
  ctx.skipped.push(relativePath);
35
39
  ctx.unsafeSkipped.push(relativePath);
@@ -17,9 +17,11 @@ import { installNativeDecisionBinary, patchInstalledMachineOwnedIntegrity } from
17
17
  import { printError } from "./output.js";
18
18
  import { compareVersions } from "./version.js";
19
19
  import { confirmAgentsTakeover, takeoverExistingAgents } from "./agents.js";
20
+ import { ensureCodexHooks, resolveCodexHooksPreference } from "./codex-hooks.js";
20
21
 
21
22
  export async function runFreshInstall(ctx) {
22
23
  await confirmAgentsTakeover(ctx);
24
+ await resolveCodexHooksPreference(ctx);
23
25
 
24
26
  for (const sourcePath of walk(ctx.templateRoot)) {
25
27
  copyTemplateFile(ctx, sourcePath);
@@ -35,7 +37,7 @@ export async function runFreshInstall(ctx) {
35
37
  ensureLocalOnlySourceControlBoundary(ctx);
36
38
  }
37
39
 
38
- export function runExistingInstall(ctx, existingInstall) {
40
+ export async function runExistingInstall(ctx, existingInstall) {
39
41
  const comparison = compareVersions(ctx, existingInstall.version, ctx.packageVersion);
40
42
 
41
43
  if (comparison > 0) {
@@ -52,10 +54,10 @@ export function runExistingInstall(ctx, existingInstall) {
52
54
  }
53
55
 
54
56
  ensureArchiveDirectory(ctx);
55
- runRepair(ctx, existingInstall.version, { fromVersion: existingInstall.version });
57
+ await runRepair(ctx, existingInstall.version, { fromVersion: existingInstall.version });
56
58
  } else {
57
59
  ensureArchiveDirectory(ctx);
58
- runRepair(ctx, existingInstall.version);
60
+ await runRepair(ctx, existingInstall.version);
59
61
  }
60
62
  }
61
63
 
@@ -68,11 +70,13 @@ function rejectUnsupportedHistoricalInstall(ctx, version) {
68
70
  process.exit(1);
69
71
  }
70
72
 
71
- function runRepair(ctx, version, options = {}) {
73
+ async function runRepair(ctx, version, options = {}) {
72
74
  ctx.summaryTitle = "NAOME harness checked";
75
+ await resolveCodexHooksPreference(ctx);
73
76
  ensureCoreHarnessFiles(ctx, `repair-${version}`);
74
77
  ensureTaskControlHarnessFiles(ctx, `repair-${version}`);
75
78
  ensureHarnessHealthFiles(ctx, `repair-${version}`);
79
+ ensureCodexHooks(ctx, `repair-${version}`);
76
80
  installNativeDecisionBinary(ctx);
77
81
  patchInstalledMachineOwnedIntegrity(ctx);
78
82
  ensureBuiltInVerificationChecks(ctx);
@@ -13,10 +13,14 @@ export {
13
13
  export function ensureCoreHarnessFiles(ctx, archiveDirName) {
14
14
  ensureNaomeIgnore(ctx);
15
15
  ensureTemplateFile(ctx, ".naome/verification.json");
16
+ ensureTemplateFile(ctx, ".naome/repository-model.json");
16
17
  replaceHarnessFile(ctx, "AGENTS.md", archiveDirName);
17
18
  replaceHarnessFile(ctx, "docs/naome/index.md", archiveDirName);
18
19
  replaceHarnessFile(ctx, "docs/naome/first-run.md", archiveDirName);
19
20
  replaceHarnessFile(ctx, "docs/naome/agent-workflow.md", archiveDirName);
21
+ replaceHarnessFile(ctx, "docs/naome/context-economy.md", archiveDirName);
22
+ replaceHarnessFile(ctx, "docs/naome/task-ledger.md", archiveDirName);
23
+ ensureTemplateFile(ctx, "docs/naome/repository-model.md");
20
24
  ensureTemplateFile(ctx, "docs/naome/security.md");
21
25
  replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
22
26
  }
@@ -33,6 +37,7 @@ export function ensureTaskControlHarnessFiles(ctx, archiveDirName) {
33
37
  replaceHarnessFile(ctx, "AGENTS.md", archiveDirName);
34
38
  replaceHarnessFile(ctx, "docs/naome/index.md", archiveDirName);
35
39
  replaceHarnessFile(ctx, "docs/naome/agent-workflow.md", archiveDirName);
40
+ replaceHarnessFile(ctx, "docs/naome/context-economy.md", archiveDirName);
36
41
  replaceHarnessFile(ctx, "docs/naome/execution.md", archiveDirName);
37
42
  replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
38
43
  }
@@ -49,6 +54,7 @@ export function ensureHarnessHealthFiles(ctx, archiveDirName) {
49
54
  replaceHarnessFile(ctx, "docs/naome/index.md", archiveDirName);
50
55
  replaceHarnessFile(ctx, "docs/naome/first-run.md", archiveDirName);
51
56
  replaceHarnessFile(ctx, "docs/naome/agent-workflow.md", archiveDirName);
57
+ replaceHarnessFile(ctx, "docs/naome/context-economy.md", archiveDirName);
52
58
  replaceHarnessFile(ctx, "docs/naome/execution.md", archiveDirName);
53
59
  ensureTemplateFile(ctx, "docs/naome/security.md");
54
60
  replaceHarnessFile(ctx, "docs/naome/upgrade.md", archiveDirName);
@@ -34,6 +34,9 @@ function parseInstallPlan(ctx, output) {
34
34
  assertInstallPlanArray(ctx, installPlan, "machineOwned");
35
35
  assertInstallPlanArray(ctx, installPlan, "projectOwned");
36
36
  assertInstallPlanArray(ctx, installPlan, "localOnlyMachineOwned");
37
+ if (installPlan.optionalCodexHookPaths !== undefined) {
38
+ assertInstallPlanArray(ctx, installPlan, "optionalCodexHookPaths");
39
+ }
37
40
  assertInstallPlanArray(ctx, installPlan, "gitignoreEntries");
38
41
  assertInstallPlanArray(ctx, installPlan, "gitExcludeEntries");
39
42
  assertInstallPlanArray(ctx, installPlan, "gitUntrackPaths");
@@ -60,6 +63,7 @@ function assignInstallPlan(ctx, installPlan) {
60
63
  ctx.machineOwnedPaths = installPlan.machineOwned;
61
64
  ctx.projectOwnedPaths = installPlan.projectOwned;
62
65
  ctx.localOnlyMachineOwnedPaths = installPlan.localOnlyMachineOwned;
66
+ ctx.optionalCodexHookPaths = installPlan.optionalCodexHookPaths ?? ctx.optionalCodexHookPaths;
63
67
  ctx.localOnlyGitIgnoreEntries = installPlan.gitignoreEntries;
64
68
  ctx.localOnlyGitExcludeEntries = installPlan.gitExcludeEntries;
65
69
  ctx.localOnlyGitUntrackPaths = installPlan.gitUntrackPaths;
package/installer/main.js CHANGED
@@ -14,7 +14,7 @@ export async function runNaomeNodeCli() {
14
14
  printHeader(ctx);
15
15
  const existingInstall = readExistingInstall(ctx);
16
16
  if (existingInstall) {
17
- runExistingInstall(ctx, existingInstall);
17
+ await runExistingInstall(ctx, existingInstall);
18
18
  } else {
19
19
  await runFreshInstall(ctx);
20
20
  }
@@ -62,8 +62,8 @@ export function findNativeDecisionBinary(ctx) {
62
62
  candidates.push(resolve(ctx.targetRoot, process.env.NAOME_NATIVE_BIN));
63
63
  }
64
64
 
65
- candidates.push(join(ctx.packageRoot, "native", `${process.platform}-${process.arch}`, ctx.nativeBinaryName));
66
65
  candidates.push(join(ctx.packageRoot, "target", "release", ctx.nativeBinaryName));
66
+ candidates.push(join(ctx.packageRoot, "native", `${process.platform}-${process.arch}`, ctx.nativeBinaryName));
67
67
 
68
68
  for (const candidate of candidates) {
69
69
  if (existsSync(candidate) && lstatSync(candidate).isFile()) {
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamentis/naome",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Native-first CLI for the NAOME agent harness.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -0,0 +1,2 @@
1
+ [features]
2
+ codex_hooks = true
@@ -0,0 +1,70 @@
1
+ {
2
+ "schema": "naome.codex-hooks.v1",
3
+ "version": 1,
4
+ "hooks": {
5
+ "SessionStart": [
6
+ {
7
+ "matcher": "startup|resume|clear",
8
+ "hooks": [
9
+ {
10
+ "type": "command",
11
+ "command": "node .naome/bin/codex-hook.js --event SessionStart"
12
+ }
13
+ ]
14
+ }
15
+ ],
16
+ "UserPromptSubmit": [
17
+ {
18
+ "hooks": [
19
+ {
20
+ "type": "command",
21
+ "command": "node .naome/bin/codex-hook.js --event UserPromptSubmit"
22
+ }
23
+ ]
24
+ }
25
+ ],
26
+ "PreToolUse": [
27
+ {
28
+ "matcher": "*",
29
+ "hooks": [
30
+ {
31
+ "type": "command",
32
+ "command": "node .naome/bin/codex-hook.js --event PreToolUse"
33
+ }
34
+ ]
35
+ }
36
+ ],
37
+ "PermissionRequest": [
38
+ {
39
+ "matcher": "*",
40
+ "hooks": [
41
+ {
42
+ "type": "command",
43
+ "command": "node .naome/bin/codex-hook.js --event PermissionRequest"
44
+ }
45
+ ]
46
+ }
47
+ ],
48
+ "PostToolUse": [
49
+ {
50
+ "matcher": "*",
51
+ "hooks": [
52
+ {
53
+ "type": "command",
54
+ "command": "node .naome/bin/codex-hook.js --event PostToolUse"
55
+ }
56
+ ]
57
+ }
58
+ ],
59
+ "Stop": [
60
+ {
61
+ "hooks": [
62
+ {
63
+ "type": "command",
64
+ "command": "node .naome/bin/codex-hook.js --event Stop"
65
+ }
66
+ ]
67
+ }
68
+ ]
69
+ }
70
+ }
@@ -10,15 +10,17 @@ const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
10
10
 
11
11
  const expectedMachineOwnedIntegrity = Object.freeze({
12
12
  ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
13
- ".naome/bin/check-task-state.js": "sha256:43c02868072d0d13499aefba2e9a5ec9517d59539fd19ff0f11e3e4623a51b44",
14
- ".naome/bin/naome.js": "sha256:3d2edd9cf7b04ffb8845db2c55ce1b9c243bd3aba112f53af4af3c11fae5b8e1",
13
+ ".naome/bin/check-task-state.js": "sha256:df54489a22b426180266e5e0fb5f9ec381477419f688435248afbf2b9b38ea81",
14
+ ".naome/bin/naome.js": "sha256:d343f367da21bf45272331eec2ea34862a0bf056978780c62d6cae02e0f7993a",
15
15
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
16
16
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
- "AGENTS.md": "sha256:9192ea81f90bb19f8043513c49b5da9e9598ee694da8356f345e7ccbca0e28df",
18
- "docs/naome/agent-workflow.md": "sha256:97788255e26282ca1b7fcaaf86c9408c9040246727e3de96b4126fcb68c10b38",
17
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
18
+ "docs/naome/agent-workflow.md": "sha256:78faeb4eed157b60f0b60bc43da36c713fc4a3436b93bd963ce5f3c12dc91f22",
19
+ "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
19
20
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
20
- "docs/naome/first-run.md": "sha256:a1dd0bd17ec9d71955a473cd2c4a615538e89a7d81e8f4e1015a50ab9efe3558",
21
- "docs/naome/index.md": "sha256:a674102cc801702dc77102afb59be0f5ab189dc638caf0bef358b9d6087d0742",
21
+ "docs/naome/first-run.md": "sha256:f1a2412f1b542e61c79b5ba65a3fdaa810b0f95cf79d9f734256418cdcfb19aa",
22
+ "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
23
+ "docs/naome/task-ledger.md": "sha256:1e524085a2f88811941fd9f2f48ca826bc3e0e4816039d07e795637847714cbd",
22
24
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
23
25
  });
24
26
 
@@ -10,15 +10,17 @@ const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
10
10
 
11
11
  const expectedMachineOwnedIntegrity = Object.freeze({
12
12
  ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
13
- ".naome/bin/check-task-state.js": "sha256:43c02868072d0d13499aefba2e9a5ec9517d59539fd19ff0f11e3e4623a51b44",
14
- ".naome/bin/naome.js": "sha256:3d2edd9cf7b04ffb8845db2c55ce1b9c243bd3aba112f53af4af3c11fae5b8e1",
13
+ ".naome/bin/check-task-state.js": "sha256:df54489a22b426180266e5e0fb5f9ec381477419f688435248afbf2b9b38ea81",
14
+ ".naome/bin/naome.js": "sha256:d343f367da21bf45272331eec2ea34862a0bf056978780c62d6cae02e0f7993a",
15
15
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
16
16
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
- "AGENTS.md": "sha256:9192ea81f90bb19f8043513c49b5da9e9598ee694da8356f345e7ccbca0e28df",
18
- "docs/naome/agent-workflow.md": "sha256:97788255e26282ca1b7fcaaf86c9408c9040246727e3de96b4126fcb68c10b38",
17
+ "AGENTS.md": "sha256:e8b2fc786c1c72b69ba8f2b2ffce4f459e799c7453ce9ff4a9f6448a8f9e6b4f",
18
+ "docs/naome/agent-workflow.md": "sha256:78faeb4eed157b60f0b60bc43da36c713fc4a3436b93bd963ce5f3c12dc91f22",
19
+ "docs/naome/context-economy.md": "sha256:3ed5075815ecf4ada46a5e65438769310307c35759fcd46b13dc0b96e02bebd9",
19
20
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
20
- "docs/naome/first-run.md": "sha256:a1dd0bd17ec9d71955a473cd2c4a615538e89a7d81e8f4e1015a50ab9efe3558",
21
- "docs/naome/index.md": "sha256:a674102cc801702dc77102afb59be0f5ab189dc638caf0bef358b9d6087d0742",
21
+ "docs/naome/first-run.md": "sha256:f1a2412f1b542e61c79b5ba65a3fdaa810b0f95cf79d9f734256418cdcfb19aa",
22
+ "docs/naome/index.md": "sha256:07ef776f49130319a5280bdb3ae38af22141708253f38eb983a4336fbae1b25a",
23
+ "docs/naome/task-ledger.md": "sha256:1e524085a2f88811941fd9f2f48ca826bc3e0e4816039d07e795637847714cbd",
22
24
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
23
25
  });
24
26
 
@@ -154,7 +156,10 @@ function findHarnessRoot(startPath) {
154
156
  let current = resolve(startPath);
155
157
 
156
158
  while (true) {
157
- if (existsSync(join(current, ".naome", "task-state.json"))) {
159
+ if (
160
+ existsSync(join(current, ".naome", "task-state.json")) ||
161
+ existsSync(join(current, ".naome", "tasks", "active.json"))
162
+ ) {
158
163
  return current;
159
164
  }
160
165
 
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+
3
+ const { createHash } = require("node:crypto");
4
+ const { existsSync, mkdirSync, readFileSync, writeFileSync } = require("node:fs");
5
+ const { dirname } = require("node:path");
6
+ const { spawnSync } = require("node:child_process");
7
+
8
+ const CACHE = ".naome/cache/codex-hook-state.json";
9
+
10
+ function readPayload() {
11
+ try {
12
+ return JSON.parse(readFileSync(0, "utf8") || "{}");
13
+ } catch {
14
+ return {};
15
+ }
16
+ }
17
+
18
+ function eventName(payload) {
19
+ const index = process.argv.indexOf("--event");
20
+ return index !== -1 && process.argv[index + 1] ? process.argv[index + 1] : payload?.hook_event_name || payload?.event || "";
21
+ }
22
+
23
+ function commandOf(payload) {
24
+ return [payload?.tool_input?.command, payload?.toolInput?.command, payload?.command].find((value) => typeof value === "string" && value);
25
+ }
26
+
27
+ function promptOf(payload) {
28
+ return [payload?.prompt, payload?.user_prompt, payload?.tool_input?.prompt, payload?.toolInput?.prompt, payload?.reason, payload?.message].find((value) => typeof value === "string" && value) || "";
29
+ }
30
+
31
+ function readJson(path) {
32
+ try {
33
+ return existsSync(path) ? JSON.parse(readFileSync(path, "utf8")) : null;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ function parseJson(value) {
40
+ try {
41
+ return JSON.parse(value);
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+
47
+ function readCache() {
48
+ return readJson(CACHE) || {};
49
+ }
50
+
51
+ function writeCache(value) {
52
+ try {
53
+ mkdirSync(dirname(CACHE), { recursive: true });
54
+ writeFileSync(CACHE, `${JSON.stringify(value)}\n`);
55
+ } catch {
56
+ // Best-effort cache only.
57
+ }
58
+ }
59
+
60
+ function run(command, args, env = process.env) {
61
+ return spawnSync(command, args, { cwd: process.cwd(), encoding: "utf8", env });
62
+ }
63
+
64
+ function runGit(args) {
65
+ return run("git", args);
66
+ }
67
+
68
+ function runNaome(args) {
69
+ return run(process.execPath, [".naome/bin/naome.js", ...args], { ...process.env, NO_COLOR: "1" });
70
+ }
71
+
72
+ function taskCheck(args) {
73
+ return run(process.execPath, [".naome/bin/check-task-state.js", ...args]);
74
+ }
75
+
76
+ function diffSignature() {
77
+ return createHash("sha256")
78
+ .update(runGit(["status", "--porcelain=v1"]).stdout || "")
79
+ .update(runGit(["diff", "--no-ext-diff", "HEAD", "--"]).stdout || "")
80
+ .digest("hex");
81
+ }
82
+
83
+ function decide(decision, reason, messages) {
84
+ write(decisionObject(decision, reason, messages));
85
+ }
86
+
87
+ function decisionObject(decision, reason, messages) {
88
+ if (decision !== "block") {
89
+ return {};
90
+ }
91
+ const detail = messages.filter(Boolean).join("; ");
92
+ return { decision, reason: compact(detail ? `${reason}: ${detail}` : reason) };
93
+ }
94
+
95
+ function write(value) {
96
+ process.stdout.write(`${JSON.stringify(value)}\n`);
97
+ }
98
+
99
+ function compact(value) {
100
+ const text = String(value);
101
+ return text.length > 500 ? `${text.slice(0, 497)}...` : text;
102
+ }
103
+
104
+ module.exports = {
105
+ commandOf,
106
+ compact,
107
+ decide,
108
+ decisionObject,
109
+ diffSignature,
110
+ eventName,
111
+ parseJson,
112
+ promptOf,
113
+ readCache,
114
+ readJson,
115
+ readPayload,
116
+ run,
117
+ runGit,
118
+ runNaome,
119
+ taskCheck,
120
+ write,
121
+ writeCache
122
+ };
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+
3
+ const { readFileSync } = require("node:fs");
4
+
5
+ const CHEAP = new Set(["diff-check", "repository-quality-check", "repository-semantic-check", "task-state-progress-check"]);
6
+ const EXPENSIVE = new Set(["installer-tests", "rust-build", "package-dry-run", "harness-health-tests", "task-state-tests", "verification-contract-tests"]);
7
+
8
+ function classifyPrompt(prompt) {
9
+ const value = prompt.toLowerCase();
10
+ if (/status|where are we|progress/.test(value)) return "status_request";
11
+ if (/review|comment|pr feedback/.test(value)) return "review";
12
+ if (/commit/.test(value)) return "commit";
13
+ if (/push/.test(value) && !/ci|check|fail/.test(value)) return "push";
14
+ if (/ci|check|failing|failed|workflow|actions/.test(value)) return "ci_fix";
15
+ if (/continue|keep going|resume|do so/.test(value)) return "continuation";
16
+ return "new_task";
17
+ }
18
+
19
+ function riskyPromptCodes(prompt) {
20
+ const value = prompt.toLowerCase();
21
+ return [
22
+ ["reset|clean|rm\\s+-rf", "risky-destructive"],
23
+ ["force push|--force|--force-with-lease|\\spush\\s+-f", "risky-force-push"],
24
+ ["--no-verify|bypass.*hook|skip.*hook", "risky-hook-bypass"],
25
+ ["publish|release|npm publish", "risky-release"]
26
+ ].filter(([pattern]) => new RegExp(pattern).test(value)).map(([, code]) => code);
27
+ }
28
+
29
+ function permissionRiskCodes(value) {
30
+ const lower = value.toLowerCase();
31
+ return [...new Set([
32
+ ["https?:|network|fetch|curl|wget|push|pull|gh\\s+|npm\\s+(install|publish)", "network"],
33
+ ["\\bgit\\b|push|commit|merge|rebase", "git"],
34
+ ["write|stage|commit|push|apply|patch|install|sync", "write"],
35
+ ["publish|npm publish", "publish"],
36
+ ["release|tag", "release"],
37
+ ["reset|clean|--force|-f\\b|rm\\s+-rf", "destructive"]
38
+ ].filter(([pattern]) => new RegExp(pattern).test(lower)).map(([, code]) => code))];
39
+ }
40
+
41
+ function hardBlockedCommand(command) {
42
+ const value = command.replace(/\s+/g, " ").trim();
43
+ return [
44
+ [/(\bgit\s+reset\b.*\B--hard\b|\bgit\s+reset\s+--hard\b)/, "destructive-git-reset-hard: hard reset requires explicit human review."],
45
+ [/\bgit\s+clean\b.*(^|\s)-[^\s]*f|\bgit\s+clean\b.*--force\b/, "destructive-git-clean: forced clean requires explicit human review."],
46
+ [/\brm\b(?=.*(?:^|\s)-[^\s]*r)(?=.*(?:^|\s)-[^\s]*f)(?=.*(?:^|\s)(?:--\s+)?(?:\.\/)?(?:[^/\s]+\/)*\.git(?:\/|\s|$))/, "destructive-git-dir-removal: removing .git is blocked."],
47
+ [/--no-verify\b/, "hook-bypass-command: --no-verify is blocked."],
48
+ [/\bgit\s+push\b.*(?:--force(?:-with-lease)?\b|(^|\s)-f(\s|$))/, "force-push-command: force pushes require fresh human review."]
49
+ ].find(([pattern]) => pattern.test(value))?.[1] || null;
50
+ }
51
+
52
+ function searchSegments(command) {
53
+ return command
54
+ .split(/&&|\|\||[;|]/)
55
+ .map((part) => part.trim().replace(/^(?:cd\s+\S+\s+)?/, ""))
56
+ .filter((part) => /^(rg|grep|find)\b/.test(part));
57
+ }
58
+
59
+ function forbiddenPath(payload, command) {
60
+ const input = payload?.tool_input || payload?.toolInput || {};
61
+ const values = [command, ...["path", "file_path", "filepath", "target_file", "pattern"].map((key) => input[key])].filter(Boolean);
62
+ return values.some((value) => tokens(value).some(blockedPath)) ? "read-boundary-violation: command or tool input touches a path blocked by .naomeignore." : null;
63
+ }
64
+
65
+ function blockedPath(path) {
66
+ if (/(^|\/)\.naome\/archive(\/|$)/.test(path)) return true;
67
+ return ignoredPatterns().some((pattern) => pathMatches(path, pattern));
68
+ }
69
+
70
+ function tokens(value) {
71
+ return String(value).replace(/\\/g, "/").split(/[\s"'`,]+/).map((token) => token.replace(/^\.\//, "").replace(/[):;]+$/, "")).filter(Boolean);
72
+ }
73
+
74
+ function ignoredPatterns() {
75
+ try {
76
+ return readFileSync(".naomeignore", "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
77
+ } catch {
78
+ return [".naome/archive/"];
79
+ }
80
+ }
81
+
82
+ function pathMatches(path, pattern) {
83
+ const actual = String(path).replace(/\\/g, "/");
84
+ const glob = String(pattern).replace(/\\/g, "/");
85
+ if (glob.endsWith("/")) return actual.startsWith(glob);
86
+ if (glob.endsWith("/**")) return actual.startsWith(glob.slice(0, -3));
87
+ if (!glob.includes("*")) return actual === glob;
88
+ return new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*")}$`).test(actual);
89
+ }
90
+
91
+ function looksLikeWriteTool(payload, command) {
92
+ const name = String(payload?.tool_name || payload?.toolName || payload?.name || "").toLowerCase();
93
+ if (/edit|write|patch|notebookedit|multiedit/.test(name)) return true;
94
+ if (!command) return false;
95
+ if (/^(git status|git diff|rg\b|grep\b|find\b|sed\b|cat\b|nl\b|wc\b|ls\b|pwd\b)/.test(command.trim())) return false;
96
+ return />|>>|\b(apply_patch|cp|mv|touch|mkdir|rm|npm install|cargo build|node --test|writeFileSync)\b/.test(command);
97
+ }
98
+
99
+ function touchedPaths(payload, command) {
100
+ const paths = [];
101
+ collectInputPaths(payload?.tool_input || payload?.toolInput || {}, paths);
102
+ collectCommandPaths(command, paths);
103
+ return [...new Set(paths.map(cleanPath).filter(Boolean))];
104
+ }
105
+
106
+ function collectInputPaths(value, paths) {
107
+ if (Array.isArray(value)) return value.forEach((entry) => collectInputPaths(entry, paths));
108
+ if (!value || typeof value !== "object") return;
109
+ for (const [key, child] of Object.entries(value)) {
110
+ if (/^(path|paths|file|files|file_path|filepath|target_file)$/.test(key)) collectPathValue(child, paths);
111
+ if (child && typeof child === "object") collectInputPaths(child, paths);
112
+ }
113
+ }
114
+
115
+ function collectPathValue(value, paths) {
116
+ if (Array.isArray(value)) return value.forEach((entry) => collectPathValue(entry, paths));
117
+ if (typeof value === "string") paths.push(value);
118
+ }
119
+
120
+ function collectCommandPaths(command, paths) {
121
+ if (!command) return;
122
+ for (const segment of command.split(/&&|\|\||[;]/).map((part) => part.trim())) {
123
+ const parts = tokens(segment);
124
+ if (/^(touch|mkdir|rm)$/.test(parts[0])) paths.push(...parts.slice(1).filter((part) => !part.startsWith("-")));
125
+ if (/^(cp|mv)$/.test(parts[0])) paths.push(...parts.slice(1).filter((part) => !part.startsWith("-")).slice(-1));
126
+ }
127
+ }
128
+
129
+ function cleanPath(path) {
130
+ return String(path).replace(/\\/g, "/").replace(/^\.\//, "").replace(/[):;]+$/, "");
131
+ }
132
+
133
+ function scopeDrift(paths, allowed) {
134
+ if (!Array.isArray(allowed)) return [];
135
+ return paths.filter((path) => !isControlStatePath(path) && !allowed.some((pattern) => pathMatches(path, pattern)));
136
+ }
137
+
138
+ function isControlStatePath(path) {
139
+ return path === ".naome/task-state.json" || path.startsWith(".naome/tasks/") || path.startsWith(".naome/cache/");
140
+ }
141
+
142
+ function owedProof(paths, verification) {
143
+ const checks = new Set();
144
+ for (const type of verification?.changeTypes || []) {
145
+ if (paths.some((path) => (type.paths || []).some((pattern) => pathMatches(path, pattern)))) {
146
+ for (const check of type.requiredChecks || []) if (!CHEAP.has(check)) checks.add(check);
147
+ }
148
+ }
149
+ return [...checks].sort();
150
+ }
151
+
152
+ function expensiveProof(checks) {
153
+ return checks.filter((check) => EXPENSIVE.has(check));
154
+ }
155
+
156
+ function pushUnique(codes, code, messages, message) {
157
+ if (!codes.includes(code)) codes.push(code);
158
+ if (!messages.includes(message)) messages.push(message);
159
+ }
160
+
161
+ function primaryReason(codes) {
162
+ if (codes.includes("scope-drift")) return "scope-drift";
163
+ if (codes.some((code) => code.endsWith("-failed"))) return "cheap-gate-failed";
164
+ return codes[0] || "naome-hook-warning";
165
+ }
166
+
167
+ module.exports = {
168
+ classifyPrompt,
169
+ expensiveProof,
170
+ forbiddenPath,
171
+ hardBlockedCommand,
172
+ looksLikeWriteTool,
173
+ owedProof,
174
+ permissionRiskCodes,
175
+ primaryReason,
176
+ pushUnique,
177
+ riskyPromptCodes,
178
+ scopeDrift,
179
+ searchSegments, touchedPaths
180
+ };