@openvulcan/dsh-vulcancode 0.0.0-stage → 0.4.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/LICENSE +21 -0
- package/README.md +86 -2
- package/assets/openvulcan-icon.svg +33 -0
- package/cordis.patch.yml +17 -0
- package/node_modules/@openvulcan/dsh-decision-guard/LICENSE +21 -0
- package/node_modules/@openvulcan/dsh-decision-guard/README.md +14 -0
- package/node_modules/@openvulcan/dsh-decision-guard/assets/decision-guard-icon.png +0 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/calls.d.ts +40 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/calls.js +150 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/client.js +2193 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/decide.d.ts +90 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/decide.js +108 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/index.d.ts +129 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/index.js +572 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/intent.d.ts +22 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/intent.js +77 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/panel.d.ts +158 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/panel.js +340 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/records.d.ts +133 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/records.js +186 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/review.d.ts +55 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/review.js +202 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/session-state.d.ts +62 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/session-state.js +155 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/version.d.ts +2 -0
- package/node_modules/@openvulcan/dsh-decision-guard/lib/version.js +4 -0
- package/node_modules/@openvulcan/dsh-decision-guard/package.json +68 -0
- package/node_modules/@openvulcan/dsh-vulcan-account/LICENSE +21 -0
- package/node_modules/@openvulcan/dsh-vulcan-account/assets/account-icon.png +0 -0
- package/node_modules/@openvulcan/dsh-vulcan-account/lib/client.js +565 -0
- package/node_modules/@openvulcan/dsh-vulcan-account/lib/index.d.ts +92 -0
- package/node_modules/@openvulcan/dsh-vulcan-account/lib/index.js +194 -0
- package/node_modules/@openvulcan/dsh-vulcan-account/package.json +57 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/LICENSE +21 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/assets/answers-icon.png +0 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/assets/prompts/answer-mode-interactive.md +79 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/assets/prompts/answer-mode-standard.md +1 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/answer-model.d.ts +258 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/answer-model.js +698 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/client.js +671 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/fences.d.ts +29 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/fences.js +70 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/index.d.ts +19 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/index.js +52 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/limits.d.ts +9 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/limits.js +9 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/prompt.d.ts +22 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/prompt.js +39 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/reply-format.d.ts +20 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/reply-format.js +17 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/session-state.d.ts +66 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/lib/session-state.js +118 -0
- package/node_modules/@openvulcan/dsh-vulcan-answers/package.json +59 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/LICENSE +21 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/assets/luaskills-icon.svg +1 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/client.js +940 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/constants.d.ts +46 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/constants.js +51 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/engine.d.ts +55 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/engine.js +149 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/hub.d.ts +49 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/hub.js +116 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/index.d.ts +26 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/index.js +276 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/protocol.d.ts +65 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/protocol.js +2 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/runtime.d.ts +111 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/runtime.js +281 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/sdk-install.d.ts +26 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/sdk-install.js +87 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/settings.d.ts +79 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/settings.js +165 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/skills.d.ts +34 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/skills.js +61 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/tools.d.ts +59 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/tools.js +107 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/worker.d.ts +10 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/lib/worker.js +140 -0
- package/node_modules/@openvulcan/dsh-vulcan-luaskills/package.json +57 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/LICENSE +21 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/assets/markdown-memory-guide.md +21 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/assets/memory-curator/SKILL.md +31 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/assets/memory-icon.png +0 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/client.js +1090 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/index.d.ts +30 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/index.js +240 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/inject.d.ts +30 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/inject.js +46 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/constants.d.ts +23 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/constants.js +25 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/document.d.ts +108 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/document.js +373 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/errors.d.ts +14 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/errors.js +31 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/index.d.ts +196 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/index.js +204 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/operations.d.ts +92 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/operations.js +472 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/package.d.ts +126 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/package.js +553 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/registry.d.ts +56 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/registry.js +182 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/scope.d.ts +13 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/scope.js +24 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/search.d.ts +65 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/search.js +227 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/snapshot.d.ts +34 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/snapshot.js +171 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/store.d.ts +72 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/store.js +250 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/timestamp.d.ts +6 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/timestamp.js +12 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/tokens.d.ts +8 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/markdown/tokens.js +38 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/page.d.ts +132 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/page.js +235 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/project.d.ts +14 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/project.js +27 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/settings.d.ts +29 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/lib/settings.js +62 -0
- package/node_modules/@openvulcan/dsh-vulcan-memory/package.json +63 -0
- package/node_modules/@openvulcan/dsh-vulcan-style/LICENSE +21 -0
- package/node_modules/@openvulcan/dsh-vulcan-style/assets/style-icon.png +0 -0
- package/node_modules/@openvulcan/dsh-vulcan-style/lib/client.js +1061 -0
- package/node_modules/@openvulcan/dsh-vulcan-style/lib/index.d.ts +34 -0
- package/node_modules/@openvulcan/dsh-vulcan-style/lib/index.js +42 -0
- package/node_modules/@openvulcan/dsh-vulcan-style/package.json +51 -0
- package/node_modules/@openvulcan/openvulcan-account/LICENSE +21 -0
- package/node_modules/@openvulcan/openvulcan-account/lib/account.d.ts +140 -0
- package/node_modules/@openvulcan/openvulcan-account/lib/account.js +347 -0
- package/node_modules/@openvulcan/openvulcan-account/lib/index.d.ts +1 -0
- package/node_modules/@openvulcan/openvulcan-account/lib/index.js +1 -0
- package/node_modules/@openvulcan/openvulcan-account/package.json +29 -0
- package/node_modules/@openvulcan/vulcan-decision/LICENSE +21 -0
- package/node_modules/@openvulcan/vulcan-decision/README.md +23 -0
- package/node_modules/@openvulcan/vulcan-decision/bin/vulcan-decision.js +4 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/cli.d.ts +5 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/cli.js +267 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/cloud/edge.d.ts +211 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/cloud/edge.js +594 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/download.d.ts +36 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/download.js +99 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/engine.d.ts +37 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/engine.js +39 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/hardware.d.ts +105 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/hardware.js +207 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/home.d.ts +26 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/home.js +54 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/index.d.ts +17 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/index.js +17 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/local/engine.d.ts +54 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/local/engine.js +157 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/local/models.d.ts +126 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/local/models.js +261 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/local/packs.d.ts +102 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/local/packs.js +195 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/local/worker.d.ts +61 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/local/worker.js +123 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/protocol.d.ts +74 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/protocol.js +31 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/render.d.ts +15 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/render.js +33 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/version.d.ts +2 -0
- package/node_modules/@openvulcan/vulcan-decision/lib/version.js +4 -0
- package/node_modules/@openvulcan/vulcan-decision/package.json +40 -0
- package/node_modules/@openvulcan/vulcan-decision/python/vulcan_decision_worker.py +363 -0
- package/node_modules/@openvulcan/vulcan-decision/runtime-packs/onnx-cpu.json +627 -0
- package/node_modules/@openvulcan/vulcan-decision/runtime-packs/onnx-cuda.json +423 -0
- package/node_modules/@openvulcan/vulcan-decision/runtime-packs/torch-cpu.json +1047 -0
- package/node_modules/@openvulcan/vulcan-decision/runtime-packs/torch-cu128.json +647 -0
- package/package.json +53 -4
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown memory as the plugin uses it: resolve whether memory is active for a session's project,
|
|
3
|
+
* run the three tools, and build the injection snapshot. Everything Markdown-specific stays below
|
|
4
|
+
* this module; the plugin entry only calls these functions.
|
|
5
|
+
*/
|
|
6
|
+
import { MAX_NODE_LEVEL, MAX_OPERATIONS_PER_WRITE, MAX_SEARCH_LIMIT, MAX_SEARCH_PATTERNS } from './constants.js';
|
|
7
|
+
import { MemoryError } from './errors.js';
|
|
8
|
+
import { parseWriteOperation, renderWriteReceipt, writeMemory } from './operations.js';
|
|
9
|
+
import { SCOPES, isScope, presetSections } from './scope.js';
|
|
10
|
+
import { renderOutline, renderSearchPage, searchNodes } from './search.js';
|
|
11
|
+
import { buildInjectionSnapshot } from './snapshot.js';
|
|
12
|
+
import { MarkdownMemoryStore } from './store.js';
|
|
13
|
+
import { isRecord } from './registry.js';
|
|
14
|
+
export { MarkdownMemoryStore } from './store.js';
|
|
15
|
+
/**
|
|
16
|
+
* Memory of a project, or `undefined` when the mode is not `markdown` or the user turned memory
|
|
17
|
+
* off for this project (which also hides the user and space scopes), as VulcanCode resolves it.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveAccess(store, settings, context) {
|
|
20
|
+
if (settings.mode !== 'markdown')
|
|
21
|
+
return undefined;
|
|
22
|
+
if (context.hostProjectId !== undefined && store.registry().projectForHost(context.hostProjectId)?.memoryEnabled === false)
|
|
23
|
+
return undefined;
|
|
24
|
+
return { store, context, budget: settings.budget };
|
|
25
|
+
}
|
|
26
|
+
export const NOT_ACTIVE_MESSAGE = 'Markdown memory is not active for this conversation; the memory mode changed or memory is off for this project.';
|
|
27
|
+
export function outline(access, args) {
|
|
28
|
+
return renderOutline(access.store.loadScopes(access.context), parseOutlineRequest(args));
|
|
29
|
+
}
|
|
30
|
+
export function search(access, args) {
|
|
31
|
+
return renderSearchPage(searchNodes(access.store.loadScopes(access.context), parseSearchRequest(args)));
|
|
32
|
+
}
|
|
33
|
+
export function write(access, author, args) {
|
|
34
|
+
const input = expectObject(args, ['operations']);
|
|
35
|
+
const operations = input['operations'];
|
|
36
|
+
if (!Array.isArray(operations))
|
|
37
|
+
throw invalidArguments('missing field `operations`');
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = operations.map(parseWriteOperation);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
throw error instanceof MemoryError ? invalidArguments(error.message) : error;
|
|
44
|
+
}
|
|
45
|
+
return renderWriteReceipt(writeMemory(access.store, access.context, author, access.budget, parsed));
|
|
46
|
+
}
|
|
47
|
+
/** The snapshot text injected into a conversation; empty when every scope is empty. */
|
|
48
|
+
export function snapshot(access) {
|
|
49
|
+
return buildInjectionSnapshot(access.store.loadScopes(access.context), access.budget).content;
|
|
50
|
+
}
|
|
51
|
+
const SCOPE_SCHEMA = { type: 'string', enum: [...SCOPES] };
|
|
52
|
+
function presetSectionKeys() {
|
|
53
|
+
return SCOPES.map(scope => `${scope} (${presetSections(scope).map(([key]) => key).join(', ')})`).join('; ');
|
|
54
|
+
}
|
|
55
|
+
/** Model-facing names, descriptions and schemas, the same text VulcanCode registers. */
|
|
56
|
+
export const TOOL_SPECS = {
|
|
57
|
+
outline: {
|
|
58
|
+
name: 'memory_outline',
|
|
59
|
+
description: 'List the heading tree of long-term memory: the user profile, space memory (rules for every project) and this project\'s memory, with node ids, revisions, update dates and body sizes. Use it to see what is remembered and where a new fact belongs before memory_write.',
|
|
60
|
+
parameters: {
|
|
61
|
+
type: 'object',
|
|
62
|
+
additionalProperties: false,
|
|
63
|
+
properties: {
|
|
64
|
+
scopes: { type: 'array', uniqueItems: true, items: SCOPE_SCHEMA, description: 'Scopes to list; defaults to all.' },
|
|
65
|
+
section: { type: 'string', description: 'Section key or H1 title to list.' },
|
|
66
|
+
pathPrefix: { type: 'string', description: 'Title path prefix, segments separated by `/`.' },
|
|
67
|
+
depth: { type: 'integer', minimum: 1, maximum: MAX_NODE_LEVEL, description: 'Deepest heading level listed; defaults to all.' },
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
search: {
|
|
72
|
+
name: 'memory_search',
|
|
73
|
+
description: 'Search long-term memory nodes with several patterns combined with OR (regex unless fixedStrings; case-insensitive by default), optionally limited to scopes, a section or a title path prefix; or read nodes by id. Each result is a whole node: scope, title path, id, revision, update time and body, with matching lines prefixed by `>> `. Catalog lines injected at session start are titles only: read the node before relying on it or changing it.',
|
|
74
|
+
parameters: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
additionalProperties: false,
|
|
77
|
+
properties: {
|
|
78
|
+
patterns: { type: 'array', maxItems: MAX_SEARCH_PATTERNS, items: { type: 'string', minLength: 1 }, description: 'Patterns combined with OR; include synonyms and other languages. Mutually exclusive with ids.' },
|
|
79
|
+
fixedStrings: { type: 'boolean', description: 'Match patterns as literal text.' },
|
|
80
|
+
ignoreCase: { type: 'boolean', description: 'Case-insensitive matching; defaults to true.' },
|
|
81
|
+
scopes: { type: 'array', uniqueItems: true, items: SCOPE_SCHEMA, description: 'Scopes to search; defaults to all.' },
|
|
82
|
+
section: { type: 'string', description: 'Section key or H1 title filter.' },
|
|
83
|
+
pathPrefix: { type: 'string', description: 'Title path prefix filter, segments separated by `/`.' },
|
|
84
|
+
ids: { type: 'array', items: { type: 'string' }, description: 'Node ids to read whole. Mutually exclusive with patterns.' },
|
|
85
|
+
limit: { type: 'integer', minimum: 1, maximum: MAX_SEARCH_LIMIT, description: 'Nodes per page.' },
|
|
86
|
+
cursor: { type: 'string', description: 'Cursor from a previous result: the next result page, or the next body page of a single id.' },
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
write: {
|
|
91
|
+
name: 'memory_write',
|
|
92
|
+
description: `Change long-term memory with 1 to ${MAX_OPERATIONS_PER_WRITE} operations applied all-or-nothing: create, replace, append, rename, move (across scopes and sections too) and delete. create needs a scope and exactly one of parentId, section or newSection. Every action except create needs the node's current expectedRevision from memory_search or memory_outline. Scopes: \`user\` describes who the user is; \`space\` holds rules and environment that hold for every project; \`project\` holds facts, decisions and constraints of this project only. The \`base\` section of space and project is injected in full every session, so keep it to a few critical, stable rules and put the rest in other sections. Write when the user asks you to remember something, corrects your approach, or a decision is made that the repository does not show. Make titles state the fact itself; bodies cannot contain H1-H4 headings.`,
|
|
93
|
+
parameters: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
additionalProperties: false,
|
|
96
|
+
properties: {
|
|
97
|
+
operations: {
|
|
98
|
+
type: 'array',
|
|
99
|
+
minItems: 1,
|
|
100
|
+
maxItems: MAX_OPERATIONS_PER_WRITE,
|
|
101
|
+
items: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
additionalProperties: false,
|
|
104
|
+
properties: {
|
|
105
|
+
action: { type: 'string', enum: ['create', 'replace', 'append', 'rename', 'move', 'delete'] },
|
|
106
|
+
id: { type: 'string', description: 'Node id; every action except create.' },
|
|
107
|
+
expectedRevision: { type: 'string', description: 'Revision last read; every action except create.' },
|
|
108
|
+
scope: { type: 'string', enum: [...SCOPES], description: 'Destination scope; required for create, optional for move.' },
|
|
109
|
+
parentId: { type: 'string', description: 'create/move: become the last child of this node.' },
|
|
110
|
+
section: { type: 'string', description: `create/move: become a child of this section, by key or H1 title. New files start with the preset sections: ${presetSectionKeys()}.` },
|
|
111
|
+
newSection: { type: 'boolean', description: 'create/move: become a new H1 section. Give exactly one of parentId, section, newSection.' },
|
|
112
|
+
title: { type: 'string', description: 'create/rename: heading text.' },
|
|
113
|
+
body: { type: 'string', description: 'create/replace: Markdown body. replace keeps the title; change it with rename.' },
|
|
114
|
+
text: { type: 'string', description: 'append: Markdown appended after a blank line.' },
|
|
115
|
+
withChildren: { type: 'boolean', description: 'delete: also delete child nodes.' },
|
|
116
|
+
},
|
|
117
|
+
required: ['action'],
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
required: ['operations'],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
function invalidArguments(message) {
|
|
126
|
+
return MemoryError.invalid(`Invalid arguments: ${message}`);
|
|
127
|
+
}
|
|
128
|
+
/** An object with only the known fields, as serde's `deny_unknown_fields` requires. */
|
|
129
|
+
function expectObject(args, fields) {
|
|
130
|
+
const input = args === undefined || args === null ? {} : args;
|
|
131
|
+
if (!isRecord(input))
|
|
132
|
+
throw invalidArguments('expected an object');
|
|
133
|
+
const unknown = Object.keys(input).find(key => !fields.includes(key));
|
|
134
|
+
if (unknown !== undefined)
|
|
135
|
+
throw invalidArguments(`unknown field \`${unknown}\`, expected one of ${fields.map(field => `\`${field}\``).join(', ')}`);
|
|
136
|
+
return input;
|
|
137
|
+
}
|
|
138
|
+
function optionalString(input, field) {
|
|
139
|
+
const value = input[field];
|
|
140
|
+
if (value === undefined || value === null)
|
|
141
|
+
return undefined;
|
|
142
|
+
if (typeof value !== 'string')
|
|
143
|
+
throw invalidArguments(`\`${field}\` must be a string`);
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
function optionalBoolean(input, field) {
|
|
147
|
+
const value = input[field];
|
|
148
|
+
if (value === undefined || value === null)
|
|
149
|
+
return undefined;
|
|
150
|
+
if (typeof value !== 'boolean')
|
|
151
|
+
throw invalidArguments(`\`${field}\` must be a boolean`);
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
function optionalInteger(input, field) {
|
|
155
|
+
const value = input[field];
|
|
156
|
+
if (value === undefined || value === null)
|
|
157
|
+
return undefined;
|
|
158
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0)
|
|
159
|
+
throw invalidArguments(`\`${field}\` must be a non-negative integer`);
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
162
|
+
function stringList(input, field) {
|
|
163
|
+
const value = input[field];
|
|
164
|
+
if (value === undefined || value === null)
|
|
165
|
+
return undefined;
|
|
166
|
+
if (!Array.isArray(value) || !value.every(item => typeof item === 'string'))
|
|
167
|
+
throw invalidArguments(`\`${field}\` must be an array of strings`);
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
function scopeList(input) {
|
|
171
|
+
const value = input['scopes'];
|
|
172
|
+
if (value === undefined || value === null)
|
|
173
|
+
return undefined;
|
|
174
|
+
if (!Array.isArray(value) || !value.every(isScope))
|
|
175
|
+
throw invalidArguments('`scopes` must be an array of user, space or project');
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
/** Copy the defined values only, so optional request fields stay absent. */
|
|
179
|
+
function defined(value) {
|
|
180
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
181
|
+
}
|
|
182
|
+
export function parseOutlineRequest(args) {
|
|
183
|
+
const input = expectObject(args, ['scopes', 'section', 'pathPrefix', 'depth']);
|
|
184
|
+
return defined({
|
|
185
|
+
scopes: scopeList(input),
|
|
186
|
+
section: optionalString(input, 'section'),
|
|
187
|
+
pathPrefix: optionalString(input, 'pathPrefix'),
|
|
188
|
+
depth: optionalInteger(input, 'depth'),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
export function parseSearchRequest(args) {
|
|
192
|
+
const input = expectObject(args, ['patterns', 'fixedStrings', 'ignoreCase', 'scopes', 'section', 'pathPrefix', 'ids', 'limit', 'cursor']);
|
|
193
|
+
return defined({
|
|
194
|
+
patterns: stringList(input, 'patterns'),
|
|
195
|
+
fixedStrings: optionalBoolean(input, 'fixedStrings'),
|
|
196
|
+
ignoreCase: optionalBoolean(input, 'ignoreCase'),
|
|
197
|
+
scopes: scopeList(input),
|
|
198
|
+
section: optionalString(input, 'section'),
|
|
199
|
+
pathPrefix: optionalString(input, 'pathPrefix'),
|
|
200
|
+
ids: stringList(input, 'ids'),
|
|
201
|
+
limit: optionalInteger(input, 'limit'),
|
|
202
|
+
cursor: optionalString(input, 'cursor'),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Write operations applied atomically across the scope files (`operations.rs`). */
|
|
2
|
+
import type { InjectionBudget } from '../settings.js';
|
|
3
|
+
import { type NodeSource } from './document.js';
|
|
4
|
+
import { type MemoryScope } from './scope.js';
|
|
5
|
+
import { type BudgetUsage } from './snapshot.js';
|
|
6
|
+
import { type MarkdownMemoryStore, type ProjectContext } from './store.js';
|
|
7
|
+
/** Where a created or moved node goes. */
|
|
8
|
+
export interface NodePlacement {
|
|
9
|
+
/** Destination scope; a move without it stays in the node's scope. */
|
|
10
|
+
readonly scope?: MemoryScope;
|
|
11
|
+
/** Parent node id; the node becomes its last child. */
|
|
12
|
+
readonly parentId?: string;
|
|
13
|
+
/** Section key or H1 title; the node becomes its last child. */
|
|
14
|
+
readonly section?: string;
|
|
15
|
+
/** Make the node a new H1 section of the scope. */
|
|
16
|
+
readonly newSection: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** One requested change. */
|
|
19
|
+
export type WriteOperation = ({
|
|
20
|
+
readonly action: 'create';
|
|
21
|
+
readonly title: string;
|
|
22
|
+
readonly body: string;
|
|
23
|
+
} & NodePlacement) | {
|
|
24
|
+
readonly action: 'replace';
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly expectedRevision: string;
|
|
27
|
+
readonly body: string;
|
|
28
|
+
} | {
|
|
29
|
+
readonly action: 'append';
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly expectedRevision: string;
|
|
32
|
+
readonly text: string;
|
|
33
|
+
} | {
|
|
34
|
+
readonly action: 'rename';
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly expectedRevision: string;
|
|
37
|
+
readonly title: string;
|
|
38
|
+
} | ({
|
|
39
|
+
readonly action: 'move';
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly expectedRevision: string;
|
|
42
|
+
} & NodePlacement) | {
|
|
43
|
+
readonly action: 'delete';
|
|
44
|
+
readonly id: string;
|
|
45
|
+
readonly expectedRevision: string;
|
|
46
|
+
readonly withChildren: boolean;
|
|
47
|
+
};
|
|
48
|
+
/** A node that may duplicate a written one. */
|
|
49
|
+
export interface DuplicateHint {
|
|
50
|
+
readonly id: string;
|
|
51
|
+
readonly scope: MemoryScope;
|
|
52
|
+
readonly path: readonly string[];
|
|
53
|
+
}
|
|
54
|
+
/** Result of one applied operation. */
|
|
55
|
+
export interface WriteOperationReceipt {
|
|
56
|
+
readonly action: WriteOperation['action'];
|
|
57
|
+
/** Node id after the operation; a node written for the first time receives a stable id. */
|
|
58
|
+
readonly id: string;
|
|
59
|
+
readonly scope: MemoryScope;
|
|
60
|
+
readonly path: readonly string[];
|
|
61
|
+
/** Revision after the operation; empty after a delete. */
|
|
62
|
+
readonly revision: string;
|
|
63
|
+
readonly newSection: boolean;
|
|
64
|
+
readonly deletedChildren: number;
|
|
65
|
+
readonly duplicates: readonly DuplicateHint[];
|
|
66
|
+
}
|
|
67
|
+
/** Result of a whole write call. */
|
|
68
|
+
export interface WriteReceipt {
|
|
69
|
+
readonly operations: readonly WriteOperationReceipt[];
|
|
70
|
+
/** Usage of the injected full-text parts after the write. */
|
|
71
|
+
readonly usage: readonly BudgetUsage[];
|
|
72
|
+
/** Memory project created for the host project by this write. */
|
|
73
|
+
readonly createdProject: string | undefined;
|
|
74
|
+
}
|
|
75
|
+
/** The receipt as model-facing English text. */
|
|
76
|
+
export declare function renderWriteReceipt(receipt: WriteReceipt): string;
|
|
77
|
+
/**
|
|
78
|
+
* Parse one operation the way VulcanCode's serde enum does: tagged by `action`, camelCase fields,
|
|
79
|
+
* unknown fields refused, optional fields may be absent or null. Messages describe the problem
|
|
80
|
+
* without the `Invalid arguments:` prefix the tool layer adds.
|
|
81
|
+
*/
|
|
82
|
+
export declare function parseWriteOperation(value: unknown): WriteOperation;
|
|
83
|
+
/** Who writes and in which conversation; recorded in node metadata. */
|
|
84
|
+
export interface WriteAuthor {
|
|
85
|
+
/** Conversation id; dropped when it cannot be stored in a metadata line. */
|
|
86
|
+
readonly session: string | undefined;
|
|
87
|
+
readonly source: NodeSource;
|
|
88
|
+
}
|
|
89
|
+
/** Apply operations in order, all or nothing; a failed commit restores originals or reports an incomplete rollback. */
|
|
90
|
+
export declare function writeMemory(store: MarkdownMemoryStore, context: ProjectContext, author: WriteAuthor, budget: InjectionBudget, operations: readonly WriteOperation[]): WriteReceipt;
|
|
91
|
+
/** Score two nodes by title character bigrams and body word overlap. */
|
|
92
|
+
export declare function similarity(title: string, body: string, otherTitle: string, otherBody: string): number;
|