@lamentis/naome 1.2.0 → 1.2.1

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 (113) hide show
  1. package/Cargo.lock +2 -2
  2. package/bin/naome-node.js +2 -1579
  3. package/bin/naome.js +19 -5
  4. package/crates/naome-cli/Cargo.toml +1 -1
  5. package/crates/naome-cli/src/dispatcher.rs +2 -1
  6. package/crates/naome-cli/src/main.rs +3 -0
  7. package/crates/naome-cli/src/quality_commands.rs +90 -2
  8. package/crates/naome-core/Cargo.toml +1 -1
  9. package/crates/naome-core/src/decision/checks.rs +64 -0
  10. package/crates/naome-core/src/decision/idle.rs +67 -0
  11. package/crates/naome-core/src/decision/json.rs +36 -0
  12. package/crates/naome-core/src/decision/states.rs +165 -0
  13. package/crates/naome-core/src/decision.rs +131 -353
  14. package/crates/naome-core/src/install_plan.rs +2 -0
  15. package/crates/naome-core/src/lib.rs +5 -3
  16. package/crates/naome-core/src/paths.rs +3 -1
  17. package/crates/naome-core/src/quality/adapter_support.rs +89 -0
  18. package/crates/naome-core/src/quality/adapters.rs +20 -67
  19. package/crates/naome-core/src/quality/cleanup.rs +13 -1
  20. package/crates/naome-core/src/quality/config.rs +8 -15
  21. package/crates/naome-core/src/quality/config_support.rs +24 -0
  22. package/crates/naome-core/src/quality/mod.rs +18 -0
  23. package/crates/naome-core/src/quality/scanner.rs +20 -8
  24. package/crates/naome-core/src/quality/structure/adapters.rs +84 -0
  25. package/crates/naome-core/src/quality/structure/checks/basic.rs +153 -0
  26. package/crates/naome-core/src/quality/structure/checks/directory.rs +144 -0
  27. package/crates/naome-core/src/quality/structure/checks/pairing.rs +63 -0
  28. package/crates/naome-core/src/quality/structure/checks.rs +124 -0
  29. package/crates/naome-core/src/quality/structure/classify/roles.rs +188 -0
  30. package/crates/naome-core/src/quality/structure/classify.rs +94 -0
  31. package/crates/naome-core/src/quality/structure/config.rs +89 -0
  32. package/crates/naome-core/src/quality/structure/defaults.rs +107 -0
  33. package/crates/naome-core/src/quality/structure/mod.rs +77 -0
  34. package/crates/naome-core/src/quality/structure/model.rs +124 -0
  35. package/crates/naome-core/src/quality/types.rs +3 -0
  36. package/crates/naome-core/src/route/builtin_checks.rs +155 -0
  37. package/crates/naome-core/src/route/builtin_context.rs +73 -0
  38. package/crates/naome-core/src/route/builtin_integrity.rs +49 -0
  39. package/crates/naome-core/src/route/builtin_require.rs +40 -0
  40. package/crates/naome-core/src/route/context.rs +180 -0
  41. package/crates/naome-core/src/route/execution.rs +96 -0
  42. package/crates/naome-core/src/route/execution_baselines.rs +146 -0
  43. package/crates/naome-core/src/route/execution_support.rs +57 -0
  44. package/crates/naome-core/src/route/execution_tasks.rs +71 -0
  45. package/crates/naome-core/src/route/git_ops.rs +72 -0
  46. package/crates/naome-core/src/route/quality_gate.rs +73 -0
  47. package/crates/naome-core/src/route/quality_gate_config.rs +126 -0
  48. package/crates/naome-core/src/route/quality_gate_snapshot.rs +69 -0
  49. package/crates/naome-core/src/route/worktree.rs +75 -0
  50. package/crates/naome-core/src/route/worktree_files.rs +32 -0
  51. package/crates/naome-core/src/route/worktree_plan.rs +131 -0
  52. package/crates/naome-core/src/route.rs +44 -1217
  53. package/crates/naome-core/src/verification.rs +1 -0
  54. package/crates/naome-core/tests/decision.rs +24 -118
  55. package/crates/naome-core/tests/harness_health.rs +2 -0
  56. package/crates/naome-core/tests/quality.rs +12 -118
  57. package/crates/naome-core/tests/quality_structure.rs +116 -0
  58. package/crates/naome-core/tests/quality_structure_adapters.rs +98 -0
  59. package/crates/naome-core/tests/quality_structure_policy.rs +125 -0
  60. package/crates/naome-core/tests/quality_structure_support/mod.rs +249 -0
  61. package/crates/naome-core/tests/repo_support/mod.rs +16 -0
  62. package/crates/naome-core/tests/repo_support/repo.rs +113 -0
  63. package/crates/naome-core/tests/repo_support/repo_factories.rs +99 -0
  64. package/crates/naome-core/tests/repo_support/repo_helpers.rs +123 -0
  65. package/crates/naome-core/tests/repo_support/routes.rs +81 -0
  66. package/crates/naome-core/tests/repo_support/verification.rs +168 -0
  67. package/crates/naome-core/tests/repo_support/verification_values.rs +135 -0
  68. package/crates/naome-core/tests/route.rs +1 -1376
  69. package/crates/naome-core/tests/route_baseline.rs +86 -0
  70. package/crates/naome-core/tests/route_completion.rs +141 -0
  71. package/crates/naome-core/tests/route_harness_refresh.rs +135 -0
  72. package/crates/naome-core/tests/route_user_diff.rs +198 -0
  73. package/crates/naome-core/tests/route_worktree.rs +54 -0
  74. package/crates/naome-core/tests/task_state.rs +60 -432
  75. package/crates/naome-core/tests/task_state_compact_support/repo.rs +1 -1
  76. package/crates/naome-core/tests/task_state_support/mod.rs +163 -0
  77. package/crates/naome-core/tests/task_state_support/states.rs +84 -0
  78. package/crates/naome-core/tests/verification.rs +4 -45
  79. package/crates/naome-core/tests/verification_contract.rs +22 -78
  80. package/crates/naome-core/tests/workflow_support/mod.rs +1 -1
  81. package/installer/agents.js +90 -0
  82. package/installer/context.js +67 -0
  83. package/installer/filesystem.js +166 -0
  84. package/installer/flows.js +84 -0
  85. package/installer/git-boundary.js +170 -0
  86. package/installer/git-hook-content.js +36 -0
  87. package/installer/git-hooks.js +134 -0
  88. package/installer/git-local.js +2 -0
  89. package/installer/git-shared.js +35 -0
  90. package/installer/harness-file-ops.js +140 -0
  91. package/installer/harness-files.js +56 -0
  92. package/installer/harness-verification.js +123 -0
  93. package/installer/install-plan.js +66 -0
  94. package/installer/main.js +25 -0
  95. package/installer/manifest-state.js +167 -0
  96. package/installer/native-build.js +24 -0
  97. package/installer/native-format.js +6 -0
  98. package/installer/native.js +162 -0
  99. package/installer/output.js +131 -0
  100. package/installer/version.js +32 -0
  101. package/native/darwin-arm64/naome +0 -0
  102. package/native/linux-x64/naome +0 -0
  103. package/package.json +2 -1
  104. package/templates/naome-root/.naome/bin/check-harness-health.js +2 -2
  105. package/templates/naome-root/.naome/bin/check-task-state.js +2 -2
  106. package/templates/naome-root/.naome/bin/naome.js +25 -21
  107. package/templates/naome-root/.naome/manifest.json +4 -2
  108. package/templates/naome-root/.naome/repository-structure.json +90 -0
  109. package/templates/naome-root/.naome/verification.json +1 -0
  110. package/templates/naome-root/docs/naome/index.md +4 -3
  111. package/templates/naome-root/docs/naome/repository-quality.md +3 -0
  112. package/templates/naome-root/docs/naome/repository-structure.md +51 -0
  113. package/templates/naome-root/docs/naome/testing.md +2 -1
