devsmind-mcp 2.4.0 ā 4.0.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 +317 -234
- package/dist/cli/activity.d.ts +9 -0
- package/dist/cli/activity.js +69 -0
- package/dist/cli/activity.js.map +1 -0
- package/dist/cli/describe.d.ts +31 -0
- package/dist/cli/describe.js +201 -0
- package/dist/cli/describe.js.map +1 -0
- package/dist/cli/diff.d.ts +14 -0
- package/dist/cli/diff.js +161 -0
- package/dist/cli/diff.js.map +1 -0
- package/dist/cli/embed.d.ts +6 -0
- package/dist/cli/embed.js +109 -0
- package/dist/cli/embed.js.map +1 -0
- package/dist/cli/extract-agent.d.ts +66 -0
- package/dist/cli/extract-agent.js +192 -0
- package/dist/cli/extract-agent.js.map +1 -0
- package/dist/cli/feedback.d.ts +11 -0
- package/dist/cli/feedback.js +90 -0
- package/dist/cli/feedback.js.map +1 -0
- package/dist/cli/index.js +139 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts +30 -0
- package/dist/cli/init.js +89 -18
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/integrations/memory-topics.d.ts +55 -0
- package/dist/cli/integrations/memory-topics.js +318 -0
- package/dist/cli/integrations/memory-topics.js.map +1 -0
- package/dist/cli/integrations/memory.d.ts +17 -6
- package/dist/cli/integrations/memory.js +52 -139
- package/dist/cli/integrations/memory.js.map +1 -1
- package/dist/cli/integrations/prompt.d.ts +8 -0
- package/dist/cli/integrations/prompt.js +24 -3
- package/dist/cli/integrations/prompt.js.map +1 -1
- package/dist/cli/integrations/registry.d.ts +26 -9
- package/dist/cli/integrations/registry.js +61 -30
- package/dist/cli/integrations/registry.js.map +1 -1
- package/dist/cli/llm-client.d.ts +116 -0
- package/dist/cli/llm-client.js +322 -0
- package/dist/cli/llm-client.js.map +1 -0
- package/dist/cli/rule.d.ts +22 -2
- package/dist/cli/rule.js +110 -34
- package/dist/cli/rule.js.map +1 -1
- package/dist/cli/runner.d.ts +21 -0
- package/dist/cli/runner.js +94 -276
- package/dist/cli/runner.js.map +1 -1
- package/dist/cli/sync-progress.d.ts +9 -0
- package/dist/cli/sync-progress.js +41 -0
- package/dist/cli/sync-progress.js.map +1 -0
- package/dist/cli/sync.js +5 -2
- package/dist/cli/sync.js.map +1 -1
- package/dist/cli/view.js +3 -2
- package/dist/cli/view.js.map +1 -1
- package/dist/cli/workflow.js +26 -20
- package/dist/cli/workflow.js.map +1 -1
- package/dist/db/activity-graph.d.ts +55 -0
- package/dist/db/activity-graph.js +314 -0
- package/dist/db/activity-graph.js.map +1 -0
- package/dist/db/activity.d.ts +221 -0
- package/dist/db/activity.js +348 -0
- package/dist/db/activity.js.map +1 -0
- package/dist/db/analyze.js +18 -6
- package/dist/db/analyze.js.map +1 -1
- package/dist/db/database.d.ts +654 -102
- package/dist/db/database.js +1911 -558
- package/dist/db/database.js.map +1 -1
- package/dist/db/edges.d.ts +24 -0
- package/dist/db/edges.js +84 -0
- package/dist/db/edges.js.map +1 -1
- package/dist/db/embedder.d.ts +39 -0
- package/dist/db/embedder.js +0 -0
- package/dist/db/embedder.js.map +1 -0
- package/dist/db/feedback.d.ts +128 -0
- package/dist/db/feedback.js +182 -0
- package/dist/db/feedback.js.map +1 -0
- package/dist/db/file-diff.d.ts +32 -0
- package/dist/db/file-diff.js +110 -0
- package/dist/db/file-diff.js.map +1 -0
- package/dist/db/grep.d.ts +78 -0
- package/dist/db/grep.js +475 -0
- package/dist/db/grep.js.map +1 -0
- package/dist/db/index-build.d.ts +75 -0
- package/dist/db/index-build.js +177 -0
- package/dist/db/index-build.js.map +1 -0
- package/dist/db/message-revert.d.ts +63 -0
- package/dist/db/message-revert.js +258 -0
- package/dist/db/message-revert.js.map +1 -0
- package/dist/db/revert.d.ts +31 -0
- package/dist/db/revert.js +108 -0
- package/dist/db/revert.js.map +1 -0
- package/dist/db/schema.d.ts +49 -4
- package/dist/db/schema.js +125 -73
- package/dist/db/schema.js.map +1 -1
- package/dist/db/search-index.d.ts +65 -0
- package/dist/db/search-index.js +74 -0
- package/dist/db/search-index.js.map +1 -0
- package/dist/db/staging.d.ts +91 -5
- package/dist/db/staging.js +148 -22
- package/dist/db/staging.js.map +1 -1
- package/dist/mcp/server.d.ts +29 -7
- package/dist/mcp/server.js +2637 -878
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/vendor/3d-force-graph.min.js +5 -0
- package/dist/mcp/vendor/force-graph.min.js +5 -0
- package/dist/mcp/vendor/model/model_int8.onnx +0 -0
- package/dist/mcp/vendor/model/vocab.txt +30522 -0
- package/dist/mcp/vendor/three.min.js +7 -0
- package/dist/mcp/view.css +419 -0
- package/dist/mcp/view.html +161 -0
- package/dist/mcp/view.js +245 -0
- package/dist/mcp/view_chat.js +382 -0
- package/dist/mcp/view_graph.js +576 -0
- package/dist/mcp/visualizer.d.ts +25 -2
- package/dist/mcp/visualizer.js +31 -4
- package/dist/mcp/visualizer.js.map +1 -1
- package/dist/utils/ast.d.ts +89 -0
- package/dist/utils/ast.js +378 -10
- package/dist/utils/ast.js.map +1 -1
- package/dist/utils/diff.d.ts +44 -0
- package/dist/utils/diff.js +78 -0
- package/dist/utils/diff.js.map +1 -0
- package/dist/utils/edit.d.ts +6 -0
- package/dist/utils/edit.js +47 -14
- package/dist/utils/edit.js.map +1 -1
- package/dist/utils/scanner.d.ts +6 -4
- package/dist/utils/scanner.js +18 -8
- package/dist/utils/scanner.js.map +1 -1
- package/dist/utils/tokenize.d.ts +45 -0
- package/dist/utils/tokenize.js +129 -0
- package/dist/utils/tokenize.js.map +1 -0
- package/dist/utils/version.d.ts +14 -0
- package/dist/utils/version.js +61 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +18 -5
- package/dist/mcp/visualizer_2d.html +0 -635
- package/dist/mcp/visualizer_3d.html +0 -613
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MEMORY_TOPICS = void 0;
|
|
4
|
+
exports.renderTopicFile = renderTopicFile;
|
|
5
|
+
exports.renderIndexLine = renderIndexLine;
|
|
6
|
+
exports.renderCombined = renderCombined;
|
|
7
|
+
exports.renderMemoryPrompt = renderMemoryPrompt;
|
|
8
|
+
const server_1 = require("../../mcp/server");
|
|
9
|
+
exports.MEMORY_TOPICS = [
|
|
10
|
+
{
|
|
11
|
+
name: 'devsmind',
|
|
12
|
+
title: 'DevsMind workflow contract',
|
|
13
|
+
description: 'The cross-cutting DevsMind workflow ā read before any code search, edit, or commit in a project with the DevsMind MCP server.',
|
|
14
|
+
hook: 'the full contract: session, search, edit, record.',
|
|
15
|
+
type: 'feedback',
|
|
16
|
+
body: server_1.DEVSMIND_INSTRUCTIONS,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'devsmind-edit-node-always',
|
|
20
|
+
title: 'Always write with edit_node',
|
|
21
|
+
description: 'Write every file with DevsMind edit_node ā never the built-in Edit/Write tools.',
|
|
22
|
+
hook: 'every file, every extension; never the built-in Edit/Write.',
|
|
23
|
+
type: 'feedback',
|
|
24
|
+
body: [
|
|
25
|
+
'`edit_node` is the write path for **every** file ā `.ts`, `.vue`, `.css`, `.json`, `.xml`, `.md`, `.py`, anything. Never reach for your own edit/write tool. Params are the ordinary ones: `file_path` + `old_string` + `new_string`; to create a new file pass `old_string: ""` and the whole file as `new_string`. If the edit creates exactly ONE new function/class, pass `description` in the same call to skip a later round trip ([[devsmind-commit-changes-contract]] would otherwise refuse the batch).',
|
|
26
|
+
'',
|
|
27
|
+
"**Why:** it traces where the text landed to the actual function/class changed, stages it, and answers with that node's callers ā a plain edit tool records nothing. Writes that land outside any function (markup, config, an import line) get no graph node; that is expected, not a failure, and the whole-file change is still staged for the local activity log.",
|
|
28
|
+
'',
|
|
29
|
+
"**How to apply:** `edit_node` is the write path for every file ā there is no second write tool to reach for instead.",
|
|
30
|
+
].join('\n'),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'devsmind-start-session-first',
|
|
34
|
+
title: 'start_session first',
|
|
35
|
+
description: 'Call start_session before your first WRITE ā session_id is required on every write, but read-only tools do NOT need one.',
|
|
36
|
+
hook: 'session_id is required on every DevsMind WRITE; reads (search_nodes, get_node_code, get_activity_log, etc.) do not need one.',
|
|
37
|
+
type: 'feedback',
|
|
38
|
+
body: [
|
|
39
|
+
'`start_session` mints a `session_id` that every WRITE tool (edit_node, commit_changes, and the other mutating calls) REQUIRES. Read-only tools (search_nodes, get_node_code, list_nodes, get_activity_log, and the other getters) do NOT need it ā search and read freely from the very first call, before start_session has even run. Never invent a session_id. On a resumed conversation that already called start_session earlier (visible in reloaded history), reuse that same id instead of starting a new one.',
|
|
40
|
+
'',
|
|
41
|
+
'**Why:** a session ties a request\'s WRITES together on the local Activity log and makes them revertable as a unit ā reads mutate nothing, so gating them buys nothing and only adds friction to the first thing an agent does (usually a search). `get_activity_log` additionally accepts `session_id` as its own OPTIONAL filter ("show me just this session\'s activity") ā do not default to passing your own conversation\'s session_id there just because you have it, or you\'ll silently scope an otherwise-broad query (e.g. "what did I do today") down to only this one conversation.',
|
|
42
|
+
'',
|
|
43
|
+
'**How to apply:** if a WRITE call errors saying session_id is required, start_session was skipped ā call it, then retry. Every response echoes the id back, so it stays visible across a long or compacted conversation. For get_activity_log, omit session_id unless you specifically want to filter to one session.',
|
|
44
|
+
].join('\n'),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'devsmind-search-nodes-before-grep',
|
|
48
|
+
title: 'search_nodes before grep',
|
|
49
|
+
description: 'Find code with search_nodes (query and/or pattern, a real regex) instead of grep or reading files ā it covers the graph AND a real file grep.',
|
|
50
|
+
hook: 'query and/or pattern (a real regex); covers graph + file grep.',
|
|
51
|
+
type: 'feedback',
|
|
52
|
+
body: [
|
|
53
|
+
"`search_nodes` is the one search call: it covers the indexed graph AND the raw filesystem, so an external grep is not needed. Two inputs, pass either or both ā a natural-language `query` (a real phrase, drives the semantic/vector layer) and/or `pattern` (a REAL regex, used exactly as you'd give grep ā not re-escaped, not split ā e.g. an identifier or \"item\\.liked\"). Pattern-only is a precision mode: exact grep + code-body matches, no semantic blur. Your own knowledge of the codebase (identifiers, error strings, config keys) makes a better pattern than tokenizing the query ever will.",
|
|
54
|
+
'',
|
|
55
|
+
'Two buckets come back:',
|
|
56
|
+
'- `nodes` (primary) ā functions/classes, each LEADING with `confidence` (high/medium/low), `relevance` and `found_by`, then `uses`/`used_by`/`history_count`; `nodes_total` is the true count before the top-20 cap.',
|
|
57
|
+
"- `files` (last resort) ā a real grep of every repo (or just `path`, if scoped), for what the graph doesn't model: CSS, JSON, `.env`, markup, wiring like \"where is CORS configured\". Sample lines report which function/class they fall inside. `files_total` is the true match count ā bigger than what's returned means there's more; pass `offset` for the next page.",
|
|
58
|
+
'',
|
|
59
|
+
"**Why:** empty buckets plus a `hint` mean the thing genuinely isn't there ā it never pads with guesses. `used_by: 0` carrying a `used_by_note` means \"unverified\", not \"dead code\". A capped page was silently indistinguishable from a complete result before `files_total`/`nodes_total` existed ā never assume \"not there\" from a short list alone. Triage on `confidence`, not on which node name reads plausibly: confidence is corroboration across independent search layers, which is evidence you cannot reconstruct by eye, and a name that merely looks right is the easiest way to pick the wrong node.",
|
|
60
|
+
'',
|
|
61
|
+
"**How to apply:** search before any grep/glob/file read. Retry once with a different pattern/query before giving up. Drop to a manual grep only if the response says `truncated: true`, or you need full file context after it points at the file. Lockfiles and build artifacts are excluded by default (`.env`, JSON and config are NOT ā those are what the files bucket is for); scoping `path` at an excluded file returns nothing and says so in `scope_note`, so read it directly rather than re-querying. A `compacted` field means the response was trimmed to fit and names what was dropped ā counts stay exact either way, and `compact:false` demands the full payload. See [[devsmind-get-node-graph]] for blast radius once you have a hit.",
|
|
62
|
+
].join('\n'),
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'devsmind-get-node-graph',
|
|
66
|
+
title: 'get_node_code graph params for callers and flows',
|
|
67
|
+
description: 'Before changing a signature or tracing a feature end to end, pass graph_depth/graph_direction on get_node_code ā "in" for the full caller blast radius, "out" + graph_code for a whole call flow.',
|
|
68
|
+
hook: 'graph_direction:"in" for blast radius, "out"+graph_code for a whole flow, in the SAME get_node_code call.',
|
|
69
|
+
type: 'feedback',
|
|
70
|
+
body: [
|
|
71
|
+
'There is no separate get_node_graph tool anymore ā `get_node_code` already includes direct callers/callees by name on every call (`uses_nodes`/`used_by_nodes`). `graph_depth` + `graph_direction` walk the TRANSITIVE graph past those, in that same call, answering the two questions git cannot:',
|
|
72
|
+
'- `graph_depth: 2-3` + `graph_direction: "in"` ā the full caller blast radius, not just direct callers. Use this BEFORE changing any signature or behavior.',
|
|
73
|
+
'- `graph_depth: 3` + `graph_direction: "out"` + `graph_code: true` ā the starting node plus everything it transitively calls, with current source, in ONE call. Use this for tracing a request/endpoint/feature end to end.',
|
|
74
|
+
'',
|
|
75
|
+
'**Why:** git shows what changed, never what depends on it. The "out"+`graph_code` combination replaces a long chain of `get_node_code` calls with a single round trip ā and depth 1 is already free, since direct neighbors come back on every call regardless of `graph_depth`.',
|
|
76
|
+
'',
|
|
77
|
+
'**How to apply:** never chain per-function code fetches when tracing a flow ā one `get_node_code` call with the right `graph_depth`/`graph_direction`/`graph_code` does it. When `graph.code_truncated: true`, check WHICH of the two causes applies, because only one is fixable: `graph.code_omitted_node_ids` names the nodes whose code exists but did not fit the budget (call `get_node_code` on exactly those, or re-issue with a bigger `graph_code_budget`), while `graph.nodes_no_code_available` counts nodes whose source genuinely could not be found ā raising the budget will never bring those back. If `graph.nodes_truncated: true`, the walk hit its 120-node cap before the queue emptied. Pairs with [[devsmind-search-nodes-before-grep]] (find the node) and [[devsmind-get-node-code-and-history]] (read it, and why it looks that way).',
|
|
78
|
+
].join('\n'),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'devsmind-get-node-code-and-history',
|
|
82
|
+
title: 'get_node_code ā the one node-read call',
|
|
83
|
+
description: 'Read one function with get_node_code instead of opening the file ā it already returns metadata, imports, named callers/callees, a file outline, and recent reasoning; pass history:"full" for the complete revision trail before refactoring.',
|
|
84
|
+
hook: 'one call: code + metadata + imports + named callers/callees + file outline + recent reasoning.',
|
|
85
|
+
type: 'feedback',
|
|
86
|
+
body: [
|
|
87
|
+
'`get_node_code` is the ONE node-read call ā no separate get_node_graph or get_node_history tool exists anymore, both folded in as params. It reads ONE function/class, live-parsed from disk ā cheaper than opening the whole file, and current, so trust it as-is. ALWAYS included, at no extra cost: `name`/`type`/`signature`/`description` (the node\'s own metadata ā `description` is the highest-signal field there is), `imports` (the file\'s ES import lines), `uses_nodes`/`used_by_nodes` (up to 20 named callers AND callees per direction, with `uses`/`used_by` always the TRUE count even when capped), `file_outline` (up to 40 OTHER declarations in the same file ā consts, types, sibling helpers, whether or not they\'re graph nodes), and `recent_history` (last 3 changes\' reasoning ONLY, no code).',
|
|
88
|
+
'',
|
|
89
|
+
'Reach further in the SAME call: `graph_depth`/`graph_direction` (default off) walks the TRANSITIVE graph past the always-included direct neighbors ā see [[devsmind-get-node-graph]]. `history:"full"` (default `"recent"`) returns EVERY revision with diffable before/after edits, pageable with `history_limit`/`history_offset` ā call it before refactoring anything with a non-trivial `history_count`.',
|
|
90
|
+
'',
|
|
91
|
+
'**Why:** git blame gives who and when; the actual decision context exists only in DevsMind history. Nothing else records why a change was made. And a bare function body alone does not say what its identifiers resolve to, who calls it, or what else lives nearby ā that used to send agents back to a raw file read for all three; `get_node_code` closes that gap itself now.',
|
|
92
|
+
'',
|
|
93
|
+
'**How to apply:** do not re-open the file after `get_node_code` for imports, "what calls this", or "what else is in this file" ā `imports`, `uses_nodes`/`used_by_nodes`, and `file_outline` already answer those. Every capped section says so honestly (`*_truncated`, `*_hint`) ā a hint means more is reachable in this SAME call (`neighbors_offset`, `graph_depth`, `history_offset`), not a dead end. `snapshot_outdated: true` means the graph disagrees with disk ā an `edit_node` on that node re-syncs it as a side effect. `source: "cached"` means the symbol was not found (renamed/moved/deleted) ā the `file_outline` still shows what IS in the file, so check there before assuming it vanished ā then verify and `rename_node` or `deprecate_node` ([[devsmind-never-delete-nodes]]).',
|
|
94
|
+
].join('\n'),
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'devsmind-get-activity-log',
|
|
98
|
+
title: 'get_activity_log for "what changed"',
|
|
99
|
+
description: 'For "what changed recently" or "which files did we touch", call get_activity_log ā the only source of the actual file list per commit; falls back to shared graph history when the local log is empty.',
|
|
100
|
+
hook: 'the one "what changed" tool, and the only source of the FILES touched; source:"auto" falls back to shared history, "both" adds teammates.',
|
|
101
|
+
type: 'feedback',
|
|
102
|
+
body: [
|
|
103
|
+
'`get_activity_log` answers "what changed", one entry per `commit_changes`. It replaced `get_recent_changes` / `get_developer_activity` / `get_changes_by_requirement` ā all three are removed. Filters compose (AND): `developer`, `session_id`, `since_hours` or `since`/`until`, `requirement_contains`.',
|
|
104
|
+
'',
|
|
105
|
+
'Each entry carries `files` (every file that commit touched), `node_ids`, `developer`, `created_at`, `request`, `summary`, `status`, `source`. The response also has `all_files` (every distinct file across the returned entries) and `total_matched` ā the pre-`limit` count, so a capped result is not mistaken for a complete one.',
|
|
106
|
+
'',
|
|
107
|
+
'It reads TWO stores. The local activity log is full-fidelity but gitignored, so it is EMPTY on a teammate\'s clone or your second machine; committed graph history is shared but lossier. `source` chooses: `"auto"` (default) reads local and falls back to graph history only when local is empty; `"both"` merges local with every session that did not run on this machine; `"local"` / `"graph"` force one. Graph-backed responses carry a `caveats` array ā `status` is always `"applied"` there, and `request` degrades to the reasoning\'s Requirement field.',
|
|
108
|
+
'',
|
|
109
|
+
'**Why:** it is the answer to "show me all the files you changed" (e.g. before writing tests against recent work). The graph tools know nodes, not the full file set of a commit. And the fallback is what makes the question answerable at all for someone who just cloned the repo.',
|
|
110
|
+
'',
|
|
111
|
+
'**How to apply:** use it for any "what did we change recently", "what did this ticket touch", "which files from this session" question ā the default `source:"auto"` is right almost always. Reach for `source:"both"` when you want TEAMMATES\' work too: once you have local activity of your own, `auto` stops at the local store and never consults shared history. `devsmind activity` and `devsmind view` ā Activity are the human-facing views of the local log ([[devsmind-cli-commands]]).',
|
|
112
|
+
].join('\n'),
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'devsmind-commit-changes-contract',
|
|
116
|
+
title: 'commit_changes contract',
|
|
117
|
+
description: 'commit_changes requires message + reasoning + feedback (all three) and refuses any batch containing an undescribed new node.',
|
|
118
|
+
hook: 'message + reasoning + feedback all required; new nodes need a description.',
|
|
119
|
+
type: 'feedback',
|
|
120
|
+
body: [
|
|
121
|
+
'`commit_changes` fails unless all THREE are present:',
|
|
122
|
+
'',
|
|
123
|
+
"1. `message` ā the user's request, verbatim, that led to this commit. Reuse the exact same text on later commits still answering that request; it merges them into one activity-log entry instead of splitting them.",
|
|
124
|
+
'2. `reasoning` ā ONE object (`what_changed`/`why`/`goal`) covering everything staged since the last commit, not one per edit.',
|
|
125
|
+
'3. `feedback` ā 5 string fields (`graph_problems`, `edge_problems`, `tools_used`, `dropped_and_why`, `devsmind_better`). Every field must be answered; `"none"` is allowed, but only after actually checking whether something in THIS task took an extra tool call, a guess, or a wrong turn. Never invent an issue to fill it.',
|
|
126
|
+
'',
|
|
127
|
+
'It also REFUSES any batch containing a brand-NEW node with no `description` (1-3 sentences of what it does and its domain concepts, in words a teammate might search by ā never a restatement of the name). Nothing staged is lost: describe it via `add_description` and retry the same call.',
|
|
128
|
+
'',
|
|
129
|
+
'**Why:** `edit_node` only stages; nothing reaches the graph or the activity log until commit. `feedback` is the only channel that improves DevsMind over time ā it routes to a local graph-fix queue and a product log ([[devsmind-graph-feedback-queue]]).',
|
|
130
|
+
'',
|
|
131
|
+
'**How to apply:** commit at natural checkpoints during a long task, and always before ending a turn with staged work. Pass `description` inline on [[devsmind-edit-node-always]] when the edit created exactly one new symbol. Noticed something worth reporting but are not committing right now? `add_feedback` takes the same 5 categories ON DEMAND ā any one or more, nothing required, no commit needed (see [[devsmind-graph-feedback-queue]]).',
|
|
132
|
+
].join('\n'),
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'devsmind-list-nodes-discovery',
|
|
136
|
+
title: 'list_nodes for discovery',
|
|
137
|
+
description: 'To enumerate what exists in a component or directory, call list_nodes rather than search_nodes or walking the file tree.',
|
|
138
|
+
hook: 'enumerate a component/directory instead of walking the tree.',
|
|
139
|
+
type: 'feedback',
|
|
140
|
+
body: [
|
|
141
|
+
'`list_nodes` is the discovery/enumeration call: all nodes for a component, module, or directory. Use it when the question is "what exists here", not "find the thing that does X" ā that one is [[devsmind-search-nodes-before-grep]].',
|
|
142
|
+
'',
|
|
143
|
+
'**Why:** search ranks by relevance and stops at the good hits; listing is exhaustive over a scope, which is what an audit or an onboarding sweep needs.',
|
|
144
|
+
'',
|
|
145
|
+
'**How to apply:** reach for it before reading a directory tree by hand, then drill in with `get_node_code` (its `graph_depth`/`graph_direction` params reach further from there). It is PAGED ā the answer is `{nodes, total, offset}`, where `total` is the true match count and `nodes` is at most `limit` (default 100, max 500). When `total` exceeds what came back, `truncated` and a `hint` name the exact next call; never read a short page as the complete set. Narrow with `type`/`file_path` in preference to paging through a whole repo. If a page is still too large the nodes come back as id/name/type/file_path only, with a `compacted` note ā `total` stays exact either way.',
|
|
146
|
+
].join('\n'),
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'devsmind-workflow-tools',
|
|
150
|
+
title: 'Workflow tools for multi-session work',
|
|
151
|
+
description: 'A workflow is a named log of how one piece of functionality grew ā bind your session to one so commits record onto it, and sync afterwards if you forgot.',
|
|
152
|
+
hook: 'bind the session; commits auto-log; workflow_sync fixes attribution afterwards.',
|
|
153
|
+
type: 'feedback',
|
|
154
|
+
body: [
|
|
155
|
+
'A workflow is a named, BACKWARD-LOOKING log of how one piece of functionality grew across many nodes and many sessions. You read it to learn how the code got this way. It is not a task list and nothing ever "completes".',
|
|
156
|
+
'',
|
|
157
|
+
'`start_session` tells you when there is a recent workflow worth continuing; otherwise `workflow_list` (with `query`, which matches name and description) finds one. Continue it with `workflow_bind`, then `workflow_get_context` to read the story ā steps in order, each with the reasoning behind it and the nodes it touched. `last_n` reads the tail, which is what catching up usually means.',
|
|
158
|
+
'',
|
|
159
|
+
'**Binding is local to YOUR session.** It never moves, pauses, or steals anyone else\'s, and two sessions can work different workflows ā or the same one ā at once. There is no project-wide "active workflow" any more; the old one synced through git and let one developer displace everybody else.',
|
|
160
|
+
'',
|
|
161
|
+
'The rest: `workflow_create`, `workflow_archive` (retire a thread without deleting it), `workflow_import` (turns existing flow/architecture `.md` docs into workflows).',
|
|
162
|
+
'',
|
|
163
|
+
"**Why:** a feature's decision history is invisible to git blame; starting fresh silently loses it. And research is the part nothing else keeps at all ā git has the diff, history has the per-node reasoning, but neither records what was evaluated and rejected.",
|
|
164
|
+
'',
|
|
165
|
+
"**How to apply:** once bound, `commit_changes` auto-logs a step ā you do NOT need `workflow_add_step` for ordinary code work. Call it for what a commit cannot express: a decision or research finding that changed no code, with the docs behind it via `doc_paths` (paths, never copies ā a path outside the repo is rejected because it would not exist for a teammate). If you worked while unbound or on the wrong thread, `workflow_sync` attaches it afterwards from your local activity log: it previews first and only writes with `confirm:true`, and re-running is a no-op. See [[devsmind-commit-changes-contract]].",
|
|
166
|
+
].join('\n'),
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: 'devsmind-graph-feedback-queue',
|
|
170
|
+
title: 'Graph feedback queue',
|
|
171
|
+
description: 'Fixing accumulated graph problems: read_graph_feedback, re-verify, fix, then mark_graph_feedback_processed.',
|
|
172
|
+
hook: 'read ā verify ā fix ā mark processed, or it never drains.',
|
|
173
|
+
type: 'feedback',
|
|
174
|
+
body: [
|
|
175
|
+
"The graph-problem reports collected by `commit_changes`' `feedback` param ā or reported directly, any time, via `add_feedback`'s `graph_problem`/`edge_problem` (no commit needed) ā drain through a supervised loop:",
|
|
176
|
+
'',
|
|
177
|
+
'1. `read_graph_feedback` ā every unprocessed report, clustered by (node_id, category), sorted by frequency. Start any batch graph-fix session here.',
|
|
178
|
+
'2. Re-verify against current code regardless of source. `confidence` ("confirmed" = evidence given, "suspected" = none) is a PRIORITY signal only ā reports go stale. `commit_changes`\' `feedback` is plain text with no evidence field, so anything sourced from it is always `suspected`; `add_feedback`\'s `graph_problem`/`edge_problem` is the only path that can produce `confirmed` ā and only because its evidence is VERIFIED FRESH at call time (file must exist, snippet must still be found in it), not self-reported.',
|
|
179
|
+
'3. Fix ā one `record_alias` / `link_nodes` / `merge_nodes` often resolves a whole cluster ([[devsmind-graph-maintenance-tools]]).',
|
|
180
|
+
"4. `mark_graph_feedback_processed` with those entry ids ā whether you fixed it or decided it doesn't apply. Otherwise the queue never drains.",
|
|
181
|
+
'',
|
|
182
|
+
"`flag_indexer_rule` records a candidate for a PERMANENT deterministic indexer rule when several reports turn out to be the same recurring pattern (e.g. a framework's generated-binding convention). It doesn't change the graph ā it's a note for a human, prioritized by `evidence_count`.",
|
|
183
|
+
'',
|
|
184
|
+
'**Why:** without step 4 the same cluster resurfaces forever; without step 2 you act on stale reports.',
|
|
185
|
+
'',
|
|
186
|
+
'**How to apply:** `devsmind feedback` (CLI) is the human-facing view of both this queue and the product-feedback log.',
|
|
187
|
+
].join('\n'),
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: 'devsmind-never-delete-nodes',
|
|
191
|
+
title: 'Never delete a node',
|
|
192
|
+
description: 'A renamed function goes through rename_node and a removed one through deprecate_node ā never delete a node.',
|
|
193
|
+
hook: 'rename_node / deprecate_node; deletion loses history forever.',
|
|
194
|
+
type: 'feedback',
|
|
195
|
+
body: [
|
|
196
|
+
'A renamed function/class goes through `rename_node`. A removed one goes through `deprecate_node` ā never a delete.',
|
|
197
|
+
'',
|
|
198
|
+
"**Why:** deleting the node destroys its recorded history ā the reasoning behind every past change ā and nothing can recover it. Not git, not a reindex.",
|
|
199
|
+
'',
|
|
200
|
+
'**How to apply:** if `get_node_code` comes back with `source: "cached"`, the symbol is gone from disk ā verify what actually happened, then `rename_node` or `deprecate_node` rather than leaving the graph stale. See [[devsmind-get-node-code-and-history]].',
|
|
201
|
+
].join('\n'),
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'devsmind-graph-maintenance-tools',
|
|
205
|
+
title: 'Graph maintenance tools',
|
|
206
|
+
description: 'Repairing the graph itself ā analyze_graph (includes orphan detection), recheck_graph, merge/split/link_nodes, record_alias, create_missing_node.',
|
|
207
|
+
hook: 'analyze (incl. orphans)/recheck plus merge, split, link, record_alias.',
|
|
208
|
+
type: 'reference',
|
|
209
|
+
body: [
|
|
210
|
+
'Maintenance surface, not day-to-day lookup:',
|
|
211
|
+
'',
|
|
212
|
+
'- `analyze_graph` ā zero-token local health check (god entities, cycles, dangling edges, renames, AND orphaned nodes ā no separate orphan lookup tool exists). `fix: true` applies only the safe automatic fixes. CLI equivalent: `devsmind analyze`.',
|
|
213
|
+
'- `recheck_graph` ā drift and disconnection sweep, pruning spurious nodes.',
|
|
214
|
+
'- `merge_nodes` / `split_node` ā a node that was wrongly split, or wrongly lumped together.',
|
|
215
|
+
"- `link_nodes` ā a real connection the AST couldn't prove (dynamic dispatch, generated bindings).",
|
|
216
|
+
'- `record_alias` ā the same symbol known by another name; often fixes a whole feedback cluster at once.',
|
|
217
|
+
'- `create_missing_node` ā something real the indexer never picked up.',
|
|
218
|
+
'- `get_visualizer_url` ā the local URL for the interactive graph view: one page, Chat + Graph tabs, 2D/3D toggle inside Graph (`devsmind view`).',
|
|
219
|
+
'',
|
|
220
|
+
'These are the fixers the [[devsmind-graph-feedback-queue]] loop reaches for.',
|
|
221
|
+
].join('\n'),
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'devsmind-indexing-tools',
|
|
225
|
+
title: 'Indexing tools',
|
|
226
|
+
description: 'Indexing a workspace runs through index_start/index_checkpoint/index_continue/index_complete ā never an external script.',
|
|
227
|
+
hook: "index_start/checkpoint/continue/complete natively; don't pause mid-index.",
|
|
228
|
+
type: 'feedback',
|
|
229
|
+
body: [
|
|
230
|
+
'Indexing runs through the MCP tools: `index_start` ā `index_checkpoint` ā `index_continue` ā `index_complete`. No external scripts.',
|
|
231
|
+
'',
|
|
232
|
+
'**Why:** the checkpoint/continue pair is what makes progress survive a context reset ā a script-driven index loses everything on a restart.',
|
|
233
|
+
'',
|
|
234
|
+
'**How to apply:** don\'t pause mid-index for confirmation; keep going until the workspace is indexed or the context limit is hit. `devsmind index` (first run) and `devsmind reindex` (incremental, for manual changes made outside `edit_node`) are the CLI counterparts ([[devsmind-cli-commands]]).',
|
|
235
|
+
].join('\n'),
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: 'devsmind-cli-commands',
|
|
239
|
+
title: 'devsmind CLI commands',
|
|
240
|
+
description: 'What the human-facing devsmind CLI offers ā setup, graph maintenance, and reviewing recorded work.',
|
|
241
|
+
hook: 'setup, graph, and review command surface.',
|
|
242
|
+
type: 'reference',
|
|
243
|
+
body: [
|
|
244
|
+
'`devsmind <cmd>`:',
|
|
245
|
+
'',
|
|
246
|
+
"**Setup** ā `init` (create/update a brain), `start`, `rule` (build + place the AI workspace rule), `mcp` (register the MCP server per tool), `memory` (seed a tool's agent-memory store).",
|
|
247
|
+
'',
|
|
248
|
+
'**Graph** ā `index` (first-time), `reindex` (incremental, for edits made outside `edit_node`), `sync` (pull committed graph + history from disk into the local brain.db), `analyze` (zero-AI health check), `describe` (backfill descriptions for nodes predating the requirement; safe to re-run), `embed` (local/offline vector embeddings, no LLM credentials; safe to re-run, `--force` for a model upgrade), `prune` (interactive permanent removal).',
|
|
249
|
+
'',
|
|
250
|
+
'**Review** ā `view` (D3 graph visualizer plus Activity/Chat tabs), `activity` (local session/message timeline), `feedback` (graph problems, product feedback, indexer-rule candidates), `diff <node_id>` (red/green with the recorded reasoning), `revert <node_id>` (undo an entity\'s most recent recorded edit), `workflow` / `workflow-import <path>`.',
|
|
251
|
+
'',
|
|
252
|
+
'The activity and feedback logs are LOCAL and gitignored ā never pushed. See [[devsmind-get-activity-log]].',
|
|
253
|
+
].join('\n'),
|
|
254
|
+
},
|
|
255
|
+
];
|
|
256
|
+
/** Map of slug ā title, for resolving [[links]] when topics get flattened into one document. */
|
|
257
|
+
const TITLES = Object.fromEntries(exports.MEMORY_TOPICS.map(t => [t.name, t.title]));
|
|
258
|
+
/** Resolve `[[slug]]` cross-links to plain titles ā meaningful only when each topic is its own file. */
|
|
259
|
+
function flattenLinks(body) {
|
|
260
|
+
return body.replace(/\[\[([a-z0-9-]+)\]\]/g, (_m, slug) => `"${TITLES[slug] ?? slug}"`);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* One topic as a standalone memory file: YAML frontmatter (name/description/type)
|
|
264
|
+
* + body. The `description` is the field a file-per-fact store ranks on when
|
|
265
|
+
* deciding what to load, so it must survive on its own without the body.
|
|
266
|
+
*/
|
|
267
|
+
function renderTopicFile(topic, header) {
|
|
268
|
+
return [
|
|
269
|
+
'---',
|
|
270
|
+
`name: ${topic.name}`,
|
|
271
|
+
`description: ${topic.description}`,
|
|
272
|
+
'metadata:',
|
|
273
|
+
` type: ${topic.type}`,
|
|
274
|
+
'---',
|
|
275
|
+
'',
|
|
276
|
+
header + topic.body.replace(/\n*$/, '\n'),
|
|
277
|
+
].join('\n');
|
|
278
|
+
}
|
|
279
|
+
/** One index line per topic, for the store's always-loaded index file. */
|
|
280
|
+
function renderIndexLine(topic) {
|
|
281
|
+
return `- [${topic.title}](${topic.name}.md) ā ${topic.hook}`;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Every topic flattened into ONE document ā for stores that load a single file
|
|
285
|
+
* (Antigravity Skills) rather than ranking many. The contract topic leads; the
|
|
286
|
+
* rest become `##` sections in registry order.
|
|
287
|
+
*/
|
|
288
|
+
function renderCombined(header) {
|
|
289
|
+
const [contract, ...rest] = exports.MEMORY_TOPICS;
|
|
290
|
+
return [
|
|
291
|
+
header + flattenLinks(contract.body),
|
|
292
|
+
'',
|
|
293
|
+
'## Tool playbook',
|
|
294
|
+
'',
|
|
295
|
+
...rest.flatMap(t => [`### ${t.title}`, '', flattenLinks(t.body), '']),
|
|
296
|
+
].join('\n').replace(/\n*$/, '\n');
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* The ONE thing `devsmind memory` prints ā a single block meant to be pasted directly into any
|
|
300
|
+
* AI chat and framed as an explicit "remember this" request, not written to a file on the user's
|
|
301
|
+
* behalf. Leads with the two rules that matter most (edit_node is the only write path; prefer
|
|
302
|
+
* search_nodes/get_node_code over grepping or opening files) so they survive even a skim, then
|
|
303
|
+
* carries the full live contract below ā the SAME `DEVSMIND_INSTRUCTIONS` text the MCP handshake
|
|
304
|
+
* and `devsmind rule` both use, so this can never quietly drift from what the server enforces.
|
|
305
|
+
*/
|
|
306
|
+
function renderMemoryPrompt() {
|
|
307
|
+
return [
|
|
308
|
+
"Please remember the following about working in this codebase ā it's the DevsMind MCP workflow, and it applies every time we work in a project with a DevsMind server:",
|
|
309
|
+
'',
|
|
310
|
+
'1. Always write files with the `edit_node` tool ā never your own built-in edit/write tool, whatever the file type.',
|
|
311
|
+
'2. Prefer `search_nodes` and `get_node_code` over grepping or opening files directly ā they already know this codebase\'s structure and history.',
|
|
312
|
+
'',
|
|
313
|
+
'The full contract, so nothing gets missed:',
|
|
314
|
+
'',
|
|
315
|
+
server_1.DEVSMIND_INSTRUCTIONS,
|
|
316
|
+
].join('\n');
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=memory-topics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-topics.js","sourceRoot":"","sources":["../../../src/cli/integrations/memory-topics.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `devsmind memory` ā
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* `devsmind memory` ā prints ONE natural-language block to paste into any AI chat, framed as an
|
|
3
|
+
* explicit "remember this" request. DevsMind writes nothing on your behalf.
|
|
4
|
+
*
|
|
5
|
+
* Why: research across all 9 tools DevsMind integrates with turned up the same finding stated
|
|
6
|
+
* independently in several of those tools' own docs ā background/automatic memory is
|
|
7
|
+
* discretionary by design (Windsurf, Codex, and Qwen say so outright; e.g. "auto-memory is
|
|
8
|
+
* best-effort, QWEN.md is guaranteed"), while an EXPLICIT in-chat request is the one thing that
|
|
9
|
+
* reliably lands. A silently-written file never crosses that trigger at all. And 5 of the 9 tools
|
|
10
|
+
* (Cursor, VS Code/Copilot, Windsurf, Kiro, Qwen) have no file DevsMind could safely write to in
|
|
11
|
+
* the first place ā hand-writing into an undocumented or auto-generated store risks corrupting
|
|
12
|
+
* it. So instead of maintaining 9 different internal file formats, this hands the user one prompt
|
|
13
|
+
* and lets each tool's own native memory feature do whatever it already does best with it.
|
|
14
|
+
*
|
|
15
|
+
* `--tool` only changes the framing line (which feature name to call out, e.g. "Cursor calls
|
|
16
|
+
* this Memories") ā the prompt itself, from `renderMemoryPrompt`, is the same for everyone.
|
|
8
17
|
*/
|
|
9
18
|
export declare function handleMemory(opts: {
|
|
10
19
|
path?: string;
|
|
20
|
+
print?: boolean;
|
|
21
|
+
tool?: string;
|
|
11
22
|
}): Promise<void>;
|
|
@@ -1,155 +1,68 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.handleMemory = handleMemory;
|
|
37
|
-
const path = __importStar(require("path"));
|
|
38
|
-
const config_1 = require("../../utils/config");
|
|
39
|
-
const server_1 = require("../../mcp/server");
|
|
40
4
|
const registry_1 = require("./registry");
|
|
5
|
+
const memory_topics_1 = require("./memory-topics");
|
|
41
6
|
const prompt_1 = require("./prompt");
|
|
42
|
-
const MEMORY_FILE_HEADER = '<!-- Seeded by `devsmind memory` ā the DevsMind team code-graph MCP server -->\n\n';
|
|
43
7
|
/**
|
|
44
|
-
* `devsmind memory` ā
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
8
|
+
* `devsmind memory` ā prints ONE natural-language block to paste into any AI chat, framed as an
|
|
9
|
+
* explicit "remember this" request. DevsMind writes nothing on your behalf.
|
|
10
|
+
*
|
|
11
|
+
* Why: research across all 9 tools DevsMind integrates with turned up the same finding stated
|
|
12
|
+
* independently in several of those tools' own docs ā background/automatic memory is
|
|
13
|
+
* discretionary by design (Windsurf, Codex, and Qwen say so outright; e.g. "auto-memory is
|
|
14
|
+
* best-effort, QWEN.md is guaranteed"), while an EXPLICIT in-chat request is the one thing that
|
|
15
|
+
* reliably lands. A silently-written file never crosses that trigger at all. And 5 of the 9 tools
|
|
16
|
+
* (Cursor, VS Code/Copilot, Windsurf, Kiro, Qwen) have no file DevsMind could safely write to in
|
|
17
|
+
* the first place ā hand-writing into an undocumented or auto-generated store risks corrupting
|
|
18
|
+
* it. So instead of maintaining 9 different internal file formats, this hands the user one prompt
|
|
19
|
+
* and lets each tool's own native memory feature do whatever it already does best with it.
|
|
20
|
+
*
|
|
21
|
+
* `--tool` only changes the framing line (which feature name to call out, e.g. "Cursor calls
|
|
22
|
+
* this Memories") ā the prompt itself, from `renderMemoryPrompt`, is the same for everyone.
|
|
50
23
|
*/
|
|
51
24
|
async function handleMemory(opts) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const scope = await (0, prompt_1.pickMemoryScope)(target);
|
|
76
|
-
const content = MEMORY_FILE_HEADER + server_1.DEVSMIND_INSTRUCTIONS;
|
|
77
|
-
const wrapped = scope.format === 'skill-md' && target.memory.wrap ? target.memory.wrap(content) : content;
|
|
78
|
-
if (mode === 'manual') {
|
|
79
|
-
printManual(target.label, scope, workspaceRoot);
|
|
80
|
-
console.log(`\nContent to place in that file:\n`);
|
|
81
|
-
console.log(indent(wrapped));
|
|
82
|
-
if (mem.pointerFile) {
|
|
83
|
-
console.log(`\nš” Also add one pointer line into ${mem.pointerFile.file} in the same folder`);
|
|
84
|
-
console.log(` (e.g. "See devsmind.md for the DevsMind workflow.") ā it loads on demand only.`);
|
|
85
|
-
}
|
|
86
|
-
return;
|
|
25
|
+
const target = await resolveTarget(opts);
|
|
26
|
+
if (!target)
|
|
27
|
+
return; // already reported: unknown --tool, or the interactive picker was cancelled
|
|
28
|
+
console.log(`\nā¹ļø ${target.label} calls this "${target.memory.featureName}".`);
|
|
29
|
+
if (target.memory.note)
|
|
30
|
+
console.log(` ${target.memory.note}`);
|
|
31
|
+
console.log(`\nš Paste this into your ${target.label} chat and ask it to remember it:\n`);
|
|
32
|
+
console.log(indent((0, memory_topics_1.renderMemoryPrompt)()));
|
|
33
|
+
console.log('');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* `--tool` resolves directly. Otherwise, an interactive TTY offers the same picker `devsmind
|
|
37
|
+
* rule`/`devsmind mcp` use (purely for the framing line ā nothing here depends on the answer
|
|
38
|
+
* the way file placement used to); a non-interactive/piped run ā or an explicit `--print` ā falls
|
|
39
|
+
* back to Claude Code's framing and says so, so scripted use never blocks on a prompt.
|
|
40
|
+
*/
|
|
41
|
+
async function resolveTarget(opts) {
|
|
42
|
+
if (opts.tool) {
|
|
43
|
+
const target = (0, registry_1.getTarget)(opts.tool);
|
|
44
|
+
if (!target) {
|
|
45
|
+
console.error(`ā Unknown tool "${opts.tool}". Valid values for --tool: ${registry_1.TARGETS.map(t => t.id).join(', ')}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
return undefined;
|
|
87
48
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
console.log(`\nContent to be written:\n`);
|
|
94
|
-
console.log(indent(merged.content));
|
|
95
|
-
const ok = await (0, prompt_1.confirmPrompt)('Write this?', true);
|
|
96
|
-
if (!ok) {
|
|
97
|
-
console.log('\nAborted ā nothing written.');
|
|
98
|
-
return;
|
|
49
|
+
return target;
|
|
50
|
+
}
|
|
51
|
+
if (!opts.print && process.stdin.isTTY && process.stdout.isTTY) {
|
|
52
|
+
try {
|
|
53
|
+
return await (0, prompt_1.pickTarget)();
|
|
99
54
|
}
|
|
100
|
-
(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
`(it only loads "on demand" otherwise)?`, true);
|
|
105
|
-
if (pointerConfirm) {
|
|
106
|
-
const pointerPath = path.join(targetDir, mem.pointerFile.file);
|
|
107
|
-
const pointerBody = `See \`${scope.file}\` in this folder for the DevsMind workflow contract ā search before grep, ` +
|
|
108
|
-
`\`edit_node\` to change existing TS/JS code, \`stage_change\` to record every other edit, ` +
|
|
109
|
-
`\`commit_changes\` before the turn ends.`;
|
|
110
|
-
const pointerMerged = (0, prompt_1.mergeRuleFile)(pointerPath, pointerBody, 'append-section');
|
|
111
|
-
if (pointerMerged.error) {
|
|
112
|
-
console.error(`ā ${pointerMerged.error}`);
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
(0, prompt_1.writeConfigFile)(pointerPath, pointerMerged.content);
|
|
116
|
-
console.log(`ā
Pointer added to ${pointerPath.replace(/\\/g, '/')}`);
|
|
117
|
-
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
if (err instanceof prompt_1.CancelledError) {
|
|
57
|
+
console.log('\nCancelled.');
|
|
58
|
+
return undefined;
|
|
118
59
|
}
|
|
60
|
+
throw err;
|
|
119
61
|
}
|
|
120
62
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
throw err;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
/** Resolve the directory to write into, prompting the user to navigate when the exact path isn't knowable. */
|
|
130
|
-
async function resolveMemoryDir(scope, label, workspaceRoot) {
|
|
131
|
-
if (scope.needsUserConfirmedDir) {
|
|
132
|
-
const start = (0, registry_1.resolveOsPath)(scope.dir);
|
|
133
|
-
return (0, prompt_1.pickDirectory)(start, `Navigate to the correct folder for ${label} (e.g. .../projects/<your-project-hash>/memory)`);
|
|
134
|
-
}
|
|
135
|
-
if (scope.scope === 'project') {
|
|
136
|
-
const base = await (0, prompt_1.pickDirectory)(workspaceRoot, `Where is the project root for ${label}?`);
|
|
137
|
-
return path.join(base, (0, registry_1.resolveOsPath)(scope.dir));
|
|
138
|
-
}
|
|
139
|
-
return (0, registry_1.resolveScopeFile)(scope.dir, 'global', workspaceRoot);
|
|
140
|
-
}
|
|
141
|
-
function printManual(label, scope, workspaceRoot) {
|
|
142
|
-
const divider = 'ā'.repeat(70);
|
|
143
|
-
const dirHint = scope.needsUserConfirmedDir
|
|
144
|
-
? `${(0, registry_1.resolveOsPath)(scope.dir)}/<your-project-hash>/...`
|
|
145
|
-
: scope.scope === 'project'
|
|
146
|
-
? path.join(workspaceRoot, (0, registry_1.resolveOsPath)(scope.dir)).replace(/\\/g, '/')
|
|
147
|
-
: (0, registry_1.resolveOsPath)(scope.dir);
|
|
148
|
-
console.log(`\n${divider}`);
|
|
149
|
-
console.log(` Seed DevsMind into ${label}`);
|
|
150
|
-
console.log(`${divider}`);
|
|
151
|
-
console.log(`\n1. Create this file:`);
|
|
152
|
-
console.log(` ${dirHint.replace(/\\/g, '/')}/${scope.file}`);
|
|
63
|
+
const fallback = (0, registry_1.getTarget)('claude-code');
|
|
64
|
+
console.log(`ā¹ļø No --tool given ā showing generic phrasing (the prompt itself is identical for every tool). Others: ${registry_1.TARGETS.map(t => t.id).join(', ')}`);
|
|
65
|
+
return fallback;
|
|
153
66
|
}
|
|
154
67
|
function indent(text) {
|
|
155
68
|
return text.split('\n').map(l => ' ' + l).join('\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/cli/integrations/memory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/cli/integrations/memory.ts"],"names":[],"mappings":";;AAqBA,oCASC;AA9BD,yCAA2D;AAC3D,mDAAqD;AACrD,qCAAsD;AAEtD;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,UAAU,YAAY,CAAC,IAAuD;IACxF,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,4EAA4E;IAEjG,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,KAAK,gBAAgB,MAAM,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC;IAChF,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI;QAAE,OAAO,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAChE,OAAO,CAAC,GAAG,CAAC,6BAA6B,MAAM,CAAC,KAAK,oCAAoC,CAAC,CAAC;IAC3F,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAA,kCAAkB,GAAE,CAAC,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAAC,IAAwC;IACnE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,IAAA,oBAAS,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,IAAI,+BAA+B,kBAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC9G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC/D,IAAI,CAAC;YACH,OAAO,MAAM,IAAA,mBAAU,GAAE,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,uBAAc,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBAC5B,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,IAAA,oBAAS,EAAC,aAAa,CAAE,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,2GAA2G,kBAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5J,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzD,CAAC"}
|