@gmickel/gno 1.17.0 → 1.18.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 +14 -2
- package/assets/skill/SKILL.md +17 -1
- package/assets/skill/mcp-reference.md +21 -0
- package/package.json +2 -2
- package/src/cli/commands/daemon.ts +69 -2
- package/src/cli/commands/models/pull.ts +13 -3
- package/src/cli/commands/status.ts +2 -0
- package/src/cli/detach.ts +37 -20
- package/src/cli/program.ts +74 -27
- package/src/config/index.ts +3 -0
- package/src/config/types.ts +37 -0
- package/src/core/job-manager.ts +19 -0
- package/src/core/mutation-generations.ts +33 -0
- package/src/llm/cache.ts +13 -3
- package/src/llm/nodeLlamaCpp/adapter.ts +10 -1
- package/src/llm/nodeLlamaCpp/lifecycle.ts +71 -0
- package/src/mcp/context.ts +161 -0
- package/src/mcp/http-security.ts +477 -0
- package/src/mcp/http-session.ts +272 -0
- package/src/mcp/http-transport.ts +370 -0
- package/src/mcp/resources/index.ts +141 -134
- package/src/mcp/server.ts +19 -79
- package/src/mcp/tools/add-collection.ts +3 -1
- package/src/mcp/tools/capture.ts +3 -0
- package/src/mcp/tools/clear-collection-embeddings.ts +2 -0
- package/src/mcp/tools/context.ts +9 -8
- package/src/mcp/tools/embed.ts +62 -52
- package/src/mcp/tools/index-cmd.ts +88 -74
- package/src/mcp/tools/index.ts +22 -2
- package/src/mcp/tools/remove-collection.ts +2 -0
- package/src/mcp/tools/status.ts +11 -0
- package/src/mcp/tools/sync.ts +16 -14
- package/src/mcp/tools/workspace-write.ts +7 -3
- package/src/serve/background-runtime.ts +12 -212
- package/src/serve/embed-scheduler.ts +74 -43
- package/src/serve/index.ts +9 -0
- package/src/serve/jobs.ts +78 -80
- package/src/serve/public/components/HealthCenter.tsx +74 -1
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Dashboard.tsx +1 -0
- package/src/serve/resident-admission.ts +159 -0
- package/src/serve/resident-background-work.ts +39 -0
- package/src/serve/resident-request.ts +55 -0
- package/src/serve/resident-runtime.ts +490 -0
- package/src/serve/resident-status.ts +96 -0
- package/src/serve/routes/api.ts +263 -167
- package/src/serve/routes/mcp.ts +69 -0
- package/src/serve/server.ts +191 -37
- package/src/serve/status-model.ts +51 -0
- package/src/serve/status.ts +5 -0
- package/src/store/sqlite/adapter.ts +26 -9
package/src/mcp/tools/embed.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { ToolContext } from "../server";
|
|
|
9
9
|
import { MCP_ERRORS } from "../../core/errors";
|
|
10
10
|
import { acquireWriteLock, type WriteLockHandle } from "../../core/file-lock";
|
|
11
11
|
import { JobError } from "../../core/job-manager";
|
|
12
|
+
import { recordIndexMutation } from "../../core/mutation-generations";
|
|
12
13
|
import { embedBacklog } from "../../embed";
|
|
13
14
|
import { LlmAdapter } from "../../llm/nodeLlamaCpp/adapter";
|
|
14
15
|
import { resolveModelUri } from "../../llm/registry";
|
|
@@ -81,64 +82,73 @@ export function handleEmbed(
|
|
|
81
82
|
"embed",
|
|
82
83
|
lock,
|
|
83
84
|
async () => {
|
|
84
|
-
|
|
85
|
-
const llm = new LlmAdapter(ctx.config);
|
|
86
|
-
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
87
|
-
policy: { offline: true, allowDownload: false },
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
if (!embedResult.ok) {
|
|
91
|
-
throw new Error(
|
|
92
|
-
`MODEL_NOT_FOUND: Embedding model not cached. ` +
|
|
93
|
-
`Model: ${modelUri}. ` +
|
|
94
|
-
`Run 'gno models pull embed' first.`
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const embedPort = embedResult.value;
|
|
99
|
-
|
|
85
|
+
const lease = ctx.acquireModelLease?.();
|
|
100
86
|
try {
|
|
101
|
-
//
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
const dimensions = embedPort.dimensions();
|
|
107
|
-
|
|
108
|
-
// Create vector index port
|
|
109
|
-
const db = ctx.store.getRawDb();
|
|
110
|
-
const vectorResult = await createVectorIndexPort(db, {
|
|
111
|
-
model: modelUri,
|
|
112
|
-
dimensions,
|
|
113
|
-
});
|
|
114
|
-
if (!vectorResult.ok) {
|
|
115
|
-
throw new Error(vectorResult.error.message);
|
|
116
|
-
}
|
|
117
|
-
const vectorIndex = vectorResult.value;
|
|
118
|
-
|
|
119
|
-
// Create stats port for backlog
|
|
120
|
-
const statsPort = createVectorStatsPort(db);
|
|
121
|
-
|
|
122
|
-
// Run embedding
|
|
123
|
-
const result = await embedBacklog({
|
|
124
|
-
statsPort,
|
|
125
|
-
embedPort,
|
|
126
|
-
vectorIndex,
|
|
127
|
-
collection: collection?.name,
|
|
128
|
-
modelUri,
|
|
129
|
-
batchSize: 32,
|
|
87
|
+
// Create LLM adapter with offline policy (fail-fast, no download)
|
|
88
|
+
const llm = new LlmAdapter(ctx.config);
|
|
89
|
+
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
90
|
+
policy: { offline: true, allowDownload: false },
|
|
130
91
|
});
|
|
131
92
|
|
|
132
|
-
if (!
|
|
133
|
-
throw new Error(
|
|
93
|
+
if (!embedResult.ok) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`MODEL_NOT_FOUND: Embedding model not cached. ` +
|
|
96
|
+
`Model: ${modelUri}. ` +
|
|
97
|
+
`Run 'gno models pull embed' first.`
|
|
98
|
+
);
|
|
134
99
|
}
|
|
135
100
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
101
|
+
const embedPort = embedResult.value;
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
// Initialize and get dimensions from port interface
|
|
105
|
+
const initResult = await embedPort.init();
|
|
106
|
+
if (!initResult.ok) {
|
|
107
|
+
throw new Error(initResult.error.message);
|
|
108
|
+
}
|
|
109
|
+
const dimensions = embedPort.dimensions();
|
|
110
|
+
|
|
111
|
+
// Create vector index port
|
|
112
|
+
const db = ctx.store.getRawDb();
|
|
113
|
+
const vectorResult = await createVectorIndexPort(db, {
|
|
114
|
+
model: modelUri,
|
|
115
|
+
dimensions,
|
|
116
|
+
});
|
|
117
|
+
if (!vectorResult.ok) {
|
|
118
|
+
throw new Error(vectorResult.error.message);
|
|
119
|
+
}
|
|
120
|
+
const vectorIndex = vectorResult.value;
|
|
121
|
+
|
|
122
|
+
// Create stats port for backlog
|
|
123
|
+
const statsPort = createVectorStatsPort(db);
|
|
124
|
+
|
|
125
|
+
// Run embedding
|
|
126
|
+
const result = await embedBacklog({
|
|
127
|
+
statsPort,
|
|
128
|
+
embedPort,
|
|
129
|
+
vectorIndex,
|
|
130
|
+
collection: collection?.name,
|
|
131
|
+
modelUri,
|
|
132
|
+
batchSize: 32,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (!result.ok) {
|
|
136
|
+
throw new Error(result.error.message);
|
|
137
|
+
}
|
|
138
|
+
recordIndexMutation(
|
|
139
|
+
result.value.embedded,
|
|
140
|
+
ctx.markIndexMutation
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
kind: "embed" as const,
|
|
145
|
+
value: result.value,
|
|
146
|
+
};
|
|
147
|
+
} finally {
|
|
148
|
+
await embedPort.dispose();
|
|
149
|
+
}
|
|
140
150
|
} finally {
|
|
141
|
-
|
|
151
|
+
lease?.release();
|
|
142
152
|
}
|
|
143
153
|
}
|
|
144
154
|
);
|
|
@@ -10,6 +10,10 @@ import type { ToolContext } from "../server";
|
|
|
10
10
|
import { MCP_ERRORS } from "../../core/errors";
|
|
11
11
|
import { acquireWriteLock, type WriteLockHandle } from "../../core/file-lock";
|
|
12
12
|
import { JobError } from "../../core/job-manager";
|
|
13
|
+
import {
|
|
14
|
+
recordContentMutation,
|
|
15
|
+
recordIndexMutation,
|
|
16
|
+
} from "../../core/mutation-generations";
|
|
13
17
|
import { normalizeCollectionName } from "../../core/validation";
|
|
14
18
|
import { embedBacklog } from "../../embed";
|
|
15
19
|
import { defaultSyncService, withContentTypeRules } from "../../ingestion";
|
|
@@ -115,86 +119,96 @@ export function handleIndex(
|
|
|
115
119
|
"index",
|
|
116
120
|
lock,
|
|
117
121
|
async () => {
|
|
118
|
-
|
|
119
|
-
const syncResult = collection
|
|
120
|
-
? await defaultSyncService
|
|
121
|
-
.syncCollection(collection, ctx.store, options)
|
|
122
|
-
.then((r) => ({
|
|
123
|
-
collections: [r],
|
|
124
|
-
totalDurationMs: r.durationMs,
|
|
125
|
-
totalFilesProcessed: r.filesProcessed,
|
|
126
|
-
totalFilesAdded: r.filesAdded,
|
|
127
|
-
totalFilesUpdated: r.filesUpdated,
|
|
128
|
-
totalFilesErrored: r.filesErrored,
|
|
129
|
-
totalFilesSkipped: r.filesSkipped,
|
|
130
|
-
}))
|
|
131
|
-
: await defaultSyncService.syncAll(
|
|
132
|
-
ctx.collections,
|
|
133
|
-
ctx.store,
|
|
134
|
-
options
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
// Phase 2: Embed
|
|
138
|
-
const llm = new LlmAdapter(ctx.config);
|
|
139
|
-
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
140
|
-
policy: { offline: true, allowDownload: false },
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
if (!embedResult.ok) {
|
|
144
|
-
throw new Error(
|
|
145
|
-
`MODEL_NOT_FOUND: Embedding model not cached. ` +
|
|
146
|
-
`Model: ${modelUri}. ` +
|
|
147
|
-
`Run 'gno models pull embed' first.`
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const embedPort = embedResult.value;
|
|
152
|
-
|
|
122
|
+
const lease = ctx.acquireModelLease?.();
|
|
153
123
|
try {
|
|
154
|
-
//
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
embedPort,
|
|
179
|
-
vectorIndex,
|
|
180
|
-
collection: collection?.name,
|
|
181
|
-
modelUri,
|
|
182
|
-
batchSize: 32,
|
|
124
|
+
// Phase 1: Sync
|
|
125
|
+
const syncResult = collection
|
|
126
|
+
? await defaultSyncService
|
|
127
|
+
.syncCollection(collection, ctx.store, options)
|
|
128
|
+
.then((r) => ({
|
|
129
|
+
collections: [r],
|
|
130
|
+
totalDurationMs: r.durationMs,
|
|
131
|
+
totalFilesProcessed: r.filesProcessed,
|
|
132
|
+
totalFilesAdded: r.filesAdded,
|
|
133
|
+
totalFilesUpdated: r.filesUpdated,
|
|
134
|
+
totalFilesErrored: r.filesErrored,
|
|
135
|
+
totalFilesSkipped: r.filesSkipped,
|
|
136
|
+
}))
|
|
137
|
+
: await defaultSyncService.syncAll(
|
|
138
|
+
ctx.collections,
|
|
139
|
+
ctx.store,
|
|
140
|
+
options
|
|
141
|
+
);
|
|
142
|
+
recordContentMutation(syncResult, ctx.markContentMutation);
|
|
143
|
+
|
|
144
|
+
// Phase 2: Embed
|
|
145
|
+
const llm = new LlmAdapter(ctx.config);
|
|
146
|
+
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
147
|
+
policy: { offline: true, allowDownload: false },
|
|
183
148
|
});
|
|
184
149
|
|
|
185
|
-
if (!
|
|
186
|
-
throw new Error(
|
|
150
|
+
if (!embedResult.ok) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
`MODEL_NOT_FOUND: Embedding model not cached. ` +
|
|
153
|
+
`Model: ${modelUri}. ` +
|
|
154
|
+
`Run 'gno models pull embed' first.`
|
|
155
|
+
);
|
|
187
156
|
}
|
|
188
157
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
158
|
+
const embedPort = embedResult.value;
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
// Initialize and get dimensions from port interface
|
|
162
|
+
const initResult = await embedPort.init();
|
|
163
|
+
if (!initResult.ok) {
|
|
164
|
+
throw new Error(initResult.error.message);
|
|
165
|
+
}
|
|
166
|
+
const dimensions = embedPort.dimensions();
|
|
167
|
+
|
|
168
|
+
// Create vector index port
|
|
169
|
+
const db = ctx.store.getRawDb();
|
|
170
|
+
const vectorResult = await createVectorIndexPort(db, {
|
|
171
|
+
model: modelUri,
|
|
172
|
+
dimensions,
|
|
173
|
+
});
|
|
174
|
+
if (!vectorResult.ok) {
|
|
175
|
+
throw new Error(vectorResult.error.message);
|
|
176
|
+
}
|
|
177
|
+
const vectorIndex = vectorResult.value;
|
|
178
|
+
|
|
179
|
+
// Create stats port for backlog
|
|
180
|
+
const statsPort = createVectorStatsPort(db);
|
|
181
|
+
|
|
182
|
+
// Run embedding
|
|
183
|
+
const backlogResult = await embedBacklog({
|
|
184
|
+
statsPort,
|
|
185
|
+
embedPort,
|
|
186
|
+
vectorIndex,
|
|
187
|
+
collection: collection?.name,
|
|
188
|
+
modelUri,
|
|
189
|
+
batchSize: 32,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
if (!backlogResult.ok) {
|
|
193
|
+
throw new Error(backlogResult.error.message);
|
|
194
|
+
}
|
|
195
|
+
recordIndexMutation(
|
|
196
|
+
backlogResult.value.embedded,
|
|
197
|
+
ctx.markIndexMutation
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
kind: "index" as const,
|
|
202
|
+
value: {
|
|
203
|
+
sync: syncResult,
|
|
204
|
+
embed: backlogResult.value,
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
} finally {
|
|
208
|
+
await embedPort.dispose();
|
|
209
|
+
}
|
|
196
210
|
} finally {
|
|
197
|
-
|
|
211
|
+
lease?.release();
|
|
198
212
|
}
|
|
199
213
|
}
|
|
200
214
|
);
|
package/src/mcp/tools/index.ts
CHANGED
|
@@ -83,6 +83,21 @@ export const MCP_TOOL_DESCRIPTIONS = {
|
|
|
83
83
|
"Verify a saved Context Capsule without rebuilding or mutating it. Reports unchanged, stale, missing, reranked, and fingerprint drift states against the active index.",
|
|
84
84
|
} as const;
|
|
85
85
|
|
|
86
|
+
/** Tool names whose execution mutates disk, config, or index state. */
|
|
87
|
+
export const MCP_WRITE_TOOL_NAMES = new Set([
|
|
88
|
+
"gno_capture",
|
|
89
|
+
"gno_add_collection",
|
|
90
|
+
"gno_sync",
|
|
91
|
+
"gno_embed",
|
|
92
|
+
"gno_index",
|
|
93
|
+
"gno_remove_collection",
|
|
94
|
+
"gno_clear_collection_embeddings",
|
|
95
|
+
"gno_create_folder",
|
|
96
|
+
"gno_rename_note",
|
|
97
|
+
"gno_move_note",
|
|
98
|
+
"gno_duplicate_note",
|
|
99
|
+
]);
|
|
100
|
+
|
|
86
101
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
87
102
|
// Shared Input Schemas
|
|
88
103
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -829,8 +844,9 @@ export async function runTool<T>(
|
|
|
829
844
|
|
|
830
845
|
// Sequential execution via mutex
|
|
831
846
|
const release = await ctx.toolMutex.acquire();
|
|
847
|
+
const modelLease = ctx.acquireModelLease?.();
|
|
832
848
|
try {
|
|
833
|
-
const data = await fn();
|
|
849
|
+
const data = await (ctx.runWithSnapshot?.(fn) ?? fn());
|
|
834
850
|
return {
|
|
835
851
|
content: [{ type: "text", text: formatText(data) }],
|
|
836
852
|
structuredContent: data as { [x: string]: unknown },
|
|
@@ -846,6 +862,7 @@ export async function runTool<T>(
|
|
|
846
862
|
structuredContent: parsedError,
|
|
847
863
|
};
|
|
848
864
|
} finally {
|
|
865
|
+
modelLease?.release();
|
|
849
866
|
release();
|
|
850
867
|
}
|
|
851
868
|
}
|
|
@@ -869,8 +886,9 @@ export async function runToolNoMutex<T>(
|
|
|
869
886
|
};
|
|
870
887
|
}
|
|
871
888
|
|
|
889
|
+
const modelLease = ctx.acquireModelLease?.();
|
|
872
890
|
try {
|
|
873
|
-
const data = await fn();
|
|
891
|
+
const data = await (ctx.runWithSnapshot?.(fn) ?? fn());
|
|
874
892
|
return {
|
|
875
893
|
content: [{ type: "text", text: formatText(data) }],
|
|
876
894
|
structuredContent: data as { [x: string]: unknown },
|
|
@@ -885,6 +903,8 @@ export async function runToolNoMutex<T>(
|
|
|
885
903
|
content: [{ type: "text", text: `Error: ${message}` }],
|
|
886
904
|
structuredContent: parsedError,
|
|
887
905
|
};
|
|
906
|
+
} finally {
|
|
907
|
+
modelLease?.release();
|
|
888
908
|
}
|
|
889
909
|
}
|
|
890
910
|
|
|
@@ -89,6 +89,8 @@ export function handleRemoveCollection(
|
|
|
89
89
|
if (!mutationResult.ok) {
|
|
90
90
|
throw mapConfigError(mutationResult.code, mutationResult.error);
|
|
91
91
|
}
|
|
92
|
+
ctx.markContentMutation?.();
|
|
93
|
+
ctx.markIndexMutation?.();
|
|
92
94
|
|
|
93
95
|
const result: RemoveCollectionResult = {
|
|
94
96
|
removed: true,
|
package/src/mcp/tools/status.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { IndexStatus } from "../../store/types";
|
|
|
8
8
|
import type { ToolContext } from "../server";
|
|
9
9
|
|
|
10
10
|
import { resolveModelUri } from "../../llm/registry";
|
|
11
|
+
import { createStandaloneResidentStatus } from "../../serve/resident-status";
|
|
11
12
|
import { runTool, type ToolResult } from "./index";
|
|
12
13
|
|
|
13
14
|
type StatusInput = Record<string, never>;
|
|
@@ -22,6 +23,14 @@ function formatStatus(status: IndexStatus): string {
|
|
|
22
23
|
lines.push(`Config: ${status.configPath}`);
|
|
23
24
|
lines.push(`Database: ${status.dbPath}`);
|
|
24
25
|
lines.push(`Health: ${status.healthy ? "OK" : "DEGRADED"}`);
|
|
26
|
+
if ("resident" in status) {
|
|
27
|
+
const resident = status.resident as NonNullable<
|
|
28
|
+
ReturnType<NonNullable<ToolContext["getResidentStatus"]>>
|
|
29
|
+
>;
|
|
30
|
+
lines.push(
|
|
31
|
+
`Runtime: ${resident.mode}${resident.resident ? ` (${resident.transport.activeSessions} sessions)` : " (standalone)"}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
25
34
|
lines.push("");
|
|
26
35
|
|
|
27
36
|
if (status.collections.length === 0) {
|
|
@@ -78,6 +87,8 @@ export function handleStatus(
|
|
|
78
87
|
return {
|
|
79
88
|
...result.value,
|
|
80
89
|
configPath: ctx.actualConfigPath,
|
|
90
|
+
resident:
|
|
91
|
+
ctx.getResidentStatus?.() ?? createStandaloneResidentStatus("stdio"),
|
|
81
92
|
};
|
|
82
93
|
},
|
|
83
94
|
formatStatus
|
package/src/mcp/tools/sync.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { ToolContext } from "../server";
|
|
|
11
11
|
import { MCP_ERRORS } from "../../core/errors";
|
|
12
12
|
import { acquireWriteLock, type WriteLockHandle } from "../../core/file-lock";
|
|
13
13
|
import { JobError } from "../../core/job-manager";
|
|
14
|
+
import { recordContentMutation } from "../../core/mutation-generations";
|
|
14
15
|
import { normalizeCollectionName } from "../../core/validation";
|
|
15
16
|
import { defaultSyncService, withContentTypeRules } from "../../ingestion";
|
|
16
17
|
import { runTool, type ToolResult } from "./index";
|
|
@@ -113,20 +114,21 @@ export function handleSync(
|
|
|
113
114
|
"sync",
|
|
114
115
|
lock,
|
|
115
116
|
async () => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
);
|
|
117
|
+
const result = collection
|
|
118
|
+
? wrapSingleSync(
|
|
119
|
+
await defaultSyncService.syncCollection(
|
|
120
|
+
collection,
|
|
121
|
+
ctx.store,
|
|
122
|
+
options
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
: await defaultSyncService.syncAll(
|
|
126
|
+
ctx.collections,
|
|
127
|
+
ctx.store,
|
|
128
|
+
options
|
|
129
|
+
);
|
|
130
|
+
recordContentMutation(result, ctx.markContentMutation);
|
|
131
|
+
return result;
|
|
130
132
|
}
|
|
131
133
|
);
|
|
132
134
|
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
planMoveRefactor,
|
|
28
28
|
planRenameRefactor,
|
|
29
29
|
} from "../../core/file-refactors";
|
|
30
|
+
import { recordContentMutation } from "../../core/mutation-generations";
|
|
30
31
|
import { defaultSyncService, withContentTypeRules } from "../../ingestion";
|
|
31
32
|
import { runTool, type ToolResult } from "./index";
|
|
32
33
|
|
|
@@ -210,11 +211,12 @@ export function handleRenameNote(
|
|
|
210
211
|
const currentPath = join(collection.path, doc.relPath);
|
|
211
212
|
const nextPath = join(collection.path, plan.nextRelPath);
|
|
212
213
|
await renameFilePath(currentPath, nextPath);
|
|
213
|
-
await defaultSyncService.syncCollection(
|
|
214
|
+
const syncResult = await defaultSyncService.syncCollection(
|
|
214
215
|
collection,
|
|
215
216
|
ctx.store,
|
|
216
217
|
withContentTypeRules({ runUpdateCmd: false }, ctx.config)
|
|
217
218
|
);
|
|
219
|
+
recordContentMutation(syncResult, ctx.markContentMutation);
|
|
218
220
|
return {
|
|
219
221
|
uri: plan.nextUri,
|
|
220
222
|
relPath: plan.nextRelPath,
|
|
@@ -255,11 +257,12 @@ export function handleMoveNote(
|
|
|
255
257
|
const nextPath = join(collection.path, plan.nextRelPath);
|
|
256
258
|
await mkdir(dirname(nextPath), { recursive: true });
|
|
257
259
|
await renameFilePath(currentPath, nextPath);
|
|
258
|
-
await defaultSyncService.syncCollection(
|
|
260
|
+
const syncResult = await defaultSyncService.syncCollection(
|
|
259
261
|
collection,
|
|
260
262
|
ctx.store,
|
|
261
263
|
withContentTypeRules({ runUpdateCmd: false }, ctx.config)
|
|
262
264
|
);
|
|
265
|
+
recordContentMutation(syncResult, ctx.markContentMutation);
|
|
263
266
|
return {
|
|
264
267
|
uri: plan.nextUri,
|
|
265
268
|
relPath: plan.nextRelPath,
|
|
@@ -308,11 +311,12 @@ export function handleDuplicateNote(
|
|
|
308
311
|
const nextPath = join(collection.path, plan.nextRelPath);
|
|
309
312
|
await mkdir(dirname(nextPath), { recursive: true });
|
|
310
313
|
await copyFilePath(currentPath, nextPath);
|
|
311
|
-
await defaultSyncService.syncCollection(
|
|
314
|
+
const syncResult = await defaultSyncService.syncCollection(
|
|
312
315
|
collection,
|
|
313
316
|
ctx.store,
|
|
314
317
|
withContentTypeRules({ runUpdateCmd: false }, ctx.config)
|
|
315
318
|
);
|
|
319
|
+
recordContentMutation(syncResult, ctx.markContentMutation);
|
|
316
320
|
return {
|
|
317
321
|
uri: plan.nextUri,
|
|
318
322
|
relPath: plan.nextRelPath,
|