@@ -0,0 +1,162 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ chmodSync,
4
+ copyFileSync,
5
+ existsSync,
6
+ lstatSync,
7
+ mkdirSync,
8
+ readFileSync,
9
+ writeFileSync,
10
+ } from "node:fs";
11
+ import { dirname, join, resolve } from "node:path";
12
+
13
+ import { hasSymlinkInTargetPath } from "./filesystem.js";
14
+ import { buildNativeDecisionBinary } from "./native-build.js";
15
+ import { formatExpectedIntegrityBlock } from "./native-format.js";
16
+ import { printError } from "./output.js";
17
+
18
+ export function installNativeDecisionBinary(ctx) {
19
+ const targetPath = join(ctx.targetRoot, ctx.nativeBinaryRelativePath);
20
+
21
+ if (hasSymlinkInTargetPath(ctx, ctx.nativeBinaryRelativePath)) {
22
+ ctx.skipped.push(ctx.nativeBinaryRelativePath);
23
+ ctx.unsafeSkipped.push(ctx.nativeBinaryRelativePath);
24
+ return;
25
+ }
26
+
27
+ const sourcePath = findNativeDecisionBinary(ctx);
28
+ if (!sourcePath) {
29
+ printError(ctx, "NAOME native decision binary is unavailable.");
30
+ console.error("Install Cargo or provide NAOME_NATIVE_BIN with a built naome binary, then rerun naome sync.");
31
+ process.exit(1);
32
+ }
33
+
34
+ if (usesSourceNativeFallback(ctx)) {
35
+ patchNaomeCommandNativeIntegrity(ctx, "sha256:generated");
36
+ ctx.skipped.push(ctx.nativeBinaryRelativePath);
37
+ return;
38
+ }
39
+
40
+ mkdirSync(dirname(targetPath), { recursive: true });
41
+ const sourceHash = sha256(readFileSync(sourcePath));
42
+ const targetHash =
43
+ existsSync(targetPath) && lstatSync(targetPath).isFile()
44
+ ? sha256(readFileSync(targetPath))
45
+ : null;
46
+
47
+ if (sourceHash !== targetHash) {
48
+ copyFileSync(sourcePath, targetPath);
49
+ ctx.updated.push(ctx.nativeBinaryRelativePath);
50
+ } else {
51
+ ctx.skipped.push(ctx.nativeBinaryRelativePath);
52
+ }
53
+
54
+ chmodSync(targetPath, 0o755);
55
+ patchNaomeCommandNativeIntegrity(ctx, `sha256:${sourceHash}`);
56
+ }
57
+
58
+ export function findNativeDecisionBinary(ctx) {
59
+ const candidates = [];
60
+
61
+ if (process.env.NAOME_NATIVE_BIN) {
62
+ candidates.push(resolve(ctx.targetRoot, process.env.NAOME_NATIVE_BIN));
63
+ }
64
+
65
+ candidates.push(join(ctx.packageRoot, "native", `${process.platform}-${process.arch}`, ctx.nativeBinaryName));
66
+ candidates.push(join(ctx.packageRoot, "target", "release", ctx.nativeBinaryName));
67
+
68
+ for (const candidate of candidates) {
69
+ if (existsSync(candidate) && lstatSync(candidate).isFile()) {
70
+ return candidate;
71
+ }
72
+ }
73
+
74
+ return buildNativeDecisionBinary(ctx);
75
+ }
76
+
77
+ export function patchInstalledMachineOwnedIntegrity(ctx) {
78
+ const integrityBlock = formatExpectedIntegrityBlock(templateIntegrity(ctx));
79
+
80
+ for (const relativePath of [ctx.healthCheckerRelativePath, ctx.taskStateCheckerRelativePath]) {
81
+ const targetPath = join(ctx.targetRoot, relativePath);
82
+ if (!existsSync(targetPath) || hasSymlinkInTargetPath(ctx, relativePath)) {
83
+ continue;
84
+ }
85
+
86
+ const content = readFileSync(targetPath, "utf8");
87
+ const nextContent = content.replace(ctx.integrityBlockPattern, integrityBlock);
88
+ if (nextContent !== content) {
89
+ writeFileSync(targetPath, nextContent);
90
+ ctx.updated.push(relativePath);
91
+ }
92
+ }
93
+ }
94
+
95
+ export function usesSourceNativeFallback(ctx) {
96
+ return existsSync(join(ctx.targetRoot, "packages", "naome", "Cargo.toml"))
97
+ && existsSync(join(ctx.targetRoot, "packages", "naome", "crates", "naome-cli", "src", "main.rs"));
98
+ }
99
+
100
+ export function installedNativeBinaryHash(ctx) {
101
+ const targetPath = join(ctx.targetRoot, ctx.nativeBinaryRelativePath);
102
+ if (
103
+ !existsSync(targetPath) ||
104
+ hasSymlinkInTargetPath(ctx, ctx.nativeBinaryRelativePath) ||
105
+ !lstatSync(targetPath).isFile()
106
+ ) {
107
+ return null;
108
+ }
109
+
110
+ return sha256(readFileSync(targetPath));
111
+ }
112
+
113
+ export function templateIntegrity(ctx) {
114
+ const integrity = {};
115
+
116
+ for (const relativePath of ctx.machineOwnedPaths) {
117
+ const sourcePath = join(ctx.templateRoot, relativePath);
118
+ integrity[relativePath] = `sha256:${machineFileHash(ctx, relativePath, readFileSync(sourcePath))}`;
119
+ }
120
+
121
+ return integrity;
122
+ }
123
+
124
+ export function sha256(content) {
125
+ return createHash("sha256").update(content).digest("hex");
126
+ }
127
+
128
+ export function machineFileHash(ctx, relativePath, content) {
129
+ let normalized = content;
130
+
131
+ if (hasGeneratedIntegrity(ctx, relativePath)) {
132
+ normalized = normalized.toString("utf8").replace(ctx.integrityBlockPattern, ctx.normalizedIntegrityBlock);
133
+ }
134
+
135
+ if (relativePath === ctx.naomeCommandRelativePath) {
136
+ normalized = normalized.toString("utf8").replace(ctx.nativeIntegrityPattern, ctx.normalizedNativeIntegrity);
137
+ }
138
+
139
+ return sha256(normalized);
140
+ }
141
+
142
+ export function hasGeneratedIntegrity(ctx, relativePath) {
143
+ return relativePath === ctx.healthCheckerRelativePath || relativePath === ctx.taskStateCheckerRelativePath;
144
+ }
145
+
146
+ function patchNaomeCommandNativeIntegrity(ctx, expectedIntegrity) {
147
+ const commandPath = join(ctx.targetRoot, ctx.naomeCommandRelativePath);
148
+ if (!existsSync(commandPath) || hasSymlinkInTargetPath(ctx, ctx.naomeCommandRelativePath)) {
149
+ return;
150
+ }
151
+
152
+ const content = readFileSync(commandPath, "utf8");
153
+ const nextContent = content.replace(
154
+ ctx.nativeIntegrityPattern,
155
+ `const expectedNativeBinaryIntegrity = "${expectedIntegrity}";\n`,
156
+ );
157
+
158
+ if (nextContent !== content) {
159
+ writeFileSync(commandPath, nextContent);
160
+ ctx.updated.push(ctx.naomeCommandRelativePath);
161
+ }
162
+ }
@@ -0,0 +1,131 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ export function printHeader(ctx) {
5
+ console.log("");
6
+ console.log(`${ctx.color.bold("NAOME")} ${ctx.color.dim(`v${ctx.packageVersion}`)}`);
7
+ console.log(ctx.color.dim("AI coding-agent harness installer"));
8
+ console.log("");
9
+ console.log(`${ctx.color.dim("target ")} ${ctx.targetRoot}`);
10
+ }
11
+
12
+ export function printSection(ctx, title) {
13
+ console.log("");
14
+ console.log(ctx.color.bold(title));
15
+ }
16
+
17
+ export function printList(ctx, items, marker) {
18
+ for (const item of uniqueStrings(items)) {
19
+ console.log(`${ctx.color.dim(marker)} ${item}`);
20
+ }
21
+ }
22
+
23
+ export function uniqueStrings(items) {
24
+ return Array.from(new Set(items));
25
+ }
26
+
27
+ export function printError(ctx, message) {
28
+ console.error("");
29
+ console.error(`${ctx.color.red("x")} ${message}`);
30
+ }
31
+
32
+ export function printCancelled(ctx, message) {
33
+ console.log("");
34
+ console.log(`${ctx.color.yellow("-")} ${message}`);
35
+ }
36
+
37
+ export function printCommandFailure(ctx, message, result) {
38
+ printError(ctx, message);
39
+ if (result.stdout.trim()) {
40
+ console.error(result.stdout.trim());
41
+ }
42
+ if (result.stderr.trim()) {
43
+ console.error(result.stderr.trim());
44
+ }
45
+ process.exit(1);
46
+ }
47
+
48
+ export function printSummary(ctx, existingInstall) {
49
+ console.log("");
50
+ console.log(`${ctx.color.green("+")} ${ctx.summaryTitle}`);
51
+
52
+ const detailedOutput = shouldPrintDetailedSummary(ctx, existingInstall);
53
+ if (!detailedOutput) {
54
+ printCompactSummary(ctx);
55
+ }
56
+
57
+ printDetailedSummary(ctx, detailedOutput);
58
+ if (ctx.unsafeSkipped.length > 0) {
59
+ printSection(ctx, "Skipped unsafe symlinked paths");
60
+ printList(ctx, ctx.unsafeSkipped, "!");
61
+ }
62
+
63
+ if (isRepositoryInitialized(ctx)) {
64
+ console.log("");
65
+ return;
66
+ }
67
+
68
+ printSection(ctx, "Next step");
69
+ console.log("Copy this into your coding agent:");
70
+ console.log("");
71
+ console.log(ctx.color.dim("```"));
72
+ console.log(ctx.nextStepPrompt);
73
+ console.log(ctx.color.dim("```"));
74
+ console.log("");
75
+ }
76
+
77
+ function printDetailedSummary(ctx, detailedOutput) {
78
+ if (detailedOutput && ctx.installed.length > 0) {
79
+ const items = uniqueStrings(ctx.installed);
80
+ printSection(ctx, `Installed ${items.length} ${items.length === 1 ? "item" : "items"}`);
81
+ printList(ctx, ctx.installed, "+");
82
+ }
83
+
84
+ if (detailedOutput && ctx.updated.length > 0) {
85
+ const items = uniqueStrings(ctx.updated);
86
+ printSection(ctx, `Updated ${items.length} ${items.length === 1 ? "item" : "items"}`);
87
+ printList(ctx, ctx.updated, "~");
88
+ }
89
+
90
+ if (detailedOutput && ctx.archived.length > 0) {
91
+ printSection(ctx, "Archived");
92
+ for (const entry of ctx.archived) {
93
+ console.log(`${ctx.color.dim(">")} ${entry.from} -> ${entry.to}`);
94
+ }
95
+ }
96
+
97
+ if (detailedOutput && ctx.skipped.length > 0) {
98
+ const items = uniqueStrings(ctx.skipped);
99
+ printSection(ctx, `Skipped ${items.length} existing ${items.length === 1 ? "path" : "paths"}`);
100
+ printList(ctx, ctx.skipped, "-");
101
+ }
102
+ }
103
+
104
+ function shouldPrintDetailedSummary(ctx, existingInstall) {
105
+ return ctx.verboseOutput || !existingInstall;
106
+ }
107
+
108
+ function printCompactSummary(ctx) {
109
+ const installedCount = uniqueStrings(ctx.installed).length;
110
+ const updatedCount = uniqueStrings(ctx.updated).length;
111
+ const archivedCount = ctx.archived.length;
112
+
113
+ if (installedCount > 0) {
114
+ console.log(`${ctx.color.dim("installed")} ${installedCount}`);
115
+ }
116
+ if (updatedCount > 0) {
117
+ console.log(`${ctx.color.dim("updated")} ${updatedCount}`);
118
+ }
119
+ if (archivedCount > 0) {
120
+ console.log(`${ctx.color.dim("archived")} ${archivedCount}`);
121
+ }
122
+ }
123
+
124
+ function isRepositoryInitialized(ctx) {
125
+ try {
126
+ const initState = JSON.parse(readFileSync(join(ctx.targetRoot, ".naome", "init-state.json"), "utf8"));
127
+ return initState.initialized === true;
128
+ } catch {
129
+ return false;
130
+ }
131
+ }
@@ -0,0 +1,32 @@
1
+ import { printError } from "./output.js";
2
+
3
+ export function compareVersions(ctx, left, right) {
4
+ const leftParts = parseVersion(ctx, left);
5
+ const rightParts = parseVersion(ctx, right);
6
+
7
+ for (let index = 0; index < 3; index += 1) {
8
+ if (leftParts[index] > rightParts[index]) {
9
+ return 1;
10
+ }
11
+
12
+ if (leftParts[index] < rightParts[index]) {
13
+ return -1;
14
+ }
15
+ }
16
+
17
+ return 0;
18
+ }
19
+
20
+ export function isVersion(version) {
21
+ return typeof version === "string" && /^\d+\.\d+\.\d+$/.test(version);
22
+ }
23
+
24
+ function parseVersion(ctx, version) {
25
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
26
+ if (!match) {
27
+ printError(ctx, `Invalid NAOME version: ${version}`);
28
+ process.exit(1);
29
+ }
30
+
31
+ return match.slice(1).map((part) => Number.parseInt(part, 10));
32
+ }
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamentis/naome",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Native-first CLI for the NAOME agent harness.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -31,6 +31,7 @@
31
31
  "Cargo.lock",
