@mrpatronz/nexusflow 2.7.0 → 2.8.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 (268) hide show
  1. package/README.md +16 -14
  2. package/dist/agent/ClaudeSdkAdapter.d.ts.map +1 -1
  3. package/dist/agent/ClaudeSdkAdapter.js +31 -8
  4. package/dist/agent/ClaudeSdkAdapter.js.map +1 -1
  5. package/dist/agent/ClaudeSdkAdapter.test.js +18 -6
  6. package/dist/agent/ClaudeSdkAdapter.test.js.map +1 -1
  7. package/dist/agent/CodexCliAdapter.d.ts +1 -1
  8. package/dist/agent/CodexCliAdapter.d.ts.map +1 -1
  9. package/dist/agent/CodexCliAdapter.js +5 -4
  10. package/dist/agent/CodexCliAdapter.js.map +1 -1
  11. package/dist/agent/CodexCliAdapter.test.js +16 -1
  12. package/dist/agent/CodexCliAdapter.test.js.map +1 -1
  13. package/dist/agent/CodexSdkAdapter.d.ts.map +1 -1
  14. package/dist/agent/CodexSdkAdapter.js +6 -0
  15. package/dist/agent/CodexSdkAdapter.js.map +1 -1
  16. package/dist/agent/ProviderRegistry.d.ts +5 -0
  17. package/dist/agent/ProviderRegistry.d.ts.map +1 -1
  18. package/dist/agent/ProviderRegistry.js +15 -0
  19. package/dist/agent/ProviderRegistry.js.map +1 -1
  20. package/dist/agent/ProviderRegistry.test.js +19 -0
  21. package/dist/agent/ProviderRegistry.test.js.map +1 -1
  22. package/dist/agent/adapters.d.ts.map +1 -1
  23. package/dist/agent/adapters.js +5 -0
  24. package/dist/agent/adapters.js.map +1 -1
  25. package/dist/agent/mcp-config.d.ts +16 -0
  26. package/dist/agent/mcp-config.d.ts.map +1 -0
  27. package/dist/agent/mcp-config.js +28 -0
  28. package/dist/agent/mcp-config.js.map +1 -0
  29. package/dist/agent/mcp-config.test.d.ts +2 -0
  30. package/dist/agent/mcp-config.test.d.ts.map +1 -0
  31. package/dist/agent/mcp-config.test.js +22 -0
  32. package/dist/agent/mcp-config.test.js.map +1 -0
  33. package/dist/agent/models.d.ts +10 -0
  34. package/dist/agent/models.d.ts.map +1 -0
  35. package/dist/agent/models.js +35 -0
  36. package/dist/agent/models.js.map +1 -0
  37. package/dist/agent/models.test.d.ts +2 -0
  38. package/dist/agent/models.test.d.ts.map +1 -0
  39. package/dist/agent/models.test.js +40 -0
  40. package/dist/agent/models.test.js.map +1 -0
  41. package/dist/agent/orchestrator.d.ts +65 -0
  42. package/dist/agent/orchestrator.d.ts.map +1 -0
  43. package/dist/agent/orchestrator.js +260 -0
  44. package/dist/agent/orchestrator.js.map +1 -0
  45. package/dist/agent/orchestrator.test.d.ts +2 -0
  46. package/dist/agent/orchestrator.test.d.ts.map +1 -0
  47. package/dist/agent/orchestrator.test.js +284 -0
  48. package/dist/agent/orchestrator.test.js.map +1 -0
  49. package/dist/agent/session.d.ts +1 -0
  50. package/dist/agent/session.d.ts.map +1 -1
  51. package/dist/agent/session.js +3 -2
  52. package/dist/agent/session.js.map +1 -1
  53. package/dist/agent/session.test.js +9 -0
  54. package/dist/agent/session.test.js.map +1 -1
  55. package/dist/agent/smoke-chat.test.d.ts +2 -0
  56. package/dist/agent/smoke-chat.test.d.ts.map +1 -0
  57. package/dist/agent/smoke-chat.test.js +166 -0
  58. package/dist/agent/smoke-chat.test.js.map +1 -0
  59. package/dist/commands/commands.test.js +3 -0
  60. package/dist/commands/commands.test.js.map +1 -1
  61. package/dist/commands/doctor.d.ts.map +1 -1
  62. package/dist/commands/doctor.js +2 -0
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/init.d.ts +3 -1
  65. package/dist/commands/init.d.ts.map +1 -1
  66. package/dist/commands/init.js +9 -1
  67. package/dist/commands/init.js.map +1 -1
  68. package/dist/commands/knowledge.d.ts +9 -0
  69. package/dist/commands/knowledge.d.ts.map +1 -1
  70. package/dist/commands/knowledge.js +59 -2
  71. package/dist/commands/knowledge.js.map +1 -1
  72. package/dist/commands/knowledge.test.js +14 -1
  73. package/dist/commands/knowledge.test.js.map +1 -1
  74. package/dist/commands/mcp.d.ts +7 -1
  75. package/dist/commands/mcp.d.ts.map +1 -1
  76. package/dist/commands/mcp.js +7 -2
  77. package/dist/commands/mcp.js.map +1 -1
  78. package/dist/commands/progress.d.ts +4 -0
  79. package/dist/commands/progress.d.ts.map +1 -0
  80. package/dist/commands/progress.js +33 -0
  81. package/dist/commands/progress.js.map +1 -0
  82. package/dist/commands/refresh.d.ts +1 -0
  83. package/dist/commands/refresh.d.ts.map +1 -1
  84. package/dist/commands/refresh.js +17 -2
  85. package/dist/commands/refresh.js.map +1 -1
  86. package/dist/commands/remote.d.ts +4 -0
  87. package/dist/commands/remote.d.ts.map +1 -0
  88. package/dist/commands/remote.js +28 -0
  89. package/dist/commands/remote.js.map +1 -0
  90. package/dist/commands/status.d.ts.map +1 -1
  91. package/dist/commands/status.js +14 -1
  92. package/dist/commands/status.js.map +1 -1
  93. package/dist/commands/status.test.d.ts +2 -0
  94. package/dist/commands/status.test.d.ts.map +1 -0
  95. package/dist/commands/status.test.js +31 -0
  96. package/dist/commands/status.test.js.map +1 -0
  97. package/dist/core/analysis-cache.d.ts +13 -3
  98. package/dist/core/analysis-cache.d.ts.map +1 -1
  99. package/dist/core/analysis-cache.js +41 -31
  100. package/dist/core/analysis-cache.js.map +1 -1
  101. package/dist/core/analysis-cache.test.js +50 -8
  102. package/dist/core/analysis-cache.test.js.map +1 -1
  103. package/dist/core/doctor.d.ts.map +1 -1
  104. package/dist/core/doctor.js +61 -0
  105. package/dist/core/doctor.js.map +1 -1
  106. package/dist/core/generation-lock.d.ts +58 -0
  107. package/dist/core/generation-lock.d.ts.map +1 -0
  108. package/dist/core/generation-lock.js +233 -0
  109. package/dist/core/generation-lock.js.map +1 -0
  110. package/dist/core/generation-lock.test.d.ts +2 -0
  111. package/dist/core/generation-lock.test.d.ts.map +1 -0
  112. package/dist/core/generation-lock.test.js +134 -0
  113. package/dist/core/generation-lock.test.js.map +1 -0
  114. package/dist/core/isolate.test.js +30 -0
  115. package/dist/core/isolate.test.js.map +1 -1
  116. package/dist/core/knowledge.d.ts +20 -0
  117. package/dist/core/knowledge.d.ts.map +1 -1
  118. package/dist/core/knowledge.js +184 -36
  119. package/dist/core/knowledge.js.map +1 -1
  120. package/dist/core/knowledge.test.js +93 -15
  121. package/dist/core/knowledge.test.js.map +1 -1
  122. package/dist/core/locks.d.ts +4 -2
  123. package/dist/core/locks.d.ts.map +1 -1
  124. package/dist/core/locks.js +55 -7
  125. package/dist/core/locks.js.map +1 -1
  126. package/dist/core/locks.test.js +48 -0
  127. package/dist/core/locks.test.js.map +1 -1
  128. package/dist/core/progress.d.ts +21 -0
  129. package/dist/core/progress.d.ts.map +1 -0
  130. package/dist/core/progress.js +40 -0
  131. package/dist/core/progress.js.map +1 -0
  132. package/dist/core/progress.test.d.ts +2 -0
  133. package/dist/core/progress.test.d.ts.map +1 -0
  134. package/dist/core/progress.test.js +52 -0
  135. package/dist/core/progress.test.js.map +1 -0
  136. package/dist/core/refresh.d.ts +5 -0
  137. package/dist/core/refresh.d.ts.map +1 -1
  138. package/dist/core/refresh.js +25 -0
  139. package/dist/core/refresh.js.map +1 -1
  140. package/dist/core/refresh.test.js +20 -0
  141. package/dist/core/refresh.test.js.map +1 -1
  142. package/dist/core/status.d.ts +2 -0
  143. package/dist/core/status.d.ts.map +1 -1
  144. package/dist/core/status.js +6 -1
  145. package/dist/core/status.js.map +1 -1
  146. package/dist/core/sync.d.ts.map +1 -1
  147. package/dist/core/sync.js +22 -1
  148. package/dist/core/sync.js.map +1 -1
  149. package/dist/core/sync.test.js +27 -0
  150. package/dist/core/sync.test.js.map +1 -1
  151. package/dist/core/workspace-git.d.ts +15 -0
  152. package/dist/core/workspace-git.d.ts.map +1 -0
  153. package/dist/core/workspace-git.js +131 -0
  154. package/dist/core/workspace-git.js.map +1 -0
  155. package/dist/core/workspace-git.test.d.ts +2 -0
  156. package/dist/core/workspace-git.test.d.ts.map +1 -0
  157. package/dist/core/workspace-git.test.js +52 -0
  158. package/dist/core/workspace-git.test.js.map +1 -0
  159. package/dist/core/workspace-skills-workflow.integration.test.js +15 -0
  160. package/dist/core/workspace-skills-workflow.integration.test.js.map +1 -1
  161. package/dist/core/workspace.create.test.js +5 -2
  162. package/dist/core/workspace.create.test.js.map +1 -1
  163. package/dist/core/workspace.d.ts.map +1 -1
  164. package/dist/core/workspace.js +11 -6
  165. package/dist/core/workspace.js.map +1 -1
  166. package/dist/generators/antigravity.d.ts.map +1 -1
  167. package/dist/generators/antigravity.js +2 -1
  168. package/dist/generators/antigravity.js.map +1 -1
  169. package/dist/generators/base.d.ts.map +1 -1
  170. package/dist/generators/base.js +5 -3
  171. package/dist/generators/base.js.map +1 -1
  172. package/dist/generators/claude.d.ts.map +1 -1
  173. package/dist/generators/claude.js +4 -1
  174. package/dist/generators/claude.js.map +1 -1
  175. package/dist/generators/codex.d.ts.map +1 -1
  176. package/dist/generators/codex.js +2 -1
  177. package/dist/generators/codex.js.map +1 -1
  178. package/dist/generators/copilot.d.ts.map +1 -1
  179. package/dist/generators/copilot.js +4 -3
  180. package/dist/generators/copilot.js.map +1 -1
  181. package/dist/generators/cursor.d.ts.map +1 -1
  182. package/dist/generators/cursor.js +6 -3
  183. package/dist/generators/cursor.js.map +1 -1
  184. package/dist/generators/index.d.ts +2 -0
  185. package/dist/generators/index.d.ts.map +1 -1
  186. package/dist/generators/index.js +79 -45
  187. package/dist/generators/index.js.map +1 -1
  188. package/dist/generators/knowledge-migration.test.d.ts +2 -0
  189. package/dist/generators/knowledge-migration.test.d.ts.map +1 -0
  190. package/dist/generators/knowledge-migration.test.js +22 -0
  191. package/dist/generators/knowledge-migration.test.js.map +1 -0
  192. package/dist/generators/plan-generator.d.ts.map +1 -1
  193. package/dist/generators/plan-generator.js +18 -9
  194. package/dist/generators/plan-generator.js.map +1 -1
  195. package/dist/generators/plan-generator.test.js +4 -1
  196. package/dist/generators/plan-generator.test.js.map +1 -1
  197. package/dist/gui/assets/AgentsPage-B4fx43rd.js +3 -0
  198. package/dist/gui/assets/{CSPContext-BG7no5S_.js → CSPContext-DBUu9tE0.js} +1 -1
  199. package/dist/gui/assets/{DashboardPage-ByGTwAQa.js → DashboardPage-DH52G8IG.js} +1 -1
  200. package/dist/gui/assets/{GettingStartedPage-Xjx3M3RH.js → GettingStartedPage-BlTrQhvi.js} +1 -1
  201. package/dist/gui/assets/ProjectsPage-BPVSLPXv.js +1 -0
  202. package/dist/gui/assets/ScaffoldRepoInline-ywcpq9PX.js +1 -0
  203. package/dist/gui/assets/{SettingsPage-B9iN6hsv.js → SettingsPage-RQr8SalV.js} +1 -1
  204. package/dist/gui/assets/SkillsPage-CYoSRrwx.js +6 -0
  205. package/dist/gui/assets/StartWorkPage-DBKK4lFi.js +1 -0
  206. package/dist/gui/assets/{StrategiesPage-DDu3jwJx.js → StrategiesPage-C36TZgDX.js} +1 -1
  207. package/dist/gui/assets/WorkspacesPage-DxEONvSq.js +6 -0
  208. package/dist/gui/assets/{alert-dialog-CdqVrvZl.js → alert-dialog-CQAX2yRx.js} +1 -1
  209. package/dist/gui/assets/index-BF6pre6G.css +2 -0
  210. package/dist/gui/assets/index-C_rwnBzF.js +52 -0
  211. package/dist/gui/assets/isElementDisabled-uy_EOitH.js +1 -0
  212. package/dist/gui/assets/textarea-ByfoCb54.js +1 -0
  213. package/dist/gui/assets/{useAriaLabelledBy-DfRdwH8a.js → useAriaLabelledBy-ClesgjMe.js} +1 -1
  214. package/dist/gui/assets/useValueChanged-DeYvGnKs.js +1 -0
  215. package/dist/gui/assets/{vsc-D6UPv2ii.js → vsc-DFh0-53h.js} +1 -1
  216. package/dist/gui/index.html +5 -7
  217. package/dist/harness/claude.d.ts +3 -1
  218. package/dist/harness/claude.d.ts.map +1 -1
  219. package/dist/harness/claude.js +4 -2
  220. package/dist/harness/claude.js.map +1 -1
  221. package/dist/harness/codex.d.ts +3 -1
  222. package/dist/harness/codex.d.ts.map +1 -1
  223. package/dist/harness/codex.js +64 -12
  224. package/dist/harness/codex.js.map +1 -1
  225. package/dist/harness/contract.test.d.ts +2 -0
  226. package/dist/harness/contract.test.d.ts.map +1 -0
  227. package/dist/harness/contract.test.js +426 -0
  228. package/dist/harness/contract.test.js.map +1 -0
  229. package/dist/harness/harness.test.js +16 -1
  230. package/dist/harness/harness.test.js.map +1 -1
  231. package/dist/harness/types.d.ts +7 -1
  232. package/dist/harness/types.d.ts.map +1 -1
  233. package/dist/index.js +52 -5
  234. package/dist/index.js.map +1 -1
  235. package/dist/mcp/server.d.ts +8 -1
  236. package/dist/mcp/server.d.ts.map +1 -1
  237. package/dist/mcp/server.js +11 -6
  238. package/dist/mcp/server.js.map +1 -1
  239. package/dist/mcp/tools.d.ts +6 -2
  240. package/dist/mcp/tools.d.ts.map +1 -1
  241. package/dist/mcp/tools.js +232 -14
  242. package/dist/mcp/tools.js.map +1 -1
  243. package/dist/mcp/tools.test.js +130 -6
  244. package/dist/mcp/tools.test.js.map +1 -1
  245. package/dist/resources/materializer.d.ts.map +1 -1
  246. package/dist/resources/materializer.js +11 -3
  247. package/dist/resources/materializer.js.map +1 -1
  248. package/dist/server.d.ts.map +1 -1
  249. package/dist/server.js +37 -6
  250. package/dist/server.js.map +1 -1
  251. package/dist/server.test.js +37 -1
  252. package/dist/server.test.js.map +1 -1
  253. package/dist/types.d.ts +17 -0
  254. package/dist/types.d.ts.map +1 -1
  255. package/package.json +2 -1
  256. package/dist/gui/assets/AgentsPage-YyYRodOR.js +0 -3
  257. package/dist/gui/assets/ProjectsPage-BMdhqAGs.js +0 -1
  258. package/dist/gui/assets/ScaffoldRepoInline-gXyYSIz5.js +0 -1
  259. package/dist/gui/assets/SkillsPage-CxcsbIsQ.js +0 -6
  260. package/dist/gui/assets/StartWorkPage-DPVHcdy4.js +0 -1
  261. package/dist/gui/assets/WorkspacesPage-BWRmP0mY.js +0 -2
  262. package/dist/gui/assets/index-CZoZQkeC.css +0 -2
  263. package/dist/gui/assets/index-wy68EqfB.js +0 -50
  264. package/dist/gui/assets/isElementDisabled-D_fu2zfc.js +0 -1
  265. package/dist/gui/assets/store-D5DUHbxn.js +0 -3
  266. package/dist/gui/assets/styles-CVwNuFCx.js +0 -1
  267. package/dist/gui/assets/textarea-BNRuIXNs.js +0 -1
  268. package/dist/gui/assets/useValueChanged-CStSGSsD.js +0 -1
