@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.
- package/README.md +16 -14
- package/dist/agent/ClaudeSdkAdapter.d.ts.map +1 -1
- package/dist/agent/ClaudeSdkAdapter.js +31 -8
- package/dist/agent/ClaudeSdkAdapter.js.map +1 -1
- package/dist/agent/ClaudeSdkAdapter.test.js +18 -6
- package/dist/agent/ClaudeSdkAdapter.test.js.map +1 -1
- package/dist/agent/CodexCliAdapter.d.ts +1 -1
- package/dist/agent/CodexCliAdapter.d.ts.map +1 -1
- package/dist/agent/CodexCliAdapter.js +5 -4
- package/dist/agent/CodexCliAdapter.js.map +1 -1
- package/dist/agent/CodexCliAdapter.test.js +16 -1
- package/dist/agent/CodexCliAdapter.test.js.map +1 -1
- package/dist/agent/CodexSdkAdapter.d.ts.map +1 -1
- package/dist/agent/CodexSdkAdapter.js +6 -0
- package/dist/agent/CodexSdkAdapter.js.map +1 -1
- package/dist/agent/ProviderRegistry.d.ts +5 -0
- package/dist/agent/ProviderRegistry.d.ts.map +1 -1
- package/dist/agent/ProviderRegistry.js +15 -0
- package/dist/agent/ProviderRegistry.js.map +1 -1
- package/dist/agent/ProviderRegistry.test.js +19 -0
- package/dist/agent/ProviderRegistry.test.js.map +1 -1
- package/dist/agent/adapters.d.ts.map +1 -1
- package/dist/agent/adapters.js +5 -0
- package/dist/agent/adapters.js.map +1 -1
- package/dist/agent/mcp-config.d.ts +16 -0
- package/dist/agent/mcp-config.d.ts.map +1 -0
- package/dist/agent/mcp-config.js +28 -0
- package/dist/agent/mcp-config.js.map +1 -0
- package/dist/agent/mcp-config.test.d.ts +2 -0
- package/dist/agent/mcp-config.test.d.ts.map +1 -0
- package/dist/agent/mcp-config.test.js +22 -0
- package/dist/agent/mcp-config.test.js.map +1 -0
- package/dist/agent/models.d.ts +10 -0
- package/dist/agent/models.d.ts.map +1 -0
- package/dist/agent/models.js +35 -0
- package/dist/agent/models.js.map +1 -0
- package/dist/agent/models.test.d.ts +2 -0
- package/dist/agent/models.test.d.ts.map +1 -0
- package/dist/agent/models.test.js +40 -0
- package/dist/agent/models.test.js.map +1 -0
- package/dist/agent/orchestrator.d.ts +65 -0
- package/dist/agent/orchestrator.d.ts.map +1 -0
- package/dist/agent/orchestrator.js +260 -0
- package/dist/agent/orchestrator.js.map +1 -0
- package/dist/agent/orchestrator.test.d.ts +2 -0
- package/dist/agent/orchestrator.test.d.ts.map +1 -0
- package/dist/agent/orchestrator.test.js +284 -0
- package/dist/agent/orchestrator.test.js.map +1 -0
- package/dist/agent/session.d.ts +1 -0
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +3 -2
- package/dist/agent/session.js.map +1 -1
- package/dist/agent/session.test.js +9 -0
- package/dist/agent/session.test.js.map +1 -1
- package/dist/agent/smoke-chat.test.d.ts +2 -0
- package/dist/agent/smoke-chat.test.d.ts.map +1 -0
- package/dist/agent/smoke-chat.test.js +166 -0
- package/dist/agent/smoke-chat.test.js.map +1 -0
- package/dist/commands/commands.test.js +3 -0
- package/dist/commands/commands.test.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +2 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +3 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +9 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/knowledge.d.ts +9 -0
- package/dist/commands/knowledge.d.ts.map +1 -1
- package/dist/commands/knowledge.js +59 -2
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/knowledge.test.js +14 -1
- package/dist/commands/knowledge.test.js.map +1 -1
- package/dist/commands/mcp.d.ts +7 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +7 -2
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/progress.d.ts +4 -0
- package/dist/commands/progress.d.ts.map +1 -0
- package/dist/commands/progress.js +33 -0
- package/dist/commands/progress.js.map +1 -0
- package/dist/commands/refresh.d.ts +1 -0
- package/dist/commands/refresh.d.ts.map +1 -1
- package/dist/commands/refresh.js +17 -2
- package/dist/commands/refresh.js.map +1 -1
- package/dist/commands/remote.d.ts +4 -0
- package/dist/commands/remote.d.ts.map +1 -0
- package/dist/commands/remote.js +28 -0
- package/dist/commands/remote.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +14 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/status.test.d.ts +2 -0
- package/dist/commands/status.test.d.ts.map +1 -0
- package/dist/commands/status.test.js +31 -0
- package/dist/commands/status.test.js.map +1 -0
- package/dist/core/analysis-cache.d.ts +13 -3
- package/dist/core/analysis-cache.d.ts.map +1 -1
- package/dist/core/analysis-cache.js +41 -31
- package/dist/core/analysis-cache.js.map +1 -1
- package/dist/core/analysis-cache.test.js +50 -8
- package/dist/core/analysis-cache.test.js.map +1 -1
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +61 -0
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/generation-lock.d.ts +58 -0
- package/dist/core/generation-lock.d.ts.map +1 -0
- package/dist/core/generation-lock.js +233 -0
- package/dist/core/generation-lock.js.map +1 -0
- package/dist/core/generation-lock.test.d.ts +2 -0
- package/dist/core/generation-lock.test.d.ts.map +1 -0
- package/dist/core/generation-lock.test.js +134 -0
- package/dist/core/generation-lock.test.js.map +1 -0
- package/dist/core/isolate.test.js +30 -0
- package/dist/core/isolate.test.js.map +1 -1
- package/dist/core/knowledge.d.ts +20 -0
- package/dist/core/knowledge.d.ts.map +1 -1
- package/dist/core/knowledge.js +184 -36
- package/dist/core/knowledge.js.map +1 -1
- package/dist/core/knowledge.test.js +93 -15
- package/dist/core/knowledge.test.js.map +1 -1
- package/dist/core/locks.d.ts +4 -2
- package/dist/core/locks.d.ts.map +1 -1
- package/dist/core/locks.js +55 -7
- package/dist/core/locks.js.map +1 -1
- package/dist/core/locks.test.js +48 -0
- package/dist/core/locks.test.js.map +1 -1
- package/dist/core/progress.d.ts +21 -0
- package/dist/core/progress.d.ts.map +1 -0
- package/dist/core/progress.js +40 -0
- package/dist/core/progress.js.map +1 -0
- package/dist/core/progress.test.d.ts +2 -0
- package/dist/core/progress.test.d.ts.map +1 -0
- package/dist/core/progress.test.js +52 -0
- package/dist/core/progress.test.js.map +1 -0
- package/dist/core/refresh.d.ts +5 -0
- package/dist/core/refresh.d.ts.map +1 -1
- package/dist/core/refresh.js +25 -0
- package/dist/core/refresh.js.map +1 -1
- package/dist/core/refresh.test.js +20 -0
- package/dist/core/refresh.test.js.map +1 -1
- package/dist/core/status.d.ts +2 -0
- package/dist/core/status.d.ts.map +1 -1
- package/dist/core/status.js +6 -1
- package/dist/core/status.js.map +1 -1
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/core/sync.js +22 -1
- package/dist/core/sync.js.map +1 -1
- package/dist/core/sync.test.js +27 -0
- package/dist/core/sync.test.js.map +1 -1
- package/dist/core/workspace-git.d.ts +15 -0
- package/dist/core/workspace-git.d.ts.map +1 -0
- package/dist/core/workspace-git.js +131 -0
- package/dist/core/workspace-git.js.map +1 -0
- package/dist/core/workspace-git.test.d.ts +2 -0
- package/dist/core/workspace-git.test.d.ts.map +1 -0
- package/dist/core/workspace-git.test.js +52 -0
- package/dist/core/workspace-git.test.js.map +1 -0
- package/dist/core/workspace-skills-workflow.integration.test.js +15 -0
- package/dist/core/workspace-skills-workflow.integration.test.js.map +1 -1
- package/dist/core/workspace.create.test.js +5 -2
- package/dist/core/workspace.create.test.js.map +1 -1
- package/dist/core/workspace.d.ts.map +1 -1
- package/dist/core/workspace.js +11 -6
- package/dist/core/workspace.js.map +1 -1
- package/dist/generators/antigravity.d.ts.map +1 -1
- package/dist/generators/antigravity.js +2 -1
- package/dist/generators/antigravity.js.map +1 -1
- package/dist/generators/base.d.ts.map +1 -1
- package/dist/generators/base.js +5 -3
- package/dist/generators/base.js.map +1 -1
- package/dist/generators/claude.d.ts.map +1 -1
- package/dist/generators/claude.js +4 -1
- package/dist/generators/claude.js.map +1 -1
- package/dist/generators/codex.d.ts.map +1 -1
- package/dist/generators/codex.js +2 -1
- package/dist/generators/codex.js.map +1 -1
- package/dist/generators/copilot.d.ts.map +1 -1
- package/dist/generators/copilot.js +4 -3
- package/dist/generators/copilot.js.map +1 -1
- package/dist/generators/cursor.d.ts.map +1 -1
- package/dist/generators/cursor.js +6 -3
- package/dist/generators/cursor.js.map +1 -1
- package/dist/generators/index.d.ts +2 -0
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +79 -45
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/knowledge-migration.test.d.ts +2 -0
- package/dist/generators/knowledge-migration.test.d.ts.map +1 -0
- package/dist/generators/knowledge-migration.test.js +22 -0
- package/dist/generators/knowledge-migration.test.js.map +1 -0
- package/dist/generators/plan-generator.d.ts.map +1 -1
- package/dist/generators/plan-generator.js +18 -9
- package/dist/generators/plan-generator.js.map +1 -1
- package/dist/generators/plan-generator.test.js +4 -1
- package/dist/generators/plan-generator.test.js.map +1 -1
- package/dist/gui/assets/AgentsPage-B4fx43rd.js +3 -0
- package/dist/gui/assets/{CSPContext-BG7no5S_.js → CSPContext-DBUu9tE0.js} +1 -1
- package/dist/gui/assets/{DashboardPage-ByGTwAQa.js → DashboardPage-DH52G8IG.js} +1 -1
- package/dist/gui/assets/{GettingStartedPage-Xjx3M3RH.js → GettingStartedPage-BlTrQhvi.js} +1 -1
- package/dist/gui/assets/ProjectsPage-BPVSLPXv.js +1 -0
- package/dist/gui/assets/ScaffoldRepoInline-ywcpq9PX.js +1 -0
- package/dist/gui/assets/{SettingsPage-B9iN6hsv.js → SettingsPage-RQr8SalV.js} +1 -1
- package/dist/gui/assets/SkillsPage-CYoSRrwx.js +6 -0
- package/dist/gui/assets/StartWorkPage-DBKK4lFi.js +1 -0
- package/dist/gui/assets/{StrategiesPage-DDu3jwJx.js → StrategiesPage-C36TZgDX.js} +1 -1
- package/dist/gui/assets/WorkspacesPage-DxEONvSq.js +6 -0
- package/dist/gui/assets/{alert-dialog-CdqVrvZl.js → alert-dialog-CQAX2yRx.js} +1 -1
- package/dist/gui/assets/index-BF6pre6G.css +2 -0
- package/dist/gui/assets/index-C_rwnBzF.js +52 -0
- package/dist/gui/assets/isElementDisabled-uy_EOitH.js +1 -0
- package/dist/gui/assets/textarea-ByfoCb54.js +1 -0
- package/dist/gui/assets/{useAriaLabelledBy-DfRdwH8a.js → useAriaLabelledBy-ClesgjMe.js} +1 -1
- package/dist/gui/assets/useValueChanged-DeYvGnKs.js +1 -0
- package/dist/gui/assets/{vsc-D6UPv2ii.js → vsc-DFh0-53h.js} +1 -1
- package/dist/gui/index.html +5 -7
- package/dist/harness/claude.d.ts +3 -1
- package/dist/harness/claude.d.ts.map +1 -1
- package/dist/harness/claude.js +4 -2
- package/dist/harness/claude.js.map +1 -1
- package/dist/harness/codex.d.ts +3 -1
- package/dist/harness/codex.d.ts.map +1 -1
- package/dist/harness/codex.js +64 -12
- package/dist/harness/codex.js.map +1 -1
- package/dist/harness/contract.test.d.ts +2 -0
- package/dist/harness/contract.test.d.ts.map +1 -0
- package/dist/harness/contract.test.js +426 -0
- package/dist/harness/contract.test.js.map +1 -0
- package/dist/harness/harness.test.js +16 -1
- package/dist/harness/harness.test.js.map +1 -1
- package/dist/harness/types.d.ts +7 -1
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/index.js +52 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +8 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +11 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +6 -2
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +232 -14
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/tools.test.js +130 -6
- package/dist/mcp/tools.test.js.map +1 -1
- package/dist/resources/materializer.d.ts.map +1 -1
- package/dist/resources/materializer.js +11 -3
- package/dist/resources/materializer.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +37 -6
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +37 -1
- package/dist/server.test.js.map +1 -1
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/gui/assets/AgentsPage-YyYRodOR.js +0 -3
- package/dist/gui/assets/ProjectsPage-BMdhqAGs.js +0 -1
- package/dist/gui/assets/ScaffoldRepoInline-gXyYSIz5.js +0 -1
- package/dist/gui/assets/SkillsPage-CxcsbIsQ.js +0 -6
- package/dist/gui/assets/StartWorkPage-DPVHcdy4.js +0 -1
- package/dist/gui/assets/WorkspacesPage-BWRmP0mY.js +0 -2
- package/dist/gui/assets/index-CZoZQkeC.css +0 -2
- package/dist/gui/assets/index-wy68EqfB.js +0 -50
- package/dist/gui/assets/isElementDisabled-D_fu2zfc.js +0 -1
- package/dist/gui/assets/store-D5DUHbxn.js +0 -3
- package/dist/gui/assets/styles-CVwNuFCx.js +0 -1
- package/dist/gui/assets/textarea-BNRuIXNs.js +0 -1
- package/dist/gui/assets/useValueChanged-CStSGSsD.js +0 -1
package/dist/commands/mcp.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
|
|
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":"
|
|
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"}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -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(
|
|
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...'));
|
package/dist/commands/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAyB,MAAM,kBAAkB,CAAC;AASzE,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAkB,EAAE,OAAuB;IAC7E,2FAA2F;IAC3F,4CAA4C;IAC5C,MAAM,cAAc,CAAC;QACnB,aAAa,EAAE,SAAS;QACxB,IAAI,EAAE,OAAO,EAAE,IAAI;QACnB,SAAS,EAAE,OAAO,EAAE,KAAK;QACzB,QAAQ,EAAE,OAAO,EAAE,IAAI;KACxB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC,CAAC;IAEvF,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,CAAC;IACxC,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,QAAQ,CAAC;IACzC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAE1B,MAAM,WAAW,GAAG;QAClB,SAAS;QACT,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC;QACtC,6CAA6C;QAC7C,KAAK;YACH,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,UAAU,CAAC;YAC9E,CAAC,CAAC,KAAK;gBACL,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,EAAE,UAAU,CAAC;gBAC1F,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,UAAU,CAAC;QACvE,mBAAmB;QACnB,KAAK;YACH,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC;YACnE,CAAC,CAAC,KAAK;gBACL,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC;gBAC/E,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC;QAC5D,iBAAiB;QACjB,KAAK;YACH,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,4BAA4B,CAAC;YAC/E,CAAC,CAAC,KAAK;gBACL,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,QAAQ,EAAE,4BAA4B,CAAC;gBAC3F,CAAC,CAAC,EAAE;KACT,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAElB,MAAM,SAAS,GAAG;QAChB,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,CAAC,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAE,KAAK,CAAC;KACnD,CAAC;IAEF,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,IAAI,CAAC;YACH,IAAI,UAAU,GAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YAEzC,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC5B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;gBAClD,2CAA2C;gBAC3C,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;oBACb,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACjC,CAAC;gBACD,IAAI,CAAC,UAAU,CAAC,UAAU;oBAAE,UAAU,CAAC,UAAU,GAAG,EAAE,CAAC;YACzD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,gEAAgE;gBAChE,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;gBACrC,IAAI,CAAC;oBACH,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,CAAC;gBAAC,MAAM,CAAC;oBACP,iDAAiD;oBACjD,SAAS;gBACX,CAAC;YACH,CAAC;YAED,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC;YAE/C,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YAC5E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAC,CAAC;YACjE,YAAY,EAAE,CAAC;QACjB,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,UAAU,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,6BAA6B,YAAY,mBAAmB,CAAC,CAAC,CAAC;QAC5F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,uFAAuF,CAAC,CAAC,CAAC;IACpH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,8DAA8D,CAAC,CAAC,CAAC;QAC1F,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;AACH,CAAC"}
|
|
@@ -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"}
|
|
@@ -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,
|
|
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"}
|
package/dist/commands/refresh.js
CHANGED
|
@@ -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
|
-
|
|
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":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,
|
|
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;
|
|
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"}
|
package/dist/commands/status.js
CHANGED
|
@@ -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 —
|
|
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;
|
|
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;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;;;;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,qEAAqE;QACrE,yEAAyE;QACzE,0DAA0D;QAC1D,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,0CAA0C,CAAC,CAAC,CAAC;IACzE,MAAM,YAAY,GAAG,MAAM,wBAAwB,CAAC,aAAa,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,IAAI,UAAU,MAAM,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,SAAS,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,YAAY,IAAI,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC;IACrO,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,qCAAqC,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1J,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IACvC,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"}
|
|
@@ -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
|
|
51
|
-
*
|
|
52
|
-
* uncommitted file therefore changes the fingerprint
|
|
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;
|
|
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
|
|
116
|
-
*
|
|
117
|
-
* uncommitted file therefore changes the fingerprint
|
|
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
|
-
|
|
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
|
|
140
|
-
if (
|
|
136
|
+
const entries = parsePorcelainZ(statusOut);
|
|
137
|
+
if (entries.length === 0) {
|
|
141
138
|
return `${prefix}${sha}`;
|
|
142
139
|
}
|
|
143
|
-
|
|
144
|
-
for (const
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
151
|
-
|
|
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
|
-
|
|
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 =
|
|
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":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
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\
|
|
86
|
+
return { stdout: ' M src/file1.ts\0' };
|
|
85
87
|
}));
|
|
86
|
-
vi.mocked(fs.
|
|
88
|
+
vi.mocked(fs.readFile).mockResolvedValue(Buffer.from('first'));
|
|
87
89
|
const fp = await getRepoFingerprint('/ws/repo-1');
|
|
88
|
-
|
|
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\
|
|
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.
|
|
133
|
+
vi.mocked(fs.readFile).mockResolvedValue(Buffer.from('aaaa'));
|
|
108
134
|
const before = await getRepoFingerprint('/ws/repo-1');
|
|
109
|
-
vi.mocked(fs.
|
|
135
|
+
vi.mocked(fs.readFile).mockResolvedValue(Buffer.from('bbbb'));
|
|
110
136
|
const after = await getRepoFingerprint('/ws/repo-1');
|
|
111
|
-
|
|
112
|
-
|
|
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'));
|