klypix-mcp 1.54.0 → 1.55.0
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 -2
- package/bin/klypix-project-map.mjs +67 -0
- package/bin/klypix-worker.mjs +7 -3
- package/examples/github/klypix-project-map.yml +45 -0
- package/package.json +4 -3
- package/src/project-graph.mjs +41 -0
package/README.md
CHANGED
|
@@ -208,12 +208,26 @@ project_map_context {
|
|
|
208
208
|
Use `compare_to` with another project-relative graph artifact to add exact total node/edge deltas
|
|
209
209
|
and additions/removals from the two bounded query neighborhoods. Both paths are confined to the
|
|
210
210
|
declared project root; unsafe source paths are withheld; large or unsupported artifacts are
|
|
211
|
-
rejected.
|
|
211
|
+
rejected. When a returned brain card names an exact mapped source path, the structured response
|
|
212
|
+
also includes a review-only evidence-link proposal. It never promotes similarity into truth and
|
|
213
|
+
never writes graph facts or links into `brain.klypix`.
|
|
212
214
|
|
|
213
215
|
Graphify is the first compatible producer. KLYPIX reads artifacts that users generate separately;
|
|
214
216
|
it does not bundle, install, or run Graphify and does not imply a partnership. A compatible generic
|
|
215
217
|
`graph.json` works through the same provider-neutral boundary.
|
|
216
218
|
|
|
219
|
+
For a reproducible map artifact on every pull request and main-branch push, install the shipped
|
|
220
|
+
read-only workflow into a Git checkout:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
npx klypix-project-map setup-github /path/to/project
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The command refuses to overwrite an existing workflow unless `--force` is explicit. The installed
|
|
227
|
+
workflow has `contents: read`, pins every action by commit SHA, pins `graphifyy==0.9.33`, validates
|
|
228
|
+
the graph contract, and uploads `graphify-out/` as a 14-day build artifact. This is opt-in CI code:
|
|
229
|
+
the local MCP tool still never installs or launches Graphify.
|
|
230
|
+
|
|
217
231
|
---
|
|
218
232
|
|
|
219
233
|
## Supported hosts and their integration level
|
|
@@ -419,7 +433,7 @@ The MCP verbs below are what agents call. These are what **you** call:
|
|
|
419
433
|
| `brain_message` | Session-to-session coordination notes (24h TTL, never written into the brain) |
|
|
420
434
|
| `brain_sync` | Context Gateway: task capsule, active-task peers, exact-file overlap, one-time alerts, timing |
|
|
421
435
|
| `brain_connect` | Find and draw related-but-unlinked cards |
|
|
422
|
-
| `project_map_context` | Read-only, bounded code-graph evidence beside correction-aware brain context; Graphify artifacts are supported but never installed or run |
|
|
436
|
+
| `project_map_context` | Read-only, bounded code-graph evidence beside correction-aware brain context, with exact-path review proposals; Graphify artifacts are supported but never installed or run locally |
|
|
423
437
|
| `canvas_view` | Returns the board as a structured render spec plus a text summary, and declares an MCP Apps (SEP-1865) UI resource |
|
|
424
438
|
| `read_canvas` | A canvas as markdown (cards, connection graph, `[[links]]`, `#tags`) |
|
|
425
439
|
| `search_canvases` | Search across canvases by name and content |
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { discoverProjectGraph } from '../src/project-graph.mjs';
|
|
6
|
+
|
|
7
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const template = path.resolve(here, '..', 'examples', 'github', 'klypix-project-map.yml');
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
const command = args[0] || 'status';
|
|
11
|
+
const force = args.includes('--force');
|
|
12
|
+
const rootArg = args.find((value, index) => index > 0 && value !== '--force') || process.cwd();
|
|
13
|
+
|
|
14
|
+
function projectRoot(value) {
|
|
15
|
+
const root = fs.realpathSync(path.resolve(value));
|
|
16
|
+
if (!fs.statSync(root).isDirectory()) throw new Error('Project root is not a directory.');
|
|
17
|
+
return root;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function usage() {
|
|
21
|
+
console.log([
|
|
22
|
+
'KLYPIX Project Map',
|
|
23
|
+
'',
|
|
24
|
+
' klypix-project-map status [project]',
|
|
25
|
+
' klypix-project-map setup-github [project] [--force]',
|
|
26
|
+
'',
|
|
27
|
+
'setup-github installs a read-only, pinned GitHub Actions workflow. It never installs or runs a provider on your computer.',
|
|
28
|
+
].join('\n'));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
if (command === '--help' || command === '-h' || command === 'help') {
|
|
33
|
+
usage();
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
const root = projectRoot(rootArg);
|
|
37
|
+
if (command === 'status') {
|
|
38
|
+
const graph = discoverProjectGraph({ project: root });
|
|
39
|
+
const workflow = path.join(root, '.github', 'workflows', 'klypix-project-map.yml');
|
|
40
|
+
console.log(`Project: ${root}`);
|
|
41
|
+
console.log(`Graph artifact: ${graph.status === 'ready' ? `ready (${graph.artifact.graphJson})` : `missing (${graph.artifact.graphJson})`}`);
|
|
42
|
+
console.log(`GitHub workflow: ${fs.existsSync(workflow) ? 'installed' : 'not installed'}`);
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
if (command !== 'setup-github') {
|
|
46
|
+
usage();
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
if (!fs.existsSync(path.join(root, '.git'))) throw new Error('Run setup-github inside a Git checkout.');
|
|
50
|
+
const destination = path.join(root, '.github', 'workflows', 'klypix-project-map.yml');
|
|
51
|
+
const source = fs.readFileSync(template, 'utf8');
|
|
52
|
+
if (fs.existsSync(destination)) {
|
|
53
|
+
const current = fs.readFileSync(destination, 'utf8');
|
|
54
|
+
if (current === source) {
|
|
55
|
+
console.log(`Project Map workflow is already current: ${destination}`);
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
if (!force) throw new Error(`Workflow already exists with different contents: ${destination}\nReview it, then rerun with --force if replacement is intended.`);
|
|
59
|
+
}
|
|
60
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
61
|
+
fs.writeFileSync(destination, source, { encoding: 'utf8', flag: 'w' });
|
|
62
|
+
console.log(`Installed Project Map workflow: ${destination}`);
|
|
63
|
+
console.log('Commit the workflow when you are ready. Pull requests and main-branch pushes will produce a read-only Project Map artifact.');
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error(`Project Map: ${error?.message || error}`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
package/bin/klypix-worker.mjs
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
opBrainInsights, opBrainConnect, opBrainReconcile, opBrainGarden, opCreateCanvas, opAddToCanvas, opBrainNote, opBrainMessage, opBrainAsk, opBrainChallenge, opCanvasView, opBrainLens,
|
|
31
31
|
opBrainTaskContext,
|
|
32
32
|
} from '../src/klypix-core.mjs';
|
|
33
|
-
import { compareProjectGraphResults, projectGraphContextMarkdown, queryProjectGraph } from '../src/project-graph.mjs';
|
|
33
|
+
import { compareProjectGraphResults, projectGraphContextMarkdown, queryProjectGraph, suggestProjectGraphBrainLinks } from '../src/project-graph.mjs';
|
|
34
34
|
import { auditProject, compactAgentsBrief, linkProject, mcpServerEntry } from '../src/agent-rules.mjs';
|
|
35
35
|
import { createMcpPresence, KLYPIX_MCP_INSTRUCTIONS } from '../src/mcp-presence.mjs';
|
|
36
36
|
import {
|
|
@@ -309,10 +309,14 @@ server.registerTool('project_map_context', {
|
|
|
309
309
|
.filter(block => block.kind === 'text')
|
|
310
310
|
.map(block => block.text)
|
|
311
311
|
.join('\n\n');
|
|
312
|
+
const evidenceLinkProposals = suggestProjectGraphBrainLinks(graphResult, brainResult.context);
|
|
313
|
+
const proposalMarkdown = evidenceLinkProposals.length
|
|
314
|
+
? `\n\n## Exact-path evidence link proposals\n\n${evidenceLinkProposals.slice(0, 12).map(proposal => `- Review brain card \`${proposal.brainCardId}\` beside **${proposal.nodeLabel}** in \`${proposal.sourceFile}\`.`).join('\n')}\n\n_These are review proposals based only on an exact source-path mention. Nothing was written to the brain._`
|
|
315
|
+
: '';
|
|
312
316
|
return toContent({
|
|
313
|
-
blocks: [{ kind: 'text', text: `${graphMarkdown}\n\n---\n\n# Project Brain - ${deep_history ? 'decisions and history' : 'current decisions and corrections'}\n\n${brainMarkdown}` }],
|
|
317
|
+
blocks: [{ kind: 'text', text: `${graphMarkdown}\n\n---\n\n# Project Brain - ${deep_history ? 'decisions and history' : 'current decisions and corrections'}\n\n${brainMarkdown}${proposalMarkdown}` }],
|
|
314
318
|
isError: brainResult.isError,
|
|
315
|
-
structured: { projectGraph: graphResult, brainContext: brainResult.context || null, deepHistory: deep_history === true },
|
|
319
|
+
structured: { projectGraph: graphResult, brainContext: brainResult.context || null, evidenceLinkProposals, deepHistory: deep_history === true },
|
|
316
320
|
});
|
|
317
321
|
});
|
|
318
322
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: KLYPIX Project Map
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
pull_request:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: klypix-project-map-${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
env:
|
|
17
|
+
GRAPHIFY_VERSION: "0.9.33"
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
project-map:
|
|
21
|
+
name: Generate bounded map artifact
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 20
|
|
24
|
+
steps:
|
|
25
|
+
- name: Check out repository
|
|
26
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
27
|
+
|
|
28
|
+
- name: Set up uv
|
|
29
|
+
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
30
|
+
with:
|
|
31
|
+
enable-cache: true
|
|
32
|
+
|
|
33
|
+
- name: Generate code-only graph
|
|
34
|
+
run: uvx --from "graphifyy==${GRAPHIFY_VERSION}" graphify extract . --code-only
|
|
35
|
+
|
|
36
|
+
- name: Validate the generated contract
|
|
37
|
+
run: node -e "const fs=require('fs'); const p='graphify-out/graph.json'; const g=JSON.parse(fs.readFileSync(p,'utf8')); if(!Array.isArray(g.nodes)||!(Array.isArray(g.edges)||Array.isArray(g.links))) throw Error('unsupported graph contract'); console.log('Project Map:',g.nodes.length,'nodes');"
|
|
38
|
+
|
|
39
|
+
- name: Upload Project Map artifact
|
|
40
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
41
|
+
with:
|
|
42
|
+
name: klypix-project-map-${{ github.sha }}
|
|
43
|
+
path: graphify-out/
|
|
44
|
+
if-no-files-found: error
|
|
45
|
+
retention-days: 14
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "klypix-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.55.0",
|
|
4
4
|
"description": "Shared project brain and MCP coordination server for multi-agent coding.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"klypix-write": "bin/klypix-write.mjs",
|
|
44
44
|
"klypix-append": "bin/klypix-append.mjs",
|
|
45
45
|
"klypix-install": "bin/klypix-install.mjs",
|
|
46
|
-
"klypix-uninstall": "bin/klypix-uninstall.mjs"
|
|
46
|
+
"klypix-uninstall": "bin/klypix-uninstall.mjs",
|
|
47
|
+
"klypix-project-map": "bin/klypix-project-map.mjs"
|
|
47
48
|
},
|
|
48
49
|
"main": "index.mjs",
|
|
49
50
|
"exports": {
|
|
@@ -75,7 +76,7 @@
|
|
|
75
76
|
},
|
|
76
77
|
"scripts": {
|
|
77
78
|
"test:project-graph": "node test/project-graph.mjs",
|
|
78
|
-
"test": "node test/project-graph.mjs && node test/mcp-auto-update.mjs && node test/mcp-supervisor.mjs && node test/runtime-inspector.mjs && node test/codex-hooks.mjs && node test/agent-presence.mjs && node test/finding-routing.mjs && node test/finding-routing-hook.mjs && node test/presence-relay.mjs && node test/context-gateway.mjs && node test/conformance.mjs && node test/brain-doctor.mjs && node test/version-currency.mjs && node test/ship-capture.mjs && node test/lane-message.mjs && node test/brain-quality.mjs && node test/brain-connect-orphans.mjs && node test/brief-and-recall.mjs && node test/layout-cluster.mjs && node test/brain-ask.mjs && node test/field-report-2026-07-04.mjs && node test/autoprop.mjs && node test/overlay-recency-2026-07-12.mjs && node test/brain-challenge.mjs && node test/brain-lens.mjs && node test/brain-kind.mjs && node test/rule-drafts.mjs && node test/claim-engine.mjs && node test/skill-staleness.mjs && node test/canvas-view.mjs && node test/status-completeness.mjs && node test/semantic-gate.mjs && node test/memory-runtime.mjs && node test/semantic-cache.mjs && node test/decay-status.mjs && node test/decay-hook.mjs && node test/evidence-anchors.mjs && node test/presence-visibility.mjs && node test/merge-brains.mjs && node test/concurrent-writes.mjs && node test/a2a-smoke.mjs && node test/cli-args.mjs && node test/format-guard.mjs && node test/git-tools.mjs && node test/uninstall.mjs",
|
|
79
|
+
"test": "node test/project-graph.mjs && node test/project-map-cli.mjs && node test/mcp-auto-update.mjs && node test/mcp-supervisor.mjs && node test/runtime-inspector.mjs && node test/codex-hooks.mjs && node test/agent-presence.mjs && node test/finding-routing.mjs && node test/finding-routing-hook.mjs && node test/presence-relay.mjs && node test/context-gateway.mjs && node test/conformance.mjs && node test/brain-doctor.mjs && node test/version-currency.mjs && node test/ship-capture.mjs && node test/lane-message.mjs && node test/brain-quality.mjs && node test/brain-connect-orphans.mjs && node test/brief-and-recall.mjs && node test/layout-cluster.mjs && node test/brain-ask.mjs && node test/field-report-2026-07-04.mjs && node test/autoprop.mjs && node test/overlay-recency-2026-07-12.mjs && node test/brain-challenge.mjs && node test/brain-lens.mjs && node test/brain-kind.mjs && node test/rule-drafts.mjs && node test/claim-engine.mjs && node test/skill-staleness.mjs && node test/canvas-view.mjs && node test/status-completeness.mjs && node test/semantic-gate.mjs && node test/memory-runtime.mjs && node test/semantic-cache.mjs && node test/decay-status.mjs && node test/decay-hook.mjs && node test/evidence-anchors.mjs && node test/presence-visibility.mjs && node test/merge-brains.mjs && node test/concurrent-writes.mjs && node test/a2a-smoke.mjs && node test/cli-args.mjs && node test/format-guard.mjs && node test/git-tools.mjs && node test/uninstall.mjs",
|
|
79
80
|
"test:memory": "node test/memory-runtime.mjs",
|
|
80
81
|
"test:memory:soak": "node --expose-gc test/memory-soak.mjs",
|
|
81
82
|
"runtime": "node bin/klypix-runtime.mjs"
|
package/src/project-graph.mjs
CHANGED
|
@@ -343,6 +343,47 @@ export function compareProjectGraphResults(current, previous) {
|
|
|
343
343
|
};
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
function textContainsExactSourcePath(text, sourceFile) {
|
|
347
|
+
const haystack = String(text || '').replace(/\\/g, '/').toLocaleLowerCase('en-US');
|
|
348
|
+
const needle = String(sourceFile || '').replace(/\\/g, '/').toLocaleLowerCase('en-US');
|
|
349
|
+
if (!needle || !haystack.includes(needle)) return false;
|
|
350
|
+
const escaped = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
351
|
+
return new RegExp(`(^|[\\s\`'"([{<])${escaped}($|[\\s\`'"\\])}>.,;:#])`, 'i').test(haystack);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Deterministic proposals only. These are never persisted and never imply
|
|
356
|
+
* causality: an exact project-relative source path must appear in the brain
|
|
357
|
+
* card text before KLYPIX will suggest reviewing the pair.
|
|
358
|
+
*/
|
|
359
|
+
export function suggestProjectGraphBrainLinks(graphResult, brainContext, limit = 40) {
|
|
360
|
+
if (graphResult?.status !== 'ready' || !Array.isArray(graphResult.nodes)) return [];
|
|
361
|
+
const hits = Array.isArray(brainContext?.hits) ? brainContext.hits : [];
|
|
362
|
+
const proposals = [];
|
|
363
|
+
const seen = new Set();
|
|
364
|
+
for (const node of graphResult.nodes) {
|
|
365
|
+
if (!node?.sourceFile) continue;
|
|
366
|
+
for (const hit of hits) {
|
|
367
|
+
const texts = [hit?.text, hit?.correctedBy].filter(Boolean);
|
|
368
|
+
if (!texts.some(text => textContainsExactSourcePath(text, node.sourceFile))) continue;
|
|
369
|
+
const key = `${hit.id}\u0000${node.id}\u0000${node.sourceFile}`;
|
|
370
|
+
if (seen.has(key)) continue;
|
|
371
|
+
seen.add(key);
|
|
372
|
+
proposals.push({
|
|
373
|
+
brainCardId: hit.id,
|
|
374
|
+
brainArea: hit.area || 'Notes',
|
|
375
|
+
nodeId: node.id,
|
|
376
|
+
nodeLabel: node.label || node.id,
|
|
377
|
+
sourceFile: node.sourceFile,
|
|
378
|
+
basis: 'exact-source-path',
|
|
379
|
+
status: 'review-proposal',
|
|
380
|
+
});
|
|
381
|
+
if (proposals.length >= Math.max(1, Math.min(100, Number(limit) || 40))) return proposals;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return proposals;
|
|
385
|
+
}
|
|
386
|
+
|
|
346
387
|
export function projectGraphContextMarkdown(result) {
|
|
347
388
|
if (result.status === 'missing') {
|
|
348
389
|
return `# Project Map\n\nNo supported project graph was found at \`${result.artifact.graphJson}\`. KLYPIX did not install or run a provider. Generate the artifact with Graphify, then retry.`;
|