@@ -1,3 +1,9 @@
1
- export declare function mcpRunCommand(workspace?: string): Promise<void>;
1
+ import type { AgentRole } from '../mcp/tools.js';
2
+ export interface McpRunOptions {
3
+ role?: AgentRole;
4
+ allow?: string[];
5
+ deny?: string[];
6
+ }
7
+ export declare function mcpRunCommand(workspace?: string, options?: McpRunOptions): Promise<void>;
2
8
  export declare function mcpSetupCommand(): Promise<void>;
3
9
  //# sourceMappingURL=mcp.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAMA,wBAAsB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,iBAIrD;AAED,wBAAsB,eAAe,kBA+EpC"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAsB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,iBAS9E;AAED,wBAAsB,eAAe,kBA+EpC"}
@@ -3,10 +3,15 @@ import * as path from 'node:path';
3
3
  import * as fs from 'node:fs/promises';
4
4
  import chalk from 'chalk';
5
5
  import { startMcpServer } from '../mcp/server.js';
6
- export async function mcpRunCommand(workspace) {
6
+ export async function mcpRunCommand(workspace, options) {
7
7
  // If not provided, it attempts to use process.cwd() or waits for workspaceId in MCP calls.
8
8
  // The startMcpServer function handles this.
9
- await startMcpServer(workspace);
9
+ await startMcpServer({
10
+ workspacePath: workspace,
11
+ role: options?.role,
12
+ allowList: options?.allow,
13
+ denyList: options?.deny,
14
+ });
10
15
  }
11
16
  export async function mcpSetupCommand() {
12
17
  console.log(chalk.blue.bold('\nSetting up NexusFlow MCP Server for AI Assistants...'));
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function progressCommand(workspaceArg?: string, options?: {
2
+ json?: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../src/commands/progress.ts"],"names":[],"mappings":"AAUA,wBAAsB,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB5G"}
@@ -0,0 +1,33 @@
1
+ import chalk from 'chalk';
2
+ import { getWorkspaceProgress } from '../core/progress.js';
3
+ import { resolveWorkspaceInteractive } from '../utils/resolve-workspace.js';
4
+ function yesNo(value) {
5
+ if (value === undefined)
6
+ return '—';
7
+ return value ? 'yes' : 'no';
8
+ }
9
+ export async function progressCommand(workspaceArg, options = {}) {
10
+ const workspacePath = await resolveWorkspaceInteractive(workspaceArg, 'Select a workspace:');
11
+ if (!workspacePath)
12
+ return;
13
+ const report = await getWorkspaceProgress(workspacePath);
14
+ if (options.json) {
15
+ console.log(JSON.stringify(report, null, 2));
16
+ return;
17
+ }
18
+ console.log(chalk.bold.cyan('\n📈 NexusFlow — Live Implementation Progress\n'));
19
+ console.log('Repo\tBranch\tExpected\tAligned\tClean\tPushed\tPR');
20
+ for (const repo of report.repos) {
21
+ console.log([
22
+ repo.name,
23
+ repo.branch ?? '—',
24
+ repo.expectedBranch,
25
+ yesNo(repo.onExpectedBranch && repo.branchExists),
26
+ yesNo(repo.clean),
27
+ yesNo(repo.pushed),
28
+ repo.pullRequest?.state ?? '—',
29
+ ].join('\t'));
30
+ }
31
+ console.log();
32
+ }
33
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/commands/progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAE5E,SAAS,KAAK,CAAC,KAA0B;IACvC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IACpC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,YAAqB,EAAE,UAA8B,EAAE;IAC3F,MAAM,aAAa,GAAG,MAAM,2BAA2B,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAC;IAC7F,IAAI,CAAC,aAAa;QAAE,OAAO;IAC3B,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,aAAa,CAAC,CAAC;IACzD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;IAClE,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC;YACV,IAAI,CAAC,IAAI;YACT,IAAI,CAAC,MAAM,IAAI,GAAG;YAClB,IAAI,CAAC,cAAc;YACnB,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,YAAY,CAAC;YACjD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YAClB,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,GAAG;SAC/B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC"}
@@ -9,5 +9,6 @@
9
9
  export declare function refreshCommand(options: {
10
10
  force?: boolean;
11
11
  strategy?: string;
12
+ check?: boolean;
12
13
  }, workspaceArg?: string): Promise<void>;
13
14
  //# sourceMappingURL=refresh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../src/commands/refresh.ts"],"names":[],"mappings":"AAWA;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/C,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAiEf"}
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../src/commands/refresh.ts"],"names":[],"mappings":"AAWA;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,EAChE,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CA6Ef"}
@@ -56,18 +56,33 @@ export async function refreshCommand(options, workspaceArg) {
56
56
  // Persist the updated feature config
57
57
  await saveFeatureConfig(workspacePath, feature);
58
58
  }
59
- console.log('Refreshing context for all repositories...');
59
+ if (options.check)
60
+ console.log('Checking generated context provenance and hashes...');
61
+ else
62
+ console.log('Refreshing context for all repositories...');
60
63
  if (options.force) {
61
64
  console.log(chalk.dim('Force mode: ignoring analysis cache.'));
62
65
  }
63
66
  let report;
64
67
  try {
65
- report = await refreshWorkspace(workspacePath, { force: options.force });
68
+ report = await refreshWorkspace(workspacePath, { force: options.force, check: options.check });
66
69
  }
67
70
  catch (error) {
68
71
  console.error(chalk.red(`✖ Failed to refresh: ${error instanceof Error ? error.message : String(error)}`));
69
72
  return;
70
73
  }
74
+ if (report.check) {
75
+ if (report.check.fresh) {
76
+ console.log(chalk.bold.green('\n✅ Generated context is fresh and unmodified.\n'));
77
+ }
78
+ else {
79
+ console.error(chalk.bold.red('\n✖ Generated context is stale or drifted:'));
80
+ for (const item of report.check.drift)
81
+ console.error(chalk.red(` - ${item.message}`));
82
+ process.exitCode = 1;
83
+ }
84
+ return;
85
+ }
71
86
  if (report.reusedRepos.length > 0) {
72
87
  console.log(chalk.dim(`\n♻️ Token-efficient refresh: ${report.reusedRepos.length} unchanged repo(s) reused cached analysis` +
73
88
  (report.analyzedRepos.length > 0 ? `, ${report.analyzedRepos.length} re-analyzed.` : '.')));
@@ -1 +1 @@
1
- {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/commands/refresh.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/commands/refresh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function remoteAddCommand(url: string, workspaceArg?: string): Promise<void>;
2
+ export declare function remotePushCommand(workspaceArg?: string): Promise<void>;
3
+ export declare function remotePullCommand(workspaceArg?: string): Promise<void>;
4
+ //# sourceMappingURL=remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/commands/remote.ts"],"names":[],"mappings":"AAaA,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxF;AAED,wBAAsB,iBAAiB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5E;AAED,wBAAsB,iBAAiB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5E"}
@@ -0,0 +1,28 @@
1
+ import chalk from 'chalk';
2
+ import { resolveWorkspaceInteractive } from '../utils/resolve-workspace.js';
3
+ import { addWorkspaceRemote, pullWorkspaceArtifacts, pushWorkspaceArtifacts, } from '../core/workspace-git.js';
4
+ async function workspace(workspaceArg) {
5
+ return resolveWorkspaceInteractive(workspaceArg, 'Select a workspace artifact repository:');
6
+ }
7
+ export async function remoteAddCommand(url, workspaceArg) {
8
+ const workspacePath = await workspace(workspaceArg);
9
+ if (!workspacePath)
10
+ return;
11
+ await addWorkspaceRemote(workspacePath, url);
12
+ console.log(chalk.green('✔ Added workspace artifact remote origin.'));
13
+ }
14
+ export async function remotePushCommand(workspaceArg) {
15
+ const workspacePath = await workspace(workspaceArg);
16
+ if (!workspacePath)
17
+ return;
18
+ await pushWorkspaceArtifacts(workspacePath);
19
+ console.log(chalk.green('✔ Pushed workspace artifact history.'));
20
+ }
21
+ export async function remotePullCommand(workspaceArg) {
22
+ const workspacePath = await workspace(workspaceArg);
23
+ if (!workspacePath)
24
+ return;
25
+ await pullWorkspaceArtifacts(workspacePath);
26
+ console.log(chalk.green('✔ Pulled workspace artifact history with rebase.'));
27
+ }
28
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/commands/remote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAElC,KAAK,UAAU,SAAS,CAAC,YAAgC;IACvD,OAAO,2BAA2B,CAAC,YAAY,EAAE,yCAAyC,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,YAAqB;IACvE,MAAM,aAAa,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,CAAC,aAAa;QAAE,OAAO;IAC3B,MAAM,kBAAkB,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAAqB;IAC3D,MAAM,aAAa,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,CAAC,aAAa;QAAE,OAAO;IAC3B,MAAM,sBAAsB,CAAC,aAAa,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAAqB;IAC3D,MAAM,aAAa,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,CAAC,aAAa;QAAE,OAAO;IAC3B,MAAM,sBAAsB,CAAC,aAAa,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC,CAAC;AAC/E,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAatG"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtG"}
@@ -7,6 +7,8 @@ import { select } from '@inquirer/prompts';
7
7
  import { loadConfig } from '../core/config.js';
8
8
  import { listWorkspaces, loadFeatureConfig } from '../core/workspace.js';
9
9
  import { getServiceStatus, loadRunningState } from '../orchestration/index.js';
10
+ import { getWorkspaceStatusReport } from '../core/status.js';
11
+ import { checkGenerationLock } from '../core/generation-lock.js';
10
12
  /**
11
13
  * Shows status of running services for a workspace.
12
14
  *
@@ -18,11 +20,22 @@ export async function statusCommand(workspaceArg, options) {
18
20
  if (!workspacePath)
19
21
  return;
20
22
  if (options?.json) {
23
+ // Preserve the established machine-readable contract. Repository and
24
+ // generated-context detail is additive in the human view below; changing
25
+ // this top-level JSON shape would break existing scripts.
21
26
  const runningState = await loadRunningState(workspacePath);
22
27
  console.log(JSON.stringify(runningState, null, 2));
23
28
  return;
24
29
  }
25
- console.log(chalk.bold.cyan('\n📊 NexusFlow — Service Status\n'));
30
+ console.log(chalk.bold.cyan('\n📊 NexusFlow — Live Workspace Status\n'));
31
+ const repositories = await getWorkspaceStatusReport(workspacePath);
32
+ console.log(chalk.bold('Repositories:'));
33
+ for (const repo of repositories.repos) {
34
+ console.log(` ${repo.name}: ${repo.branch ?? 'detached'} @ ${repo.headSha?.slice(0, 12) ?? 'unknown'}; ${repo.dirty ? 'dirty' : 'clean'}; ${repo.ahead === null ? 'not pushed' : `${repo.ahead} ahead / ${repo.behind} behind`}`);
35
+ }
36
+ const freshness = await checkGenerationLock(workspacePath);
37
+ console.log(`\n${freshness.fresh ? chalk.green('Generated context: fresh') : chalk.red(`Generated context: stale/drifted (${freshness.drift.length})`)}`);
38
+ console.log(chalk.bold('\nServices:'));
26
39
  await getServiceStatus(workspacePath);
27
40
  console.log();
28
41
  }
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,YAAqB,EAAE,OAA4B;IACrF,MAAM,aAAa,GAAG,MAAM,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAC3D,IAAI,CAAC,aAAa;QAAE,OAAO;IAE3B,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,aAAa,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC,CAAC;IAClE,MAAM,gBAAgB,CAAC,aAAa,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAAC,YAAqB;IACnD,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IAEtC,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1D,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC,aAAa,CAAC;IAEhD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAE9D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC;QAC5B,OAAO,EAAE,qBAAqB;QAC9B,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC/B,IAAI,EAAE,GAAG,EAAE,CAAC,UAAU,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC,EAAE;YACnE,KAAK,EAAE,EAAE,CAAC,aAAa;SACxB,CAAC,CAAC;KACJ,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=status.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.test.d.ts","sourceRoot":"","sources":["../../src/commands/status.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { statusCommand } from './status.js';
3
+ import * as orchestration from '../orchestration/index.js';
4
+ import * as repositoryStatus from '../core/status.js';
5
+ import * as generationLock from '../core/generation-lock.js';
6
+ vi.mock('../core/config.js');
7
+ vi.mock('../core/workspace.js');
8
+ vi.mock('../orchestration/index.js');
9
+ vi.mock('../core/status.js');
10
+ vi.mock('../core/generation-lock.js');
11
+ describe('statusCommand', () => {
12
+ beforeEach(() => {
13
+ vi.clearAllMocks();
14
+ });
15
+ it('preserves the legacy running-state shape for --json', async () => {
16
+ const runningState = {
17
+ workspacePath: '/ws',
18
+ services: [],
19
+ orchestrators: [],
20
+ updatedAt: '2026-08-26T00:00:00.000Z',
21
+ };
22
+ vi.mocked(orchestration.loadRunningState).mockResolvedValue(runningState);
23
+ const log = vi.spyOn(console, 'log').mockImplementation(() => undefined);
24
+ await statusCommand('/ws', { json: true });
25
+ expect(JSON.parse(String(log.mock.calls[0][0]))).toEqual(runningState);
26
+ expect(repositoryStatus.getWorkspaceStatusReport).not.toHaveBeenCalled();
27
+ expect(generationLock.checkGenerationLock).not.toHaveBeenCalled();
28
+ log.mockRestore();
29
+ });
30
+ });
31
+ //# sourceMappingURL=status.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.test.js","sourceRoot":"","sources":["../../src/commands/status.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,aAAa,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,gBAAgB,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,cAAc,MAAM,4BAA4B,CAAC;AAE7D,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AAC7B,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;AAChC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;AACrC,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AAC7B,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;AAEtC,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,YAAY,GAAG;YACnB,aAAa,EAAE,KAAK;YACpB,QAAQ,EAAE,EAAE;YACZ,aAAa,EAAE,EAAE;YACjB,SAAS,EAAE,0BAA0B;SACtC,CAAC;QACF,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;QAC1E,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAEzE,MAAM,aAAa,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACxE,MAAM,CAAC,gBAAgB,CAAC,wBAAwB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACzE,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAClE,GAAG,CAAC,WAAW,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -7,6 +7,13 @@
7
7
  * an upgrade so the generators never read stale analysis.
8
8
  */
9
9
  import type { ProjectAnalysis } from '../types.js';
10
+ /**
11
+ * This package's version, used as part of every repo fingerprint.
12
+ *
13
+ * Read locally rather than via `utils/update-check`, which drags config loading
14
+ * and the network update check into `core/`.
15
+ */
16
+ export declare function getGeneratorVersion(): string;
10
17
  /** A cached analysis result for a single repo. */
11
18
  export interface AnalysisCacheEntry {
12
19
  /** Directory name of the repo. */
@@ -47,9 +54,12 @@ export declare function loadAnalysisCache(workspacePath: string): Promise<Analys
47
54
  export declare function saveAnalysisCache(workspacePath: string, cache: AnalysisCache, currentRepoNames?: string[]): Promise<void>;
48
55
  /**
49
56
  * Computes a content fingerprint for a repo: this package's version, the HEAD
50
- * commit SHA, and a hash of the dirty working-tree files (status line + size +
51
- * mtime per file) when the tree is not clean. Editing, adding, or deleting an
52
- * uncommitted file therefore changes the fingerprint too.
57
+ * commit SHA, and a hash of each dirty path plus its actual bytes (or symlink
58
+ * target) when the tree is not clean. Editing, adding, or deleting an
59
+ * uncommitted file therefore changes the fingerprint even when its size and
60
+ * directory metadata stay unchanged. Platforms without a no-follow file-open
61
+ * flag fail closed for dirty regular files and return `null`, forcing analysis
62
+ * instead of reusing a cache based on an unsafe read.
53
63
  *
54
64
  * The version is part of the key so that upgrading NexusFlow re-runs the
55
65
  * analysis the generators read from. Keyed on repo content alone, an upgrade that
@@ -1 +1 @@
1
- {"version":3,"file":"analysis-cache.d.ts","sourceRoot":"","sources":["../../src/core/analysis-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAkDnD,kDAAkD;AAClD,MAAM,WAAW,kBAAkB;IACjC,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAC3C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,CAAC,CAWxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,aAAa,EACpB,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAUf;AAaD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuCxB"}
1
+ {"version":3,"file":"analysis-cache.d.ts","sourceRoot":"","sources":["../../src/core/analysis-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AASnD;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAkC5C;AAED,kDAAkD;AAClD,MAAM,WAAW,kBAAkB;IACjC,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAC3C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,CAAC,CAWxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,aAAa,EACpB,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAsDxB"}
@@ -7,11 +7,12 @@
7
7
  * an upgrade so the generators never read stale analysis.
8
8
  */
9
9
  import { createHash } from 'node:crypto';
10
- import { existsSync, readFileSync } from 'node:fs';
10
+ import { constants, existsSync, readFileSync } from 'node:fs';
11
11
  import * as fs from 'node:fs/promises';
12
12
  import * as path from 'node:path';
13
13
  import { fileURLToPath } from 'node:url';
14
14
  import { execa } from 'execa';
15
+ import { parsePorcelainZ } from '../utils/multi-git.js';
15
16
  /** Name of the analysis cache file, written at the workspace root. */
16
17
  const CACHE_FILE = '.nexusflow-analysis-cache.json';
17
18
  /** Memoised own version; resolved once per process. */
@@ -22,7 +23,7 @@ let generatorVersion;
22
23
  * Read locally rather than via `utils/update-check`, which drags config loading
23
24
  * and the network update check into `core/`.
24
25
  */
25
- function getGeneratorVersion() {
26
+ export function getGeneratorVersion() {
26
27
  if (generatorVersion !== undefined)
27
28
  return generatorVersion;
28
29
  let resolved;
@@ -100,21 +101,14 @@ export async function saveAnalysisCache(workspacePath, cache, currentRepoNames)
100
101
  const data = JSON.stringify(cache, null, 2) + '\n';
101
102
  await fs.writeFile(getAnalysisCachePath(workspacePath), data, 'utf-8');
102
103
  }
103
- /**
104
- * Strips the surrounding quotes git adds to porcelain paths containing
105
- * special characters.
106
- */
107
- function unquotePorcelainPath(p) {
108
- if (p.startsWith('"') && p.endsWith('"')) {
109
- return p.slice(1, -1);
110
- }
111
- return p;
112
- }
113
104
  /**
114
105
  * Computes a content fingerprint for a repo: this package's version, the HEAD
115
- * commit SHA, and a hash of the dirty working-tree files (status line + size +
116
- * mtime per file) when the tree is not clean. Editing, adding, or deleting an
117
- * uncommitted file therefore changes the fingerprint too.
106
+ * commit SHA, and a hash of each dirty path plus its actual bytes (or symlink
107
+ * target) when the tree is not clean. Editing, adding, or deleting an
108
+ * uncommitted file therefore changes the fingerprint even when its size and
109
+ * directory metadata stay unchanged. Platforms without a no-follow file-open
110
+ * flag fail closed for dirty regular files and return `null`, forcing analysis
111
+ * instead of reusing a cache based on an unsafe read.
118
112
  *
119
113
  * The version is part of the key so that upgrading NexusFlow re-runs the
120
114
  * analysis the generators read from. Keyed on repo content alone, an upgrade that
@@ -133,31 +127,47 @@ export async function getRepoFingerprint(repoPath) {
133
127
  cwd: repoPath,
134
128
  });
135
129
  const sha = shaOut.trim();
136
- const { stdout: statusOut } = await execa('git', ['status', '--porcelain'], {
130
+ // `-uall` is essential: plain porcelain collapses an untracked directory to
131
+ // `?? newdir/`, so editing a file inside it leaves the directory metadata
132
+ // unchanged and used to produce a false cache hit / false "fresh" result.
133
+ const { stdout: statusOut } = await execa('git', ['status', '--porcelain=v1', '-z', '-uall'], {
137
134
  cwd: repoPath,
138
135
  });
139
- const lines = statusOut.split('\n').filter(Boolean);
140
- if (lines.length === 0) {
136
+ const entries = parsePorcelainZ(statusOut);
137
+ if (entries.length === 0) {
141
138
  return `${prefix}${sha}`;
142
139
  }
143
- let dirtySignature = '';
144
- for (const line of lines) {
145
- const rel = line.slice(3).trim();
146
- // Rename lines look like "R old -> new"; stat the new path.
147
- const target = rel.includes(' -> ') ? rel.split(' -> ').pop() : rel;
148
- const filePath = path.join(repoPath, unquotePorcelainPath(target));
140
+ const dirty = createHash('sha256');
141
+ for (const entry of entries.sort((a, b) => a.path.localeCompare(b.path))) {
142
+ dirty.update(entry.code).update('\0').update(entry.path).update('\0');
143
+ const filePath = path.join(repoPath, entry.path);
149
144
  try {
150
- const st = await fs.stat(filePath);
151
- dirtySignature += `${line}|${st.size}|${Math.floor(st.mtimeMs)}\n`;
145
+ // Reading the link itself never follows it. For ordinary files, the
146
+ // no-follow flag closes the lstat/read race where an untrusted worktree
147
+ // could swap a checked file for a symlink before its bytes were read.
148
+ const target = await fs.readlink(filePath);
149
+ dirty.update('symlink\0').update(target);
152
150
  }
153
151
  catch {
154
- dirtySignature += `${line}|missing\n`;
152
+ if (typeof constants.O_NOFOLLOW !== 'number') {
153
+ // Windows does not expose O_NOFOLLOW. An ordinary read after the
154
+ // failed readlink probe would reintroduce a symlink-swap race, so
155
+ // disable cache reuse for this dirty snapshot and reanalyze it.
156
+ return null;
157
+ }
158
+ try {
159
+ const flags = constants.O_RDONLY | constants.O_NOFOLLOW;
160
+ dirty.update('file\0').update(await fs.readFile(filePath, { flag: flags }));
161
+ }
162
+ catch {
163
+ // Deletions have no bytes to read; their status and path above are the
164
+ // complete retained state that must invalidate the snapshot.
165
+ dirty.update('missing\0');
166
+ }
155
167
  }
168
+ dirty.update('\0');
156
169
  }
157
- const dirtyHash = createHash('sha1')
158
- .update(dirtySignature)
159
- .digest('hex')
160
- .slice(0, 12);
170
+ const dirtyHash = dirty.digest('hex').slice(0, 12);
161
171
  return `${prefix}${sha}+${dirtyHash}`;
162
172
  }
163
173
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"analysis-cache.js","sourceRoot":"","sources":["../../src/core/analysis-cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analysis-cache.js","sourceRoot":"","sources":["../../src/core/analysis-cache.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { constants } from 'node:fs';
2
3
  import * as fs from 'node:fs/promises';
3
4
  import { execa } from 'execa';
4
5
  import { loadAnalysisCache, saveAnalysisCache, getRepoFingerprint, } from './analysis-cache.js';
@@ -23,6 +24,7 @@ describe('analysis-cache', () => {
23
24
  beforeEach(() => {
24
25
  vi.clearAllMocks();
25
26
  vi.mocked(fs.writeFile).mockResolvedValue(undefined);
27
+ vi.mocked(fs.readlink).mockRejectedValue(Object.assign(new Error('not a link'), { code: 'EINVAL' }));
26
28
  });
27
29
  describe('loadAnalysisCache', () => {
28
30
  it('returns an empty skeleton when the file is absent', async () => {
@@ -81,11 +83,16 @@ describe('analysis-cache', () => {
81
83
  vi.mocked(execa).mockImplementation((async (_cmd, args) => {
82
84
  if (args[0] === 'rev-parse')
83
85
  return { stdout: 'abc123\n' };
84
- return { stdout: ' M src/file1.ts\n' };
86
+ return { stdout: ' M src/file1.ts\0' };
85
87
  }));
86
- vi.mocked(fs.stat).mockResolvedValue({ size: 100, mtimeMs: 1000 });
88
+ vi.mocked(fs.readFile).mockResolvedValue(Buffer.from('first'));
87
89
  const fp = await getRepoFingerprint('/ws/repo-1');
88
- expect(fp).toMatch(/^nf\S+:abc123\+[0-9a-f]{12}$/);
90
+ if (typeof constants.O_NOFOLLOW === 'number') {
91
+ expect(fp).toMatch(/^nf\S+:abc123\+[0-9a-f]{12}$/);
92
+ }
93
+ else {
94
+ expect(fp).toBeNull();
95
+ }
89
96
  });
90
97
  it('invalidates every cached fingerprint when the version changes', async () => {
91
98
  // The whole point: an upgraded install must not accept the old key.
@@ -102,14 +109,49 @@ describe('analysis-cache', () => {
102
109
  vi.mocked(execa).mockImplementation((async (_cmd, args) => {
103
110
  if (args[0] === 'rev-parse')
104
111
  return { stdout: 'abc123\n' };
105
- return { stdout: ' M src/file1.ts\n' };
112
+ return { stdout: ' M src/file1.ts\0' };
113
+ }));
114
+ vi.mocked(fs.readFile).mockResolvedValue(Buffer.from('first'));
115
+ const before = await getRepoFingerprint('/ws/repo-1');
116
+ vi.mocked(fs.readFile).mockResolvedValue(Buffer.from('second'));
117
+ const after = await getRepoFingerprint('/ws/repo-1');
118
+ if (typeof constants.O_NOFOLLOW === 'number') {
119
+ expect(before).not.toBe(after);
120
+ expect(before).not.toBe('abc123');
121
+ }
122
+ else {
123
+ expect(before).toBeNull();
124
+ expect(after).toBeNull();
125
+ }
126
+ });
127
+ it('changes when content inside an untracked directory changes without directory metadata changing', async () => {
128
+ vi.mocked(execa).mockImplementation((async (_cmd, args) => {
129
+ if (args[0] === 'rev-parse')
130
+ return { stdout: 'abc123\n' };
131
+ return { stdout: '?? newdir/source.ts\0' };
106
132
  }));
107
- vi.mocked(fs.stat).mockResolvedValue({ size: 100, mtimeMs: 1000 });
133
+ vi.mocked(fs.readFile).mockResolvedValue(Buffer.from('aaaa'));
108
134
  const before = await getRepoFingerprint('/ws/repo-1');
109
- vi.mocked(fs.stat).mockResolvedValue({ size: 150, mtimeMs: 2000 });
135
+ vi.mocked(fs.readFile).mockResolvedValue(Buffer.from('bbbb'));
110
136
  const after = await getRepoFingerprint('/ws/repo-1');
111
- expect(before).not.toBe(after);
112
- expect(before).not.toBe('abc123');
137
+ if (typeof constants.O_NOFOLLOW === 'number') {
138
+ expect(after).not.toBe(before);
139
+ }
140
+ else {
141
+ expect(before).toBeNull();
142
+ expect(after).toBeNull();
143
+ }
144
+ });
145
+ it('hashes a symlink target without reading through the link', async () => {
146
+ vi.mocked(execa).mockImplementation((async (_cmd, args) => {
147
+ if (args[0] === 'rev-parse')
148
+ return { stdout: 'abc123\n' };
149
+ return { stdout: ' M src/link.ts\0' };
150
+ }));
151
+ vi.mocked(fs.readlink).mockResolvedValue('../outside/secret');
152
+ const fp = await getRepoFingerprint('/ws/repo-1');
153
+ expect(fp).toMatch(/^nf\S+:abc123\+[0-9a-f]{12}$/);
154
+ expect(fs.readFile).not.toHaveBeenCalled();
113
155
  });
114
156
  it('returns null when git fails', async () => {
115
157
  vi.mocked(execa).mockRejectedValue(new Error('not a git repository'));