32
32
  "Cargo.toml",
33
33
  "crates",
34
+ "installer",
34
35
  "native",
35
36
  "templates",
36
37
  "README.md"
@@ -11,14 +11,14 @@ const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
11
11
  const expectedMachineOwnedIntegrity = Object.freeze({
12
12
  ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
13
13
  ".naome/bin/check-task-state.js": "sha256:43c02868072d0d13499aefba2e9a5ec9517d59539fd19ff0f11e3e4623a51b44",
14
- ".naome/bin/naome.js": "sha256:5675f729be6da3cbda1d8b9e0b36821cc98409aae95dff0603ed9161a5eb3b38",
14
+ ".naome/bin/naome.js": "sha256:87eabd690bf55f0b0195446db46fa7c19bfa17395d31c2f34a9ef9339d2229e2",
15
15
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
16
16
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
17
  "AGENTS.md": "sha256:9192ea81f90bb19f8043513c49b5da9e9598ee694da8356f345e7ccbca0e28df",
18
18
  "docs/naome/agent-workflow.md": "sha256:802eb34cf268fc9c5e7aefc28192efef4bf60302d30b3f78e5a61b876ce8a098",
19
19
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
20
20
  "docs/naome/first-run.md": "sha256:a1dd0bd17ec9d71955a473cd2c4a615538e89a7d81e8f4e1015a50ab9efe3558",
21
- "docs/naome/index.md": "sha256:7d917f1fa368874653bb458384bd9d0b221529e19644028a3143db3d3c144213",
21
+ "docs/naome/index.md": "sha256:a674102cc801702dc77102afb59be0f5ab189dc638caf0bef358b9d6087d0742",
22
22
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
23
23
  });
