@contorium/mcp 0.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 +97 -0
- package/bin/contorium-mcp.js +34 -0
- package/dist/autoContext.d.ts +2 -0
- package/dist/autoContext.js +2 -0
- package/dist/bootstrapCli.d.ts +2 -0
- package/dist/bootstrapCli.js +21 -0
- package/dist/conflicts.d.ts +19 -0
- package/dist/conflicts.js +49 -0
- package/dist/dashboardEnsure.d.ts +10 -0
- package/dist/dashboardEnsure.js +41 -0
- package/dist/intelligence.d.ts +16 -0
- package/dist/intelligence.js +38 -0
- package/dist/intentGraph.d.ts +20 -0
- package/dist/intentGraph.js +51 -0
- package/dist/mcpBootstrap.d.ts +8 -0
- package/dist/mcpBootstrap.js +81 -0
- package/dist/memoryStore.d.ts +18 -0
- package/dist/memoryStore.js +57 -0
- package/dist/paths.d.ts +12 -0
- package/dist/paths.js +66 -0
- package/dist/runtimeState.d.ts +14 -0
- package/dist/runtimeState.js +36 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +567 -0
- package/dist/stateBuilder.d.ts +16 -0
- package/dist/stateBuilder.js +40 -0
- package/dist/understanding.d.ts +1 -0
- package/dist/understanding.js +1 -0
- package/dist/workspace.d.ts +12 -0
- package/dist/workspace.js +40 -0
- package/dist/workspaceConfig.d.ts +14 -0
- package/dist/workspaceConfig.js +80 -0
- package/node_modules/@contora/state-core/dist/adapterSync.d.ts +29 -0
- package/node_modules/@contora/state-core/dist/adapterSync.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/adapterSync.js +142 -0
- package/node_modules/@contora/state-core/dist/adapters.d.ts +20 -0
- package/node_modules/@contora/state-core/dist/adapters.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/adapters.js +24 -0
- package/node_modules/@contora/state-core/dist/bootstrap/bootstrapState.d.ts +6 -0
- package/node_modules/@contora/state-core/dist/bootstrap/bootstrapState.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/bootstrap/bootstrapState.js +116 -0
- package/node_modules/@contora/state-core/dist/bootstrapArtifacts.d.ts +18 -0
- package/node_modules/@contora/state-core/dist/bootstrapArtifacts.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/bootstrapArtifacts.js +43 -0
- package/node_modules/@contora/state-core/dist/bootstrapState.d.ts +6 -0
- package/node_modules/@contora/state-core/dist/bootstrapState.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/bootstrapState.js +60 -0
- package/node_modules/@contora/state-core/dist/dashboardActivity.d.ts +12 -0
- package/node_modules/@contora/state-core/dist/dashboardActivity.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/dashboardActivity.js +58 -0
- package/node_modules/@contora/state-core/dist/dualMode.d.ts +11 -0
- package/node_modules/@contora/state-core/dist/dualMode.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/dualMode.js +38 -0
- package/node_modules/@contora/state-core/dist/gitScan.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/gitScan.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/gitScan.js +39 -0
- package/node_modules/@contora/state-core/dist/index.d.ts +44 -0
- package/node_modules/@contora/state-core/dist/index.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/index.js +141 -0
- package/node_modules/@contora/state-core/dist/minimalSnapshot.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/minimalSnapshot.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/minimalSnapshot.js +60 -0
- package/node_modules/@contora/state-core/dist/scanner/gitScan.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/scanner/gitScan.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/scanner/gitScan.js +42 -0
- package/node_modules/@contora/state-core/dist/scanner/workspaceScanner.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/scanner/workspaceScanner.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/scanner/workspaceScanner.js +148 -0
- package/node_modules/@contora/state-core/dist/semiAutoHandoff.d.ts +46 -0
- package/node_modules/@contora/state-core/dist/semiAutoHandoff.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/semiAutoHandoff.js +227 -0
- package/node_modules/@contora/state-core/dist/sourceMetadata.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/sourceMetadata.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/sourceMetadata.js +27 -0
- package/node_modules/@contora/state-core/dist/state-builder/buildFromScan.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/state-builder/buildFromScan.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/buildFromScan.js +33 -0
- package/node_modules/@contora/state-core/dist/state-builder/normalization.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/state-builder/normalization.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/normalization.js +107 -0
- package/node_modules/@contora/state-core/dist/state-builder/rebuildFromScan.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/state-builder/rebuildFromScan.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/rebuildFromScan.js +22 -0
- package/node_modules/@contora/state-core/dist/state-builder/snapshot.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/state-builder/snapshot.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/snapshot.js +53 -0
- package/node_modules/@contora/state-core/dist/state-builder/store.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/state-builder/store.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/store.js +99 -0
- package/node_modules/@contora/state-core/dist/state-builder/types.d.ts +18 -0
- package/node_modules/@contora/state-core/dist/state-builder/types.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/state-builder/types.js +20 -0
- package/node_modules/@contora/state-core/dist/types.d.ts +42 -0
- package/node_modules/@contora/state-core/dist/types.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/types.js +3 -0
- package/node_modules/@contora/state-core/dist/understanding/buildUnderstanding.d.ts +22 -0
- package/node_modules/@contora/state-core/dist/understanding/buildUnderstanding.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/buildUnderstanding.js +87 -0
- package/node_modules/@contora/state-core/dist/understanding/changeDetector.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/understanding/changeDetector.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/changeDetector.js +68 -0
- package/node_modules/@contora/state-core/dist/understanding/chpHandoff.d.ts +49 -0
- package/node_modules/@contora/state-core/dist/understanding/chpHandoff.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/chpHandoff.js +214 -0
- package/node_modules/@contora/state-core/dist/understanding/extractor.d.ts +21 -0
- package/node_modules/@contora/state-core/dist/understanding/extractor.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/extractor.js +173 -0
- package/node_modules/@contora/state-core/dist/understanding/formatCanonicalExport.d.ts +30 -0
- package/node_modules/@contora/state-core/dist/understanding/formatCanonicalExport.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/formatCanonicalExport.js +363 -0
- package/node_modules/@contora/state-core/dist/understanding/formatHandoff.d.ts +20 -0
- package/node_modules/@contora/state-core/dist/understanding/formatHandoff.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/formatHandoff.js +57 -0
- package/node_modules/@contora/state-core/dist/understanding/graphBuilder.d.ts +9 -0
- package/node_modules/@contora/state-core/dist/understanding/graphBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/graphBuilder.js +107 -0
- package/node_modules/@contora/state-core/dist/understanding/handoffBuilder.d.ts +12 -0
- package/node_modules/@contora/state-core/dist/understanding/handoffBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/handoffBuilder.js +101 -0
- package/node_modules/@contora/state-core/dist/understanding/impactAnalyzer.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/understanding/impactAnalyzer.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/impactAnalyzer.js +58 -0
- package/node_modules/@contora/state-core/dist/understanding/intentFusion.d.ts +9 -0
- package/node_modules/@contora/state-core/dist/understanding/intentFusion.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/intentFusion.js +54 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/closureConstants.d.ts +24 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/closureConstants.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/closureConstants.js +33 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/confidence.d.ts +20 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/confidence.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/confidence.js +53 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/gitFrequency.d.ts +5 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/gitFrequency.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/gitFrequency.js +19 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/hotspotBuilder.d.ts +13 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/hotspotBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/hotspotBuilder.js +101 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/intentFunctionMapper.d.ts +22 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/intentFunctionMapper.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/intentFunctionMapper.js +106 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/knowledgeGraphBuilder.d.ts +23 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/knowledgeGraphBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/knowledgeGraphBuilder.js +415 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/normalize.d.ts +11 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/normalize.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/normalize.js +136 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/rebuildTrigger.d.ts +13 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/rebuildTrigger.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/rebuildTrigger.js +34 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/snapshotBuilder.d.ts +17 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/snapshotBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/snapshotBuilder.js +73 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/store.d.ts +7 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/store.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/store.js +127 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/types.d.ts +116 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/types.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/knowledgeGraph/types.js +6 -0
- package/node_modules/@contora/state-core/dist/understanding/miniGraph.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/understanding/miniGraph.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/miniGraph.js +18 -0
- package/node_modules/@contora/state-core/dist/understanding/store.d.ts +24 -0
- package/node_modules/@contora/state-core/dist/understanding/store.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/store.js +243 -0
- package/node_modules/@contora/state-core/dist/understanding/symbolValidator.d.ts +9 -0
- package/node_modules/@contora/state-core/dist/understanding/symbolValidator.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/symbolValidator.js +51 -0
- package/node_modules/@contora/state-core/dist/understanding/timelineTracker.d.ts +3 -0
- package/node_modules/@contora/state-core/dist/understanding/timelineTracker.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/timelineTracker.js +129 -0
- package/node_modules/@contora/state-core/dist/understanding/treeSitterParser.d.ts +24 -0
- package/node_modules/@contora/state-core/dist/understanding/treeSitterParser.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/treeSitterParser.js +56 -0
- package/node_modules/@contora/state-core/dist/understanding/types.d.ts +136 -0
- package/node_modules/@contora/state-core/dist/understanding/types.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/types.js +5 -0
- package/node_modules/@contora/state-core/dist/understanding/understandingGraphBuilder.d.ts +23 -0
- package/node_modules/@contora/state-core/dist/understanding/understandingGraphBuilder.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/understanding/understandingGraphBuilder.js +67 -0
- package/node_modules/@contora/state-core/dist/version.d.ts +3 -0
- package/node_modules/@contora/state-core/dist/version.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/version.js +21 -0
- package/node_modules/@contora/state-core/dist/workspaceScanner.d.ts +4 -0
- package/node_modules/@contora/state-core/dist/workspaceScanner.d.ts.map +1 -0
- package/node_modules/@contora/state-core/dist/workspaceScanner.js +112 -0
- package/node_modules/@contora/state-core/package.json +49 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @contorium/mcp
|
|
2
|
+
|
|
3
|
+
Standard MCP server for **Claude Code · Cursor · Codex · Gemini CLI**.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# global
|
|
9
|
+
npm install -g @contorium/mcp
|
|
10
|
+
|
|
11
|
+
# or one-shot
|
|
12
|
+
npx @contorium/mcp
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Monorepo dev (this repo):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
cd packages/mcp && npm run build
|
|
19
|
+
npx contorium-mcp --workspace /path/to/project
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Publish to npm
|
|
23
|
+
|
|
24
|
+
Only **one** npm package is required: `@contorium/mcp`.
|
|
25
|
+
`@contora/state-core` is **bundled inside** the tarball (no separate `@contora` org needed).
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm login # once
|
|
29
|
+
npm run publish:npm # publish @contorium/mcp
|
|
30
|
+
npm run publish:npm:dry-run # validate tarball without login
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Bootstrap (without starting stdio server)
|
|
34
|
+
|
|
35
|
+
Pre-sync `.contora` and schedule dashboard before opening the AI host:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx contorium-mcp bootstrap --workspace /path/to/your-project
|
|
39
|
+
# or after global install:
|
|
40
|
+
contorium-mcp bootstrap
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Start (stdio MCP server)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx contorium-mcp
|
|
47
|
+
# or with explicit workspace
|
|
48
|
+
npx contorium-mcp --workspace E:/your-project
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Workspace priority:** `--workspace` → `CONTORIUM_WORKSPACE` → `.mcp.json` → current directory.
|
|
52
|
+
|
|
53
|
+
## MCP host config
|
|
54
|
+
|
|
55
|
+
### Cursor / Claude (`.mcp.json`)
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"mcpServers": {
|
|
60
|
+
"contorium": {
|
|
61
|
+
"command": "npx",
|
|
62
|
+
"args": ["@contorium/mcp"],
|
|
63
|
+
"env": {
|
|
64
|
+
"CONTORIUM_WORKSPACE": "E:/your-project"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Codex (`config.toml`)
|
|
72
|
+
|
|
73
|
+
```toml
|
|
74
|
+
[mcp_servers.contorium]
|
|
75
|
+
command = "npx"
|
|
76
|
+
args = ["@contorium/mcp"]
|
|
77
|
+
env = { CONTORIUM_WORKSPACE = "." }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Standard tools (MCP v1)
|
|
81
|
+
|
|
82
|
+
| Tool | Purpose |
|
|
83
|
+
|------|---------|
|
|
84
|
+
| `get_handoff_injection_status` | Semi-auto new-chat prompt |
|
|
85
|
+
| `confirm_handoff_injection` | User confirmed (Y) |
|
|
86
|
+
| `skip_handoff_injection` | User declined (N) |
|
|
87
|
+
| `get_project_handoff` | CHP v1 AI memory (compact / markdown / json) |
|
|
88
|
+
| `get_recent_changes` | File & function updates |
|
|
89
|
+
| `get_understanding_graph` | Call chains + impact |
|
|
90
|
+
| `get_runtime_state` | Bootstrap / dashboard / session |
|
|
91
|
+
|
|
92
|
+
Legacy tools (`get_project_change`, `get_project_graph`, …) remain available.
|
|
93
|
+
|
|
94
|
+
## Requirements
|
|
95
|
+
|
|
96
|
+
- Node.js 18+
|
|
97
|
+
- Optional: `@contora/cli` (`npm i -g @contora/cli`) for dashboard bootstrap when not in monorepo
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
|
|
5
|
+
* @contorium/mcp — standard npm entry (npx contorium-mcp / npx @contorium/mcp)
|
|
6
|
+
|
|
7
|
+
* Workspace: --workspace > CONTORIUM_WORKSPACE > .mcp.json > cwd
|
|
8
|
+
|
|
9
|
+
*
|
|
10
|
+
|
|
11
|
+
* Subcommands:
|
|
12
|
+
|
|
13
|
+
* contorium-mcp bootstrap [--workspace PATH] — sync .contora + schedule dashboard (no stdio server)
|
|
14
|
+
|
|
15
|
+
* contorium-mcp — start MCP stdio server (default)
|
|
16
|
+
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const sub = process.argv[2];
|
|
20
|
+
|
|
21
|
+
if (sub === 'bootstrap') {
|
|
22
|
+
|
|
23
|
+
const { runMcpBootstrapCli } = await import('../dist/bootstrapCli.js');
|
|
24
|
+
|
|
25
|
+
await runMcpBootstrapCli(process.argv.slice(2));
|
|
26
|
+
|
|
27
|
+
} else {
|
|
28
|
+
|
|
29
|
+
const { startMcpServer } = await import('../dist/server.js');
|
|
30
|
+
|
|
31
|
+
await startMcpServer();
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { prepareHandoffInjection, syncWorkspaceState } from '@contora/state-core';
|
|
2
|
+
import { scheduleMcpRuntimeBootstrap } from './dashboardEnsure.js';
|
|
3
|
+
import { findWorkspaceRoot, initWorkspaceFromArgv, resolveWorkspaceRoot } from './paths.js';
|
|
4
|
+
/** `contorium-mcp bootstrap` — one-shot runtime sync without starting stdio MCP. */
|
|
5
|
+
export async function runMcpBootstrapCli(argv) {
|
|
6
|
+
initWorkspaceFromArgv(argv);
|
|
7
|
+
const hint = resolveWorkspaceRoot();
|
|
8
|
+
const root = await findWorkspaceRoot(hint);
|
|
9
|
+
console.error(`[contorium-mcp] bootstrap workspace: ${root}`);
|
|
10
|
+
const result = await syncWorkspaceState(root, 'mcp', { forceArtifacts: true });
|
|
11
|
+
scheduleMcpRuntimeBootstrap(root);
|
|
12
|
+
const prep = await prepareHandoffInjection(root);
|
|
13
|
+
console.error(`[contorium-mcp] bootstrap: mode=${result.mode} artifacts=${result.created ? 'created' : 'updated'}`);
|
|
14
|
+
if (prep.shouldPrompt) {
|
|
15
|
+
console.error('[contorium-mcp] handoff: pending — new AI chat will auto-prompt (Enter/i · n skip in terminal, [?] in IDE)');
|
|
16
|
+
}
|
|
17
|
+
else if (prep.alreadyInjected) {
|
|
18
|
+
console.error('[contorium-mcp] handoff: already injected for this runtime');
|
|
19
|
+
}
|
|
20
|
+
console.error('[contorium-mcp] bootstrap complete — configure MCP host to spawn contorium-mcp for stdio server');
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface McpStateConflictSource {
|
|
2
|
+
source: string;
|
|
3
|
+
detail: string;
|
|
4
|
+
}
|
|
5
|
+
export interface McpStateConflict {
|
|
6
|
+
id: string;
|
|
7
|
+
type: string;
|
|
8
|
+
title: string;
|
|
9
|
+
sources: McpStateConflictSource[];
|
|
10
|
+
status: string;
|
|
11
|
+
action: string;
|
|
12
|
+
detectedAt: number;
|
|
13
|
+
}
|
|
14
|
+
export interface McpConflictsArtifact {
|
|
15
|
+
version: number;
|
|
16
|
+
generatedAt: number;
|
|
17
|
+
conflicts: McpStateConflict[];
|
|
18
|
+
}
|
|
19
|
+
export declare function loadStateConflicts(workspaceRoot: string): Promise<McpConflictsArtifact | null>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import { conflictsFile } from './paths.js';
|
|
3
|
+
export async function loadStateConflicts(workspaceRoot) {
|
|
4
|
+
const fp = conflictsFile(workspaceRoot);
|
|
5
|
+
try {
|
|
6
|
+
const text = await fs.readFile(fp, 'utf8');
|
|
7
|
+
const o = JSON.parse(text);
|
|
8
|
+
if (!o || o.version !== 1) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const conflicts = [];
|
|
12
|
+
if (Array.isArray(o.conflicts)) {
|
|
13
|
+
for (const item of o.conflicts) {
|
|
14
|
+
if (!item || typeof item !== 'object') {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const c = item;
|
|
18
|
+
const sources = [];
|
|
19
|
+
if (Array.isArray(c.sources)) {
|
|
20
|
+
for (const s of c.sources) {
|
|
21
|
+
if (s && typeof s === 'object' && typeof s.detail === 'string') {
|
|
22
|
+
sources.push({
|
|
23
|
+
source: String(s.source ?? 'unknown'),
|
|
24
|
+
detail: s.detail,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
conflicts.push({
|
|
30
|
+
id: typeof c.id === 'string' ? c.id : 'conf_unknown',
|
|
31
|
+
type: typeof c.type === 'string' ? c.type : 'unknown',
|
|
32
|
+
title: typeof c.title === 'string' ? c.title : 'Conflict',
|
|
33
|
+
sources,
|
|
34
|
+
status: typeof c.status === 'string' ? c.status : 'UNRESOLVED',
|
|
35
|
+
action: typeof c.action === 'string' ? c.action : 'Developer review required',
|
|
36
|
+
detectedAt: typeof c.detectedAt === 'number' ? c.detectedAt : 0,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
version: 1,
|
|
42
|
+
generatedAt: typeof o.generatedAt === 'number' ? o.generatedAt : 0,
|
|
43
|
+
conflicts,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface CliSpawnPlan {
|
|
2
|
+
command: string;
|
|
3
|
+
args: string[];
|
|
4
|
+
}
|
|
5
|
+
/** Resolve contorium CLI for bootstrap/wake — monorepo dev or global/npx when published. */
|
|
6
|
+
export declare function resolveContoriumSpawn(subcommand: string, workspaceRoot: string, extraArgs?: string[]): CliSpawnPlan;
|
|
7
|
+
/** CRBP — MCP client initialize → bootstrap runtime attach. */
|
|
8
|
+
export declare function scheduleMcpRuntimeBootstrap(workspaceRoot: string): void;
|
|
9
|
+
/** Activity update after bootstrap (file/git events). */
|
|
10
|
+
export declare function scheduleMcpDashboardWake(workspaceRoot: string, detail?: string): void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
/** Resolve contorium CLI for bootstrap/wake — monorepo dev or global/npx when published. */
|
|
6
|
+
export function resolveContoriumSpawn(subcommand, workspaceRoot, extraArgs = []) {
|
|
7
|
+
const root = path.resolve(workspaceRoot);
|
|
8
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const monorepoCli = path.resolve(here, '../../cli/bin/contorium.cjs');
|
|
10
|
+
if (fs.existsSync(monorepoCli)) {
|
|
11
|
+
return {
|
|
12
|
+
command: process.execPath,
|
|
13
|
+
args: [monorepoCli, subcommand, root, ...extraArgs],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
command: process.platform === 'win32' ? 'npx.cmd' : 'npx',
|
|
18
|
+
args: ['contorium', subcommand, root, ...extraArgs],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function spawnDetached(plan) {
|
|
22
|
+
const useShell = process.platform === 'win32' && !plan.args[0]?.endsWith('.cjs');
|
|
23
|
+
spawn(plan.command, plan.args, {
|
|
24
|
+
detached: true,
|
|
25
|
+
stdio: 'ignore',
|
|
26
|
+
windowsHide: true,
|
|
27
|
+
shell: useShell,
|
|
28
|
+
}).unref();
|
|
29
|
+
}
|
|
30
|
+
/** CRBP — MCP client initialize → bootstrap runtime attach. */
|
|
31
|
+
export function scheduleMcpRuntimeBootstrap(workspaceRoot) {
|
|
32
|
+
spawnDetached(resolveContoriumSpawn('bootstrap', workspaceRoot, ['--source', 'mcp']));
|
|
33
|
+
}
|
|
34
|
+
/** Activity update after bootstrap (file/git events). */
|
|
35
|
+
export function scheduleMcpDashboardWake(workspaceRoot, detail) {
|
|
36
|
+
const extra = ['--source', 'mcp'];
|
|
37
|
+
if (detail) {
|
|
38
|
+
extra.push('--detail', detail);
|
|
39
|
+
}
|
|
40
|
+
spawnDetached(resolveContoriumSpawn('dashboard', workspaceRoot, ['wake', ...extra]));
|
|
41
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface McpStateSummary {
|
|
2
|
+
version: number;
|
|
3
|
+
generatedAt: number;
|
|
4
|
+
project_intent: string;
|
|
5
|
+
current_focus: string;
|
|
6
|
+
active_domains: string[];
|
|
7
|
+
active_problem_area: string;
|
|
8
|
+
activity_clusters: Array<{
|
|
9
|
+
cluster: string;
|
|
10
|
+
files: string[];
|
|
11
|
+
weight: number;
|
|
12
|
+
}>;
|
|
13
|
+
next_likely_actions: string[];
|
|
14
|
+
confidence: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function loadProjectIntelligence(workspaceRoot: string): Promise<McpStateSummary | null>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import { stateSummaryFile } from './paths.js';
|
|
3
|
+
export async function loadProjectIntelligence(workspaceRoot) {
|
|
4
|
+
const fp = stateSummaryFile(workspaceRoot);
|
|
5
|
+
try {
|
|
6
|
+
const text = await fs.readFile(fp, 'utf8');
|
|
7
|
+
const o = JSON.parse(text);
|
|
8
|
+
if (!o || typeof o !== 'object' || o.version !== 1) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
version: 1,
|
|
13
|
+
generatedAt: typeof o.generatedAt === 'number' ? o.generatedAt : 0,
|
|
14
|
+
project_intent: typeof o.project_intent === 'string' ? o.project_intent : '',
|
|
15
|
+
current_focus: typeof o.current_focus === 'string' ? o.current_focus : '',
|
|
16
|
+
active_domains: Array.isArray(o.active_domains)
|
|
17
|
+
? o.active_domains.filter((x) => typeof x === 'string')
|
|
18
|
+
: [],
|
|
19
|
+
active_problem_area: typeof o.active_problem_area === 'string' ? o.active_problem_area : '',
|
|
20
|
+
activity_clusters: Array.isArray(o.activity_clusters)
|
|
21
|
+
? o.activity_clusters
|
|
22
|
+
.filter((x) => !!x && typeof x === 'object')
|
|
23
|
+
.map((c) => ({
|
|
24
|
+
cluster: typeof c.cluster === 'string' ? c.cluster : '',
|
|
25
|
+
files: Array.isArray(c.files) ? c.files.filter((f) => typeof f === 'string') : [],
|
|
26
|
+
weight: typeof c.weight === 'number' ? c.weight : 0,
|
|
27
|
+
}))
|
|
28
|
+
: [],
|
|
29
|
+
next_likely_actions: Array.isArray(o.next_likely_actions)
|
|
30
|
+
? o.next_likely_actions.filter((x) => typeof x === 'string')
|
|
31
|
+
: [],
|
|
32
|
+
confidence: typeof o.confidence === 'number' ? o.confidence : 0,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface McpIntentGraph {
|
|
2
|
+
version: number;
|
|
3
|
+
updatedAt: number;
|
|
4
|
+
nodes: Array<{
|
|
5
|
+
id: string;
|
|
6
|
+
text: string;
|
|
7
|
+
status: string;
|
|
8
|
+
confidence: number;
|
|
9
|
+
relatedFiles: string[];
|
|
10
|
+
lastUpdated: number;
|
|
11
|
+
learnedAt: number;
|
|
12
|
+
}>;
|
|
13
|
+
edges: Array<{
|
|
14
|
+
from: string;
|
|
15
|
+
to: string;
|
|
16
|
+
type: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export declare function loadIntentGraph(workspaceRoot: string): Promise<McpIntentGraph | null>;
|
|
20
|
+
export declare function activeIntentNodes(graph: McpIntentGraph, max?: number): McpIntentGraph['nodes'];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import { intentGraphFile } from './paths.js';
|
|
3
|
+
export async function loadIntentGraph(workspaceRoot) {
|
|
4
|
+
const fp = intentGraphFile(workspaceRoot);
|
|
5
|
+
try {
|
|
6
|
+
const text = await fs.readFile(fp, 'utf8');
|
|
7
|
+
const o = JSON.parse(text);
|
|
8
|
+
if (!o || typeof o !== 'object' || o.version !== 1) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
version: 1,
|
|
13
|
+
updatedAt: typeof o.updatedAt === 'number' ? o.updatedAt : 0,
|
|
14
|
+
nodes: Array.isArray(o.nodes)
|
|
15
|
+
? o.nodes
|
|
16
|
+
.filter((x) => !!x && typeof x === 'object')
|
|
17
|
+
.map((n) => ({
|
|
18
|
+
id: typeof n.id === 'string' ? n.id : '',
|
|
19
|
+
text: typeof n.text === 'string' ? n.text : '',
|
|
20
|
+
status: typeof n.status === 'string' ? n.status : 'PARTIAL',
|
|
21
|
+
confidence: typeof n.confidence === 'number' ? n.confidence : 0,
|
|
22
|
+
relatedFiles: Array.isArray(n.relatedFiles)
|
|
23
|
+
? n.relatedFiles.filter((f) => typeof f === 'string')
|
|
24
|
+
: [],
|
|
25
|
+
lastUpdated: typeof n.lastUpdated === 'number' ? n.lastUpdated : 0,
|
|
26
|
+
learnedAt: typeof n.learnedAt === 'number' ? n.learnedAt : 0,
|
|
27
|
+
}))
|
|
28
|
+
.filter((n) => n.id && n.text)
|
|
29
|
+
: [],
|
|
30
|
+
edges: Array.isArray(o.edges)
|
|
31
|
+
? o.edges
|
|
32
|
+
.filter((x) => !!x && typeof x === 'object')
|
|
33
|
+
.map((e) => ({
|
|
34
|
+
from: typeof e.from === 'string' ? e.from : '',
|
|
35
|
+
to: typeof e.to === 'string' ? e.to : '',
|
|
36
|
+
type: typeof e.type === 'string' ? e.type : 'RELATED_TO',
|
|
37
|
+
}))
|
|
38
|
+
.filter((e) => e.from && e.to)
|
|
39
|
+
: [],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function activeIntentNodes(graph, max = 8) {
|
|
47
|
+
return graph.nodes
|
|
48
|
+
.filter((n) => n.status === 'ACTIVE' || n.status === 'WEAKENING' || n.status === 'PARTIAL')
|
|
49
|
+
.sort((a, b) => b.confidence - a.confidence)
|
|
50
|
+
.slice(0, max);
|
|
51
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** MCP startup bootstrap. */
|
|
2
|
+
export declare function ensureWorkspaceBootstrapped(workspaceRoot: string): Promise<{
|
|
3
|
+
bootstrapped: boolean;
|
|
4
|
+
mode: string;
|
|
5
|
+
}>;
|
|
6
|
+
/** Light sync: 5s poll + watch events dir and git HEAD. */
|
|
7
|
+
export declare function startMcpLightSync(workspaceRoot: string): void;
|
|
8
|
+
export declare function stopMcpLightSync(): void;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { syncWorkspaceState } from '@contora/state-core';
|
|
4
|
+
import { scheduleMcpDashboardWake } from './dashboardEnsure.js';
|
|
5
|
+
import { checkActiveRuntime, confirmHandoffInjection, readHandoffInjectionState, syncInjectionWithRuntime, } from '@contora/state-core';
|
|
6
|
+
const CONTORA_EVENTS = '.contora/events';
|
|
7
|
+
const SYNC_MS = 5_000;
|
|
8
|
+
const DEBOUNCE_MS = 400;
|
|
9
|
+
let syncTimer;
|
|
10
|
+
let debounceTimer;
|
|
11
|
+
let eventsWatcher;
|
|
12
|
+
let gitHeadWatcher;
|
|
13
|
+
function scheduleReactiveSync(workspaceRoot) {
|
|
14
|
+
if (debounceTimer) {
|
|
15
|
+
clearTimeout(debounceTimer);
|
|
16
|
+
}
|
|
17
|
+
debounceTimer = setTimeout(() => {
|
|
18
|
+
debounceTimer = undefined;
|
|
19
|
+
void syncWorkspaceState(workspaceRoot, 'mcp')
|
|
20
|
+
.then(async () => {
|
|
21
|
+
scheduleMcpDashboardWake(workspaceRoot, 'mcp-reactive-sync');
|
|
22
|
+
await syncInjectionWithRuntime(workspaceRoot);
|
|
23
|
+
const { runtime_id } = await checkActiveRuntime(workspaceRoot);
|
|
24
|
+
const injection = await readHandoffInjectionState(workspaceRoot);
|
|
25
|
+
if (runtime_id &&
|
|
26
|
+
injection?.runtime_id === runtime_id &&
|
|
27
|
+
injection.status === 'injected') {
|
|
28
|
+
await confirmHandoffInjection(workspaceRoot, injection.format ?? 'markdown');
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
.catch(() => undefined);
|
|
32
|
+
}, DEBOUNCE_MS);
|
|
33
|
+
}
|
|
34
|
+
/** MCP startup bootstrap. */
|
|
35
|
+
export async function ensureWorkspaceBootstrapped(workspaceRoot) {
|
|
36
|
+
const result = await syncWorkspaceState(workspaceRoot, 'mcp', { forceArtifacts: true });
|
|
37
|
+
if (result.created) {
|
|
38
|
+
console.error('[contorium-mcp] bootstrap: created .contora/state.json (scan-driven)');
|
|
39
|
+
}
|
|
40
|
+
return { bootstrapped: result.created, mode: result.mode };
|
|
41
|
+
}
|
|
42
|
+
/** Light sync: 5s poll + watch events dir and git HEAD. */
|
|
43
|
+
export function startMcpLightSync(workspaceRoot) {
|
|
44
|
+
stopMcpLightSync();
|
|
45
|
+
const root = path.resolve(workspaceRoot);
|
|
46
|
+
syncTimer = setInterval(() => {
|
|
47
|
+
void syncWorkspaceState(root, 'mcp').catch(() => undefined);
|
|
48
|
+
}, SYNC_MS);
|
|
49
|
+
syncTimer.unref?.();
|
|
50
|
+
const eventsDir = path.join(root, CONTORA_EVENTS);
|
|
51
|
+
try {
|
|
52
|
+
fs.mkdirSync(eventsDir, { recursive: true });
|
|
53
|
+
eventsWatcher = fs.watch(eventsDir, () => scheduleReactiveSync(root));
|
|
54
|
+
eventsWatcher.unref?.();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
/* optional */
|
|
58
|
+
}
|
|
59
|
+
const gitHead = path.join(root, '.git', 'HEAD');
|
|
60
|
+
try {
|
|
61
|
+
gitHeadWatcher = fs.watch(gitHead, () => scheduleReactiveSync(root));
|
|
62
|
+
gitHeadWatcher.unref?.();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
/* not a git repo */
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function stopMcpLightSync() {
|
|
69
|
+
if (syncTimer) {
|
|
70
|
+
clearInterval(syncTimer);
|
|
71
|
+
syncTimer = undefined;
|
|
72
|
+
}
|
|
73
|
+
if (debounceTimer) {
|
|
74
|
+
clearTimeout(debounceTimer);
|
|
75
|
+
debounceTimer = undefined;
|
|
76
|
+
}
|
|
77
|
+
eventsWatcher?.close();
|
|
78
|
+
eventsWatcher = undefined;
|
|
79
|
+
gitHeadWatcher?.close();
|
|
80
|
+
gitHeadWatcher = undefined;
|
|
81
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type MemoryEntryType = 'note' | 'decision' | 'architecture';
|
|
2
|
+
export interface MemoryEntry {
|
|
3
|
+
value: string;
|
|
4
|
+
type: MemoryEntryType;
|
|
5
|
+
timestamp: number;
|
|
6
|
+
}
|
|
7
|
+
export interface MemoryFile {
|
|
8
|
+
version: 1;
|
|
9
|
+
entries: Record<string, MemoryEntry>;
|
|
10
|
+
}
|
|
11
|
+
export declare function storeMemory(workspaceRoot: string, key: string, value: string, type?: MemoryEntryType): Promise<{
|
|
12
|
+
success: true;
|
|
13
|
+
key: string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function getMemory(workspaceRoot: string, key: string): Promise<MemoryEntry | null>;
|
|
16
|
+
export declare function searchMemory(workspaceRoot: string, query: string): Promise<Array<{
|
|
17
|
+
key: string;
|
|
18
|
+
} & MemoryEntry>>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { mcpMemoryFile } from './paths.js';
|
|
4
|
+
function emptyFile() {
|
|
5
|
+
return { version: 1, entries: {} };
|
|
6
|
+
}
|
|
7
|
+
async function loadFile(workspaceRoot) {
|
|
8
|
+
const fp = mcpMemoryFile(workspaceRoot);
|
|
9
|
+
try {
|
|
10
|
+
const raw = await fs.readFile(fp, 'utf8');
|
|
11
|
+
const parsed = JSON.parse(raw);
|
|
12
|
+
if (!parsed || typeof parsed !== 'object' || !parsed.entries || typeof parsed.entries !== 'object') {
|
|
13
|
+
return emptyFile();
|
|
14
|
+
}
|
|
15
|
+
return { version: 1, entries: parsed.entries };
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return emptyFile();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function saveFile(workspaceRoot, data) {
|
|
22
|
+
const fp = mcpMemoryFile(workspaceRoot);
|
|
23
|
+
await fs.mkdir(path.dirname(fp), { recursive: true });
|
|
24
|
+
await fs.writeFile(fp, JSON.stringify(data, null, 2), 'utf8');
|
|
25
|
+
}
|
|
26
|
+
export async function storeMemory(workspaceRoot, key, value, type = 'note') {
|
|
27
|
+
const k = key.trim();
|
|
28
|
+
if (!k) {
|
|
29
|
+
throw new Error('key is required');
|
|
30
|
+
}
|
|
31
|
+
const file = await loadFile(workspaceRoot);
|
|
32
|
+
file.entries[k] = {
|
|
33
|
+
value,
|
|
34
|
+
type,
|
|
35
|
+
timestamp: Date.now(),
|
|
36
|
+
};
|
|
37
|
+
await saveFile(workspaceRoot, file);
|
|
38
|
+
return { success: true, key: k };
|
|
39
|
+
}
|
|
40
|
+
export async function getMemory(workspaceRoot, key) {
|
|
41
|
+
const file = await loadFile(workspaceRoot);
|
|
42
|
+
return file.entries[key.trim()] ?? null;
|
|
43
|
+
}
|
|
44
|
+
export async function searchMemory(workspaceRoot, query) {
|
|
45
|
+
const q = query.trim().toLowerCase();
|
|
46
|
+
if (!q) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const file = await loadFile(workspaceRoot);
|
|
50
|
+
const results = [];
|
|
51
|
+
for (const [key, entry] of Object.entries(file.entries)) {
|
|
52
|
+
if (key.toLowerCase().includes(q) || entry.value.toLowerCase().includes(q)) {
|
|
53
|
+
results.push({ key, ...entry });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return results.sort((a, b) => b.timestamp - a.timestamp).slice(0, 32);
|
|
57
|
+
}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Apply CLI --workspace before other resolution (call once at startup). */
|
|
2
|
+
export declare function initWorkspaceFromArgv(argv?: string[]): string;
|
|
3
|
+
/** Workspace root for MCP (priority: startup override → env → .mcp.json → cwd). */
|
|
4
|
+
export declare function resolveWorkspaceRoot(): string;
|
|
5
|
+
export declare function contoraDir(workspaceRoot: string): string;
|
|
6
|
+
export declare function mcpMemoryFile(workspaceRoot: string): string;
|
|
7
|
+
export declare function stateSummaryFile(workspaceRoot: string): string;
|
|
8
|
+
export declare function intentGraphFile(workspaceRoot: string): string;
|
|
9
|
+
export declare function projectStateFile(workspaceRoot: string): string;
|
|
10
|
+
export declare function projectSnapshotFile(workspaceRoot: string): string;
|
|
11
|
+
export declare function conflictsFile(workspaceRoot: string): string;
|
|
12
|
+
export declare function findWorkspaceRoot(startDir: string): Promise<string>;
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { resolveMcpStartupConfig, setStartupWorkspace } from './workspaceConfig.js';
|
|
4
|
+
const CONTORA_DATA_DIR = '.contora';
|
|
5
|
+
const LEGACY_DATA_DIR = '.context-recall';
|
|
6
|
+
/** Apply CLI --workspace before other resolution (call once at startup). */
|
|
7
|
+
export function initWorkspaceFromArgv(argv = process.argv.slice(2)) {
|
|
8
|
+
const config = resolveMcpStartupConfig(argv);
|
|
9
|
+
if (config.workspaceFromArgv) {
|
|
10
|
+
setStartupWorkspace(config.workspaceHint);
|
|
11
|
+
}
|
|
12
|
+
return config.workspaceHint;
|
|
13
|
+
}
|
|
14
|
+
/** Workspace root for MCP (priority: startup override → env → .mcp.json → cwd). */
|
|
15
|
+
export function resolveWorkspaceRoot() {
|
|
16
|
+
const config = resolveMcpStartupConfig();
|
|
17
|
+
return config.workspaceHint;
|
|
18
|
+
}
|
|
19
|
+
export function contoraDir(workspaceRoot) {
|
|
20
|
+
return path.join(workspaceRoot, CONTORA_DATA_DIR);
|
|
21
|
+
}
|
|
22
|
+
export function mcpMemoryFile(workspaceRoot) {
|
|
23
|
+
return path.join(contoraDir(workspaceRoot), 'mcp', 'memories.json');
|
|
24
|
+
}
|
|
25
|
+
export function stateSummaryFile(workspaceRoot) {
|
|
26
|
+
return path.join(contoraDir(workspaceRoot), 'intelligence', 'state-summary.json');
|
|
27
|
+
}
|
|
28
|
+
export function intentGraphFile(workspaceRoot) {
|
|
29
|
+
return path.join(contoraDir(workspaceRoot), 'intent-graph', 'graph.json');
|
|
30
|
+
}
|
|
31
|
+
export function projectStateFile(workspaceRoot) {
|
|
32
|
+
return path.join(contoraDir(workspaceRoot), 'state-builder', 'project-state.json');
|
|
33
|
+
}
|
|
34
|
+
export function projectSnapshotFile(workspaceRoot) {
|
|
35
|
+
return path.join(contoraDir(workspaceRoot), 'state-builder', 'project-snapshot.md');
|
|
36
|
+
}
|
|
37
|
+
export function conflictsFile(workspaceRoot) {
|
|
38
|
+
return path.join(contoraDir(workspaceRoot), 'state-engine', 'conflicts.json');
|
|
39
|
+
}
|
|
40
|
+
export async function findWorkspaceRoot(startDir) {
|
|
41
|
+
let dir = path.resolve(startDir);
|
|
42
|
+
for (let i = 0; i < 12; i++) {
|
|
43
|
+
const primary = path.join(dir, CONTORA_DATA_DIR, 'state.json');
|
|
44
|
+
const legacy = path.join(dir, LEGACY_DATA_DIR, 'state.json');
|
|
45
|
+
try {
|
|
46
|
+
await fs.access(primary);
|
|
47
|
+
return dir;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
/* continue */
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
await fs.access(legacy);
|
|
54
|
+
return dir;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
/* continue */
|
|
58
|
+
}
|
|
59
|
+
const parent = path.dirname(dir);
|
|
60
|
+
if (parent === dir) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
dir = parent;
|
|
64
|
+
}
|
|
65
|
+
return path.resolve(startDir);
|
|
66
|
+
}
|