24
24
 
@@ -11,14 +11,14 @@ const nativeBinaryName = process.platform === "win32" ? "naome.exe" : "naome";
11
11
  const expectedMachineOwnedIntegrity = Object.freeze({
12
12
  ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
13
13
  ".naome/bin/check-task-state.js": "sha256:43c02868072d0d13499aefba2e9a5ec9517d59539fd19ff0f11e3e4623a51b44",
14
- ".naome/bin/naome.js": "sha256:5675f729be6da3cbda1d8b9e0b36821cc98409aae95dff0603ed9161a5eb3b38",
14
+ ".naome/bin/naome.js": "sha256:87eabd690bf55f0b0195446db46fa7c19bfa17395d31c2f34a9ef9339d2229e2",
15
15
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
16
16
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
17
17
  "AGENTS.md": "sha256:9192ea81f90bb19f8043513c49b5da9e9598ee694da8356f345e7ccbca0e28df",
18
18
  "docs/naome/agent-workflow.md": "sha256:802eb34cf268fc9c5e7aefc28192efef4bf60302d30b3f78e5a61b876ce8a098",
19
19
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
20
20
  "docs/naome/first-run.md": "sha256:a1dd0bd17ec9d71955a473cd2c4a615538e89a7d81e8f4e1015a50ab9efe3558",
21
- "docs/naome/index.md": "sha256:7d917f1fa368874653bb458384bd9d0b221529e19644028a3143db3d3c144213",
21
+ "docs/naome/index.md": "sha256:a674102cc801702dc77102afb59be0f5ab189dc638caf0bef358b9d6087d0742",
22
22
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
23
23
  });
24
24
 
@@ -27,7 +27,7 @@ function main(argv) {
27
27
  return;
28
28
  }
29
29
 
30
- if (["status", "next", "intent", "route", "explain", "quality", "cleanup", "refresh-integrity", "workflow"].includes(command)) {
30
+ if (["status", "next", "intent", "route", "explain", "quality", "structure", "cleanup", "refresh-integrity", "workflow"].includes(command)) {
31
31
  runNativeDecisionCommand(command, args);
32
32
  return;
33
33
  }
@@ -349,26 +349,30 @@ function findAncestorWithMarker(startPath, markerParts) {
349
349
  }
350
350
 
351
351
  function printHelp() {
352
- console.log("Usage:");
353
- console.log(" naome status [--json]");
354
- console.log(" naome next [--json]");
355
- console.log(" naome intent --prompt-file <path> [--json]");
356
- console.log(" naome intent --prompt <text> [--json]");
357
- console.log(" naome route --prompt-file <path> [--execute] [--json]");
358
- console.log(" naome route --prompt <text> [--execute] [--json]");
359
- console.log(" naome explain --prompt-file <path> [--json]");
360
- console.log(" naome explain --prompt <text> [--json]");
361
- console.log(" naome quality init [--json]");
362
- console.log(" naome quality check --changed [--json]");
363
- console.log(" naome quality report [--json]");
364
- console.log(" naome cleanup plan [--json]");
365
- console.log(" naome cleanup route --path <path> [--json]");
366
- console.log(" naome refresh-integrity [--json]");
367
- console.log(" naome workflow search-profile|check-search|phases|processes|mutations [--json]");
368
- console.log(" naome install");
369
- console.log(" naome sync");
370
- console.log(" naome commit -m \"type(scope): message\"");
371
- console.log(" node .naome/bin/naome.js commit -m \"type(scope): message\"");
352
+ const commands = [
353
+ "naome status [--json]",
354
+ "naome next [--json]",
355
+ "naome intent --prompt-file <path> [--json]",
356
+ "naome intent --prompt <text> [--json]",
357
+ "naome route --prompt-file <path> [--execute] [--json]",
358
+ "naome route --prompt <text> [--execute] [--json]",
359
+ "naome explain --prompt-file <path> [--json]",
360
+ "naome explain --prompt <text> [--json]",
361
+ "naome quality init [--json]",
362
+ "naome quality check --changed [--json]",
363
+ "naome quality report [--json]",
364
+ "naome structure report [--json]",
365
+ "naome structure explain --path <path> [--json]",
366
+ "naome cleanup plan [--json]",
367
+ "naome cleanup route --path <path> [--json]",
368
+ "naome refresh-integrity [--json]",
369
+ "naome workflow search-profile|check-search|phases|processes|mutations [--json]",
370
+ "naome install",
371
+ "naome sync",
372
+ "naome commit -m \"type(scope): message\"",
373
+ "node .naome/bin/naome.js commit -m \"type(scope): message\""
374
+ ];
375
+ console.log(["Usage:", ...commands.map((command) => ` ${command}`)].join("\n"));
372
376
  }
373
377
 
374
378
  function fail(message) {
@@ -4,14 +4,14 @@
4
4
  "integrity": {
5
5
  ".naome/bin/check-harness-health.js": "sha256:dc4de52b79c69600b9ba47b924e2c2b8de61a2cbfab6d1ccc0f1924d963db657",
6
6
  ".naome/bin/check-task-state.js": "sha256:43c02868072d0d13499aefba2e9a5ec9517d59539fd19ff0f11e3e4623a51b44",
7
- ".naome/bin/naome.js": "sha256:5675f729be6da3cbda1d8b9e0b36821cc98409aae95dff0603ed9161a5eb3b38",
7
+ ".naome/bin/naome.js": "sha256:87eabd690bf55f0b0195446db46fa7c19bfa17395d31c2f34a9ef9339d2229e2",
8
8
  ".naome/package.json": "sha256:8005a3491db7d92f36ac66369861589f9c47123d3a7c71e643fc2c06168cd45a",
9
9
  ".naome/task-contract.schema.json": "sha256:1b3b62350328d0d6d660e36d1d1baaa2b88718530db774f9ab2a9e2fcba369c8",
10
10
  "AGENTS.md": "sha256:9192ea81f90bb19f8043513c49b5da9e9598ee694da8356f345e7ccbca0e28df",
11
11
  "docs/naome/agent-workflow.md": "sha256:802eb34cf268fc9c5e7aefc28192efef4bf60302d30b3f78e5a61b876ce8a098",
12
12
  "docs/naome/execution.md": "sha256:bfc5d55838942ec8e3d790b59e3c634ff5bf6a2298265cef3dca9788a097eafb",
13
13
  "docs/naome/first-run.md": "sha256:a1dd0bd17ec9d71955a473cd2c4a615538e89a7d81e8f4e1015a50ab9efe3558",
14
- "docs/naome/index.md": "sha256:7d917f1fa368874653bb458384bd9d0b221529e19644028a3143db3d3c144213",
14
+ "docs/naome/index.md": "sha256:a674102cc801702dc77102afb59be0f5ab189dc638caf0bef358b9d6087d0742",
15
15
  "docs/naome/upgrade.md": "sha256:2c60f0441bbd98bd528d109b30a7ded4b0ad55d61ffb9f52edac9e93b7999cb1"
16
16
  },
17
17
  "machineOwned": [
@@ -37,11 +37,13 @@
37
37
  ".naome/upgrade-state.json",
38
38
  ".naome/verification.json",
39
39
  ".naome/repository-quality.json",
40
+ ".naome/repository-structure.json",
40
41
  ".naome/repository-quality-baseline.json",
41
42
  "docs/naome/architecture.md",
42
43
  "docs/naome/decisions.md",
43
44
  "docs/naome/repo-profile.md",
44
45
  "docs/naome/repository-quality.md",
46
+ "docs/naome/repository-structure.md",
45
47
  "docs/naome/security.md",
46
48
  "docs/naome/testing.md"
47
49
  ]
@@ -0,0 +1,90 @@
1
+ {
2
+ "schema": "naome.repository-structure.v1",
3
+ "version": 1,
4
+ "status": "ready",
5
+ "enabledAdapters": [],
6
+ "sourceRoots": [
7
+ "src/**",
8
+ "app/**",
9
+ "apps/*/src/**",
10
+ "packages/*/src/**",
11
+ "crates/*/src/**",
12
+ "**/src/**",
13
+ "lib/**"
14
+ ],
15
+ "testRoots": [
16
+ "test/**",
17
+ "tests/**",
18
+ "__tests__/**",
19
+ "packages/*/test/**",
20
+ "packages/*/tests/**",
21
+ "crates/*/tests/**",
22
+ "**/tests/**",
23
+ "scripts/*.test.js"
24
+ ],
25
+ "docsRoots": [
26
+ "docs/**",
27
+ "doc/**"
28
+ ],
29
+ "generatedRoots": [
30
+ "**/generated/**",
31
+ "**/__generated__/**",
32
+ "**/codegen/**",
33
+ "**/*.generated.*"
34
+ ],
35
+ "artifactRoots": [
36
+ "dist/**",
37
+ "build/**",
38
+ "coverage/**",
39
+ ".next/**",
40
+ "target/**",
41
+ "**/dist/**",
42
+ "**/build/**"
43
+ ],
44
+ "moduleRoots": [
45
+ "src/**",
46
+ "app/**",
47
+ "packages/*/src/**",
48
+ "crates/*/src/**",
49
+ "**/src/**"
50
+ ],
51
+ "allowedRootFiles": [
52
+ "README.md",
53
+ "LICENSE",
54
+ "NOTICE",
55
+ "CHANGELOG.md",
56
+ "CONTRIBUTING.md",
57
+ "SECURITY.md",
58
+ "AGENTS.md",
59
+ "package.json",
60
+ "Cargo.toml",
61
+ "pyproject.toml",
62
+ "go.mod",
63
+ "go.sum",
64
+ "Makefile",
65
+ ".gitignore",
66
+ ".naomeignore"
67
+ ],
68
+ "directoryRoleRules": [],
69
+ "layerRules": [],
70
+ "ignoredPaths": [
71
+ ".git/**",
72
+ "node_modules/**",
73
+ "vendor/**",
74
+ "target/**",
75
+ "**/target/**",
76
+ "dist/**",
77
+ "build/**",
78
+ "coverage/**",
79
+ ".next/**"
80
+ ],
81
+ "disabledChecks": [],
82
+ "changedCodePolicy": "block",
83
+ "debtPolicy": "report",
84
+ "limits": {
85
+ "maxDirectoryFiles": 40,
86
+ "maxPathDepth": 10,
87
+ "maxDirectoryRoles": 2,
88
+ "maxDumpingGroundFiles": 12
89
+ }
90
+ }
@@ -48,6 +48,7 @@
48
48
  "source": "NAOME built-in",
49
49
  "evidence": [
50
50
  ".naome/repository-quality.json",
51
+ ".naome/repository-structure.json",
51
52
  ".naome/repository-quality-baseline.json"
52
53
  ],
53
54
  "lastVerified": null
@@ -18,9 +18,10 @@ for the current step.
18
18
  11. `testing.md`
19
19
  12. `.naome/verification.json`
20
20
  13. `repository-quality.md`, when repository-quality checks or cleanup are relevant
21
- 14. `security.md`
22
- 15. `agent-workflow.md`
23
- 16. `decisions.md`, when changing durable project policy
21
+ 14. `repository-structure.md`, when path roles or structure cleanup are relevant
22
+ 15. `security.md`
23
+ 16. `agent-workflow.md`
24
+ 17. `decisions.md`, when changing durable project policy
24
25
 
25
26
  ## Source Types
26
27
 
@@ -33,6 +33,9 @@ to avoid overlapping window spam and include repeated regions inside the same
33
33
  file. Near-duplicate function checks compare functions/components, not
34
34
  container symbols against their own children.
35
35
 
36
+ Structure checks run through the same gate. See `repository-structure.md` for
37
+ path roles, module/layer policy, adapters, and cleanup routing.
38
+
36
39
  Agents may propose stricter repo-specific rules after inspecting the language
37
40
  and stack.
38
41
 
@@ -0,0 +1,51 @@
1
+ # Repository Structure
2
+
3
+ NAOME checks whether new and changed files land in a maintainable directory
4
+ structure. Existing structure debt stays visible in reports and cleanup routes,
5
+ but normal feature work is blocked only by relevant changed paths.
6
+
7
+ ## Model
8
+
9
+ The structure model classifies each path as:
10
+
11
+ `path -> role -> module -> layer -> language -> generated/debt/changed`
12
+
13
+ Generic roles are `source`, `test`, `docs`, `config`, `script`, `generated`,
14
+ `artifact`, `dependency/vendor`, and `unknown`.
15
+
16
+ ## Gates
17
+
18
+ - `naome quality check --changed` includes structure checks.
19
+ - `naome quality report` shows structure debt with other quality findings.
20
+ - `naome structure report --json` returns only structure findings.
21
+ - `naome structure explain --path <path> --json` explains one path's role,
22
+ module, layer, language, generated flag, debt flag, and changed flag.
23
+ - `naome cleanup plan` and `naome cleanup route --path <path>` include
24
+ structure findings when a cleanup task should move or split files.
25
+
26
+ ## Checks
27
+
28
+ Structure checks include directory role mixing, misplaced file roles,
29
+ root-level file sprawl, dumping-ground directories, directory size, path depth,
30
+ case-insensitive path collisions, and source/test pairing hints.
31
+
32
+ Dumping-ground names such as `utils`, `helpers`, `common`, `shared`, `misc`,
33
+ and `lib` are not banned. New feature logic there is reported when a named
34
+ module location is more appropriate.
35
+
36
+ ## Adapters
37
+
38
+ The core is language-independent. Adapters add deterministic signals for stack
39
+ conventions. Built-in adapters currently include `rust` and
40
+ `javascript-typescript`; future adapters can add source roots, test roots,
41
+ module roots, and allowed root files without changing gate behavior.
42
+
43
+ ## Local Policy
44
+
45
+ Rules live in `.naome/repository-structure.json`. Product defaults contain no
46
+ repository-specific paths. Local policy may add source roots, test roots,
47
+ generated roots, allowed root files, directory role rules, and layer rules.
48
+
49
+ Use local policy to document real repository conventions, not to grant special
50
+ rights to one product or hide cleanup work. Loosening a structure rule to pass a
51
+ feature diff requires human review.
@@ -58,6 +58,7 @@ phase is failing or missing.
58
58
  - Store long command output as a compact summary that preserves command, cwd,
59
59
  exit code, relevant lines, affected paths, and artifacts.
60
60
  - When intake defines change types, include `repository-quality-check` as a
61
- required check for source, documentation, harness, template, and CI changes.
61
+ required check for source, structure, documentation, harness, template, and
62
+ CI changes.
62
63
  - Before completion, select proof from the Verification Map when possible.
63
64
  - Report exact commands and results. Do not claim proof that did not run.