@gmickel/gno 2.5.1 → 2.6.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 +60 -5
- package/assets/skill/README.md +5 -1
- package/assets/skill/SKILL.md +75 -1
- package/assets/skill/cli-reference.md +123 -0
- package/assets/skill/examples.md +30 -0
- package/assets/skill/mcp-reference.md +52 -0
- package/assets/skill/recipes/capture-and-file.md +6 -0
- package/assets/skill/recipes/memory-file-decision.md +6 -0
- package/assets/skill/recipes/memory-supersede-fact.md +5 -0
- package/assets/skill/recipes/session-evidence-lookup.md +98 -0
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/{gno-browser-clipper-v2.5.1.zip → gno-browser-clipper-v2.6.0.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.6.0.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +2 -1
- package/spec/cli.md +347 -24
- package/spec/mcp.md +198 -2
- package/spec/output-schemas/capture-receipt.schema.json +3 -0
- package/spec/output-schemas/mcp-capture-result.schema.json +3 -0
- package/spec/output-schemas/memory-remember.schema.json +8 -2
- package/spec/output-schemas/request-status.schema.json +113 -0
- package/spec/output-schemas/sessions-automation-run.schema.json +46 -0
- package/spec/output-schemas/sessions-discovery.schema.json +38 -0
- package/spec/output-schemas/sessions-import-receipt.schema.json +156 -0
- package/spec/output-schemas/sessions-status.schema.json +432 -0
- package/src/cli/commands/ask.ts +14 -2
- package/src/cli/commands/capture.ts +55 -96
- package/src/cli/commands/daemon.ts +41 -0
- package/src/cli/commands/ls.ts +3 -0
- package/src/cli/commands/memory.ts +12 -3
- package/src/cli/commands/request-status.ts +59 -0
- package/src/cli/commands/reset.ts +39 -5
- package/src/cli/commands/sessions.ts +713 -0
- package/src/cli/commands/shared.ts +14 -1
- package/src/cli/program.ts +388 -1
- package/src/cli/session-binding.ts +49 -0
- package/src/config/types.ts +8 -0
- package/src/core/capture-publish.ts +239 -0
- package/src/core/capture-sync.ts +3 -0
- package/src/core/memory-remember.ts +233 -122
- package/src/core/memory-types.ts +11 -0
- package/src/core/network-boundary-inventory.ts +8 -0
- package/src/core/request-receipts.ts +671 -0
- package/src/index.ts +9 -0
- package/src/mcp/context.ts +8 -0
- package/src/mcp/http-egress.ts +4 -0
- package/src/mcp/http-transport.ts +2 -0
- package/src/mcp/tools/capture.ts +87 -83
- package/src/mcp/tools/index.ts +66 -0
- package/src/mcp/tools/memory-remember.ts +7 -0
- package/src/mcp/tools/memory-shared.ts +7 -1
- package/src/mcp/tools/request-status.ts +73 -0
- package/src/mcp/tools/sessions.ts +208 -0
- package/src/sdk/client.ts +180 -84
- package/src/sdk/index.ts +6 -0
- package/src/sdk/types.ts +54 -2
- package/src/serve/capture-service.ts +98 -32
- package/src/serve/config-sync.ts +3 -2
- package/src/serve/public/app.tsx +4 -1
- package/src/serve/public/components/CaptureModal.tsx +26 -8
- package/src/serve/public/components/sessions/AutomationPanel.tsx +800 -0
- package/src/serve/public/components/sessions/ImportReceipt.tsx +238 -0
- package/src/serve/public/components/sessions/SessionSearch.tsx +286 -0
- package/src/serve/public/components/sessions/SourcesPanel.tsx +541 -0
- package/src/serve/public/components/sessions/api.ts +40 -0
- package/src/serve/public/components/sessions/snippet.tsx +53 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/hooks/use-api.ts +10 -2
- package/src/serve/public/lib/request-intent.ts +69 -0
- package/src/serve/public/lib/workspace-actions.ts +12 -1
- package/src/serve/public/lib/workspace-tabs.ts +2 -0
- package/src/serve/public/pages/Dashboard.tsx +10 -0
- package/src/serve/public/pages/DocView.tsx +15 -1
- package/src/serve/public/pages/DocumentEditor.tsx +139 -96
- package/src/serve/public/pages/Sessions.tsx +350 -0
- package/src/serve/resident-runtime.ts +43 -3
- package/src/serve/routes/api.ts +476 -147
- package/src/serve/routes/sessions.ts +766 -0
- package/src/serve/security.ts +9 -0
- package/src/serve/server.ts +205 -1
- package/src/serve/session-automation.ts +146 -0
- package/src/sessions/archive.ts +348 -0
- package/src/sessions/automation-state.ts +444 -0
- package/src/sessions/automation-status.ts +239 -0
- package/src/sessions/automation.ts +1169 -0
- package/src/sessions/binding.ts +105 -0
- package/src/sessions/claude-hook.ts +240 -0
- package/src/sessions/config.ts +176 -0
- package/src/sessions/format.ts +191 -0
- package/src/sessions/import-child-env.ts +8 -0
- package/src/sessions/import-child.ts +152 -0
- package/src/sessions/parsers/claude-code.ts +259 -0
- package/src/sessions/parsers/codex.ts +303 -0
- package/src/sessions/parsers/hermes.ts +248 -0
- package/src/sessions/parsers/openclaw.ts +496 -0
- package/src/sessions/parsers/shared.ts +184 -0
- package/src/sessions/sanitize.ts +222 -0
- package/src/sessions/service.ts +1533 -0
- package/src/sessions/setup.ts +477 -0
- package/src/sessions/sources.ts +518 -0
- package/src/sessions/state.ts +118 -0
- package/src/sessions/types.ts +457 -0
- package/src/store/sqlite/adapter.ts +54 -15
- package/src/store/sqlite/scoped-index.ts +9 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.5.1.zip.sha256 +0 -1
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP session-archive tools: bounded status (including opt-in automation),
|
|
3
|
+
* import of owner-registered sources, and a run request for a configured
|
|
4
|
+
* automation profile. Thin adapters over the core sessions services. Hooks,
|
|
5
|
+
* schedules and source access are managed only by the local owner.
|
|
6
|
+
*
|
|
7
|
+
* Remote callers never discover host directories and never name paths:
|
|
8
|
+
* import accepts a registered source ID only. Import is registered only with
|
|
9
|
+
* `--enable-write`, and neither tool is part of the core profile.
|
|
10
|
+
*
|
|
11
|
+
* @module src/mcp/tools/sessions
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
|
|
16
|
+
import type { ToolContext } from "../server";
|
|
17
|
+
|
|
18
|
+
import { runAutomationProfile } from "../../sessions/automation";
|
|
19
|
+
import {
|
|
20
|
+
formatAutomationRunText,
|
|
21
|
+
formatImportReceiptText,
|
|
22
|
+
formatStatusText,
|
|
23
|
+
} from "../../sessions/format";
|
|
24
|
+
import { importInChildProcess } from "../../sessions/import-child";
|
|
25
|
+
import { SessionsService } from "../../sessions/service";
|
|
26
|
+
import {
|
|
27
|
+
MAX_IMPORT_LIMIT,
|
|
28
|
+
type SessionAutomationRunResult,
|
|
29
|
+
type SessionImportReceipt,
|
|
30
|
+
remoteSafeSessionsError,
|
|
31
|
+
} from "../../sessions/types";
|
|
32
|
+
import { runTool, type ToolResult } from "./index";
|
|
33
|
+
|
|
34
|
+
export const sessionsStatusInputSchema = z.object({});
|
|
35
|
+
|
|
36
|
+
export const sessionsImportInputSchema = z
|
|
37
|
+
.object({
|
|
38
|
+
sourceId: z
|
|
39
|
+
.string()
|
|
40
|
+
.trim()
|
|
41
|
+
.min(1)
|
|
42
|
+
.max(64)
|
|
43
|
+
.describe(
|
|
44
|
+
"ID of an owner-registered session source (see gno_sessions_status)"
|
|
45
|
+
),
|
|
46
|
+
dryRun: z
|
|
47
|
+
.boolean()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe("Parse and report without writing archive or index state"),
|
|
50
|
+
limit: z
|
|
51
|
+
.number()
|
|
52
|
+
.int()
|
|
53
|
+
.min(1)
|
|
54
|
+
.max(MAX_IMPORT_LIMIT)
|
|
55
|
+
.optional()
|
|
56
|
+
.describe(
|
|
57
|
+
"Maximum changed units processed this call; the rest are deferred"
|
|
58
|
+
),
|
|
59
|
+
})
|
|
60
|
+
.strict();
|
|
61
|
+
|
|
62
|
+
export type SessionsImportToolInput = z.infer<typeof sessionsImportInputSchema>;
|
|
63
|
+
|
|
64
|
+
export const sessionsAutomationRunInputSchema = z
|
|
65
|
+
.object({
|
|
66
|
+
profileId: z
|
|
67
|
+
.string()
|
|
68
|
+
.trim()
|
|
69
|
+
.min(1)
|
|
70
|
+
.max(64)
|
|
71
|
+
.describe(
|
|
72
|
+
"ID of an owner-configured automation profile (see gno_sessions_status)"
|
|
73
|
+
),
|
|
74
|
+
})
|
|
75
|
+
.strict();
|
|
76
|
+
|
|
77
|
+
export type SessionsAutomationRunToolInput = z.infer<
|
|
78
|
+
typeof sessionsAutomationRunInputSchema
|
|
79
|
+
>;
|
|
80
|
+
|
|
81
|
+
export const SESSIONS_AUTOMATION_RUN_MCP_ANNOTATIONS = {
|
|
82
|
+
readOnlyHint: false,
|
|
83
|
+
destructiveHint: false,
|
|
84
|
+
idempotentHint: true,
|
|
85
|
+
openWorldHint: false,
|
|
86
|
+
} as const;
|
|
87
|
+
|
|
88
|
+
export const SESSIONS_STATUS_MCP_ANNOTATIONS = {
|
|
89
|
+
readOnlyHint: true,
|
|
90
|
+
destructiveHint: false,
|
|
91
|
+
idempotentHint: true,
|
|
92
|
+
openWorldHint: false,
|
|
93
|
+
} as const;
|
|
94
|
+
|
|
95
|
+
export const SESSIONS_IMPORT_MCP_ANNOTATIONS = {
|
|
96
|
+
readOnlyHint: false,
|
|
97
|
+
destructiveHint: false,
|
|
98
|
+
idempotentHint: true,
|
|
99
|
+
openWorldHint: false,
|
|
100
|
+
} as const;
|
|
101
|
+
|
|
102
|
+
function service(ctx: ToolContext): SessionsService {
|
|
103
|
+
return new SessionsService({
|
|
104
|
+
config: ctx.config,
|
|
105
|
+
configPath: ctx.actualConfigPath,
|
|
106
|
+
indexName: ctx.indexName,
|
|
107
|
+
store: ctx.store,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Re-throw as `CODE: message` (the shape runTool parses), never with host paths. */
|
|
112
|
+
function rethrowSessionsError(error: unknown): never {
|
|
113
|
+
const typed = remoteSafeSessionsError(error);
|
|
114
|
+
throw new Error(`${typed.code}: ${typed.message}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function handleSessionsStatus(ctx: ToolContext): Promise<ToolResult> {
|
|
118
|
+
return runTool(
|
|
119
|
+
ctx,
|
|
120
|
+
"gno_sessions_status",
|
|
121
|
+
async () => {
|
|
122
|
+
try {
|
|
123
|
+
return await service(ctx).status();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
return rethrowSessionsError(error);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
formatStatusText
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function handleSessionsImport(
|
|
133
|
+
args: SessionsImportToolInput,
|
|
134
|
+
ctx: ToolContext
|
|
135
|
+
): Promise<ToolResult> {
|
|
136
|
+
return runTool(
|
|
137
|
+
ctx,
|
|
138
|
+
"gno_sessions_import",
|
|
139
|
+
async () => {
|
|
140
|
+
if (!ctx.enableWrite) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
"WRITE_DISABLED: gno_sessions_import requires --enable-write or GNO_MCP_ENABLE_WRITE=1"
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
let receipt: SessionImportReceipt;
|
|
146
|
+
try {
|
|
147
|
+
// A child process keeps this server answering during a long import.
|
|
148
|
+
receipt = await importInChildProcess({
|
|
149
|
+
config: ctx.config,
|
|
150
|
+
configPath: ctx.actualConfigPath,
|
|
151
|
+
indexName: ctx.indexName,
|
|
152
|
+
sourceId: args.sourceId,
|
|
153
|
+
dryRun: args.dryRun === true,
|
|
154
|
+
limit: args.limit,
|
|
155
|
+
});
|
|
156
|
+
} catch (error) {
|
|
157
|
+
return rethrowSessionsError(error);
|
|
158
|
+
}
|
|
159
|
+
if (!receipt.dryRun && receipt.lexical.collections.length > 0) {
|
|
160
|
+
ctx.markContentMutation?.();
|
|
161
|
+
ctx.markIndexMutation?.();
|
|
162
|
+
}
|
|
163
|
+
return receipt;
|
|
164
|
+
},
|
|
165
|
+
formatImportReceiptText
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function handleSessionsAutomationRun(
|
|
170
|
+
args: SessionsAutomationRunToolInput,
|
|
171
|
+
ctx: ToolContext
|
|
172
|
+
): Promise<ToolResult> {
|
|
173
|
+
return runTool(
|
|
174
|
+
ctx,
|
|
175
|
+
"gno_sessions_automation_run",
|
|
176
|
+
async () => {
|
|
177
|
+
if (!ctx.enableWrite) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
"WRITE_DISABLED: gno_sessions_automation_run requires --enable-write or GNO_MCP_ENABLE_WRITE=1"
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
let result: SessionAutomationRunResult;
|
|
183
|
+
try {
|
|
184
|
+
result = await runAutomationProfile(
|
|
185
|
+
{
|
|
186
|
+
configPath: ctx.actualConfigPath,
|
|
187
|
+
indexName: ctx.indexName,
|
|
188
|
+
store: ctx.store,
|
|
189
|
+
// A child process keeps this server answering during the run.
|
|
190
|
+
inChildProcess: true,
|
|
191
|
+
},
|
|
192
|
+
args.profileId,
|
|
193
|
+
{ trigger: "manual" }
|
|
194
|
+
);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
return rethrowSessionsError(error);
|
|
197
|
+
}
|
|
198
|
+
if (
|
|
199
|
+
result.receipts.some((receipt) => receipt.lexical.collections.length)
|
|
200
|
+
) {
|
|
201
|
+
ctx.markContentMutation?.();
|
|
202
|
+
ctx.markIndexMutation?.();
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
},
|
|
206
|
+
formatAutomationRunText
|
|
207
|
+
);
|
|
208
|
+
}
|
package/src/sdk/client.ts
CHANGED
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
GnoCaptureOptions,
|
|
22
22
|
GnoCaptureResult,
|
|
23
23
|
GnoClient,
|
|
24
|
+
GnoRequestStatusResult,
|
|
24
25
|
GnoCreateFolderOptions,
|
|
25
26
|
GnoCreateFolderResult,
|
|
26
27
|
GnoCreateNoteOptions,
|
|
@@ -49,6 +50,11 @@ import type {
|
|
|
49
50
|
GnoRenameNoteApplyOptions,
|
|
50
51
|
GnoRenameNoteOptions,
|
|
51
52
|
GnoSearchOptions,
|
|
53
|
+
GnoSessionsAutomationRunResult,
|
|
54
|
+
GnoSessionsDiscovery,
|
|
55
|
+
GnoSessionsImportInput,
|
|
56
|
+
GnoSessionsImportReceipt,
|
|
57
|
+
GnoSessionsStatus,
|
|
52
58
|
GnoUpdateOptions,
|
|
53
59
|
GnoVectorSearchOptions,
|
|
54
60
|
KnowledgeChangesResult,
|
|
@@ -90,17 +96,17 @@ import { buildVerifiedAsk } from "../app/verified-ask";
|
|
|
90
96
|
import {
|
|
91
97
|
buildContentTypeBoostStatus,
|
|
92
98
|
ConfigSchema,
|
|
99
|
+
getConfigPaths,
|
|
93
100
|
loadConfig,
|
|
94
101
|
normalizeConfigContentTypes,
|
|
95
102
|
normalizeContentTypes,
|
|
96
103
|
} from "../config";
|
|
97
104
|
import {
|
|
98
|
-
|
|
99
|
-
type CapturePlan,
|
|
105
|
+
CaptureSyncError,
|
|
100
106
|
listCaptureDiskRelPaths,
|
|
101
107
|
planCapture,
|
|
102
108
|
} from "../core/capture";
|
|
103
|
-
import {
|
|
109
|
+
import { publishCapture } from "../core/capture-publish";
|
|
104
110
|
import { projectCollectionEgressPolicy } from "../core/collection-egress-policy-projection";
|
|
105
111
|
import { CollectionEgressPolicyService } from "../core/collection-egress-policy-service";
|
|
106
112
|
import { applyConfigChange } from "../core/config-mutation";
|
|
@@ -140,6 +146,12 @@ import {
|
|
|
140
146
|
ProjectAffinityInputError,
|
|
141
147
|
resolveRemoteProjectAffinity,
|
|
142
148
|
} from "../core/project-affinity-surface";
|
|
149
|
+
import {
|
|
150
|
+
localRequestLedger,
|
|
151
|
+
readRequestStatus,
|
|
152
|
+
RequestReceiptError,
|
|
153
|
+
type RequestReceiptErrorCode,
|
|
154
|
+
} from "../core/request-receipts";
|
|
143
155
|
import { RetrievalTraceManagementService } from "../core/retrieval-trace-management";
|
|
144
156
|
import {
|
|
145
157
|
finishRetrievalTraceAfterError,
|
|
@@ -169,7 +181,6 @@ import {
|
|
|
169
181
|
normalizeMetadataPredicate,
|
|
170
182
|
type MetadataPredicate,
|
|
171
183
|
} from "../core/typed-metadata";
|
|
172
|
-
import { writeLeasePath } from "../core/write-lease";
|
|
173
184
|
import {
|
|
174
185
|
defaultSyncService,
|
|
175
186
|
type SyncResult,
|
|
@@ -193,6 +204,10 @@ import { searchHybrid } from "../pipeline/hybrid";
|
|
|
193
204
|
import { RequestHydration } from "../pipeline/hydration";
|
|
194
205
|
import { searchBm25 } from "../pipeline/search";
|
|
195
206
|
import { searchVectorWithEmbedding } from "../pipeline/vsearch";
|
|
207
|
+
import { runAutomationProfile } from "../sessions/automation";
|
|
208
|
+
import { assertSessionBinding } from "../sessions/binding";
|
|
209
|
+
import { SessionsService } from "../sessions/service";
|
|
210
|
+
import { SESSIONS_VALIDATION_CODES, SessionsError } from "../sessions/types";
|
|
196
211
|
import { SqliteAdapter } from "../store/sqlite/adapter";
|
|
197
212
|
import { openScopedIndexStore } from "../store/sqlite/scoped-index";
|
|
198
213
|
import { createVectorIndexPort } from "../store/vector";
|
|
@@ -314,6 +329,19 @@ async function resolveClientState(
|
|
|
314
329
|
options.indexName ?? DEFAULT_INDEX_NAME
|
|
315
330
|
);
|
|
316
331
|
const dbPath = options.dbPath ?? getIndexDbPath(indexName);
|
|
332
|
+
try {
|
|
333
|
+
await assertSessionBinding({
|
|
334
|
+
config,
|
|
335
|
+
configPath:
|
|
336
|
+
configSource === "inline"
|
|
337
|
+
? "<inline-config>"
|
|
338
|
+
: (options.configPath ?? getConfigPaths().configFile),
|
|
339
|
+
indexName,
|
|
340
|
+
dbPath,
|
|
341
|
+
});
|
|
342
|
+
} catch (cause) {
|
|
343
|
+
throw toSessionsSdkError(cause);
|
|
344
|
+
}
|
|
317
345
|
await mkdir(dirname(dbPath), { recursive: true });
|
|
318
346
|
|
|
319
347
|
const store = new SqliteAdapter();
|
|
@@ -337,6 +365,16 @@ async function resolveClientState(
|
|
|
337
365
|
};
|
|
338
366
|
}
|
|
339
367
|
|
|
368
|
+
/** Map a sessions error onto the SDK family; the sessions code survives in `details.code`. */
|
|
369
|
+
function toSessionsSdkError(cause: unknown): unknown {
|
|
370
|
+
if (!(cause instanceof SessionsError)) return cause;
|
|
371
|
+
return sdkError(
|
|
372
|
+
SESSIONS_VALIDATION_CODES.has(cause.code) ? "VALIDATION" : "RUNTIME",
|
|
373
|
+
cause.message,
|
|
374
|
+
{ cause, details: { code: cause.code } }
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
|
|
340
378
|
/** SDK error family per memory code; exhaustive so a new code fails to compile. */
|
|
341
379
|
const MEMORY_ERROR_TO_SDK: Readonly<Record<MemoryErrorCode, GnoSdkErrorCode>> =
|
|
342
380
|
{
|
|
@@ -363,9 +401,28 @@ const MEMORY_ERROR_TO_SDK: Readonly<Record<MemoryErrorCode, GnoSdkErrorCode>> =
|
|
|
363
401
|
MEMORY_QUERY_FAILED: "RUNTIME",
|
|
364
402
|
};
|
|
365
403
|
|
|
404
|
+
const REQUEST_ERROR_TO_SDK: Record<RequestReceiptErrorCode, GnoSdkErrorCode> = {
|
|
405
|
+
REQUEST_ID_INVALID: "VALIDATION",
|
|
406
|
+
REQUEST_ID_CONFLICT: "VALIDATION",
|
|
407
|
+
REQUEST_EXPIRED: "VALIDATION",
|
|
408
|
+
REQUEST_PENDING: "RUNTIME",
|
|
409
|
+
REQUEST_RECOVERY_CONFLICT: "RUNTIME",
|
|
410
|
+
REQUEST_CAPACITY_EXHAUSTED: "RUNTIME",
|
|
411
|
+
REQUEST_LEDGER_UNAVAILABLE: "RUNTIME",
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
/** Request receipt errors carry their stable code in `details.code`. */
|
|
415
|
+
function toRequestSdkError(cause: unknown): unknown {
|
|
416
|
+
if (!(cause instanceof RequestReceiptError)) return cause;
|
|
417
|
+
return sdkError(REQUEST_ERROR_TO_SDK[cause.code], cause.message, {
|
|
418
|
+
cause,
|
|
419
|
+
details: { code: cause.code },
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
366
423
|
/** Map a core MemoryError onto the SDK error family; the memory code survives in `details.code`. */
|
|
367
424
|
function toMemorySdkError(cause: unknown): unknown {
|
|
368
|
-
if (!(cause instanceof MemoryError)) return cause;
|
|
425
|
+
if (!(cause instanceof MemoryError)) return toRequestSdkError(cause);
|
|
369
426
|
return sdkError(MEMORY_ERROR_TO_SDK[cause.code], cause.message, {
|
|
370
427
|
cause,
|
|
371
428
|
details: { code: cause.code },
|
|
@@ -1345,6 +1402,8 @@ class GnoClientImpl implements GnoClient {
|
|
|
1345
1402
|
requestedIndexName: resolution.value.indexName,
|
|
1346
1403
|
config: this.config,
|
|
1347
1404
|
configPath: this.configPath,
|
|
1405
|
+
}).catch((cause: unknown) => {
|
|
1406
|
+
throw toSessionsSdkError(cause);
|
|
1348
1407
|
});
|
|
1349
1408
|
try {
|
|
1350
1409
|
const result = await getDocumentByRef(
|
|
@@ -1384,6 +1443,8 @@ class GnoClientImpl implements GnoClient {
|
|
|
1384
1443
|
requestedIndexName: resolution.value.indexName,
|
|
1385
1444
|
config: this.config,
|
|
1386
1445
|
configPath: this.configPath,
|
|
1446
|
+
}).catch((cause: unknown) => {
|
|
1447
|
+
throw toSessionsSdkError(cause);
|
|
1387
1448
|
});
|
|
1388
1449
|
try {
|
|
1389
1450
|
const result = await multiGetDocuments(
|
|
@@ -1790,7 +1851,8 @@ class GnoClientImpl implements GnoClient {
|
|
|
1790
1851
|
store: this.store,
|
|
1791
1852
|
config: this.config,
|
|
1792
1853
|
collections: this.config.collections,
|
|
1793
|
-
lockPath:
|
|
1854
|
+
lockPath: this.requestLedger().lockPath,
|
|
1855
|
+
requests: this.requestLedger(),
|
|
1794
1856
|
embedPort: ports.embedPort,
|
|
1795
1857
|
vectorIndex: ports.vectorIndex,
|
|
1796
1858
|
})
|
|
@@ -1802,6 +1864,62 @@ class GnoClientImpl implements GnoClient {
|
|
|
1802
1864
|
}
|
|
1803
1865
|
}
|
|
1804
1866
|
|
|
1867
|
+
private sessionsService(): SessionsService {
|
|
1868
|
+
this.assertOpen();
|
|
1869
|
+
return new SessionsService({
|
|
1870
|
+
config: this.config,
|
|
1871
|
+
configPath: this.configPath ?? getConfigPaths().configFile,
|
|
1872
|
+
indexName: this.indexName,
|
|
1873
|
+
store: this.store,
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
async sessionsStatus(): Promise<GnoSessionsStatus> {
|
|
1878
|
+
try {
|
|
1879
|
+
return await this.sessionsService().status();
|
|
1880
|
+
} catch (cause) {
|
|
1881
|
+
throw toSessionsSdkError(cause);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
async discoverSessions(): Promise<GnoSessionsDiscovery> {
|
|
1886
|
+
try {
|
|
1887
|
+
return await this.sessionsService().discover();
|
|
1888
|
+
} catch (cause) {
|
|
1889
|
+
throw toSessionsSdkError(cause);
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
async importSessions(
|
|
1894
|
+
input: GnoSessionsImportInput
|
|
1895
|
+
): Promise<GnoSessionsImportReceipt> {
|
|
1896
|
+
try {
|
|
1897
|
+
// The SDK runs in the owner's process, so explicit paths are allowed.
|
|
1898
|
+
return await this.sessionsService().import(input, { allowPaths: true });
|
|
1899
|
+
} catch (cause) {
|
|
1900
|
+
throw toSessionsSdkError(cause);
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
async runSessionsAutomation(input: {
|
|
1905
|
+
profileId: string;
|
|
1906
|
+
}): Promise<GnoSessionsAutomationRunResult> {
|
|
1907
|
+
this.assertOpen();
|
|
1908
|
+
try {
|
|
1909
|
+
return await runAutomationProfile(
|
|
1910
|
+
{
|
|
1911
|
+
configPath: this.configPath ?? getConfigPaths().configFile,
|
|
1912
|
+
indexName: this.indexName,
|
|
1913
|
+
store: this.store,
|
|
1914
|
+
},
|
|
1915
|
+
input.profileId,
|
|
1916
|
+
{ trigger: "manual" }
|
|
1917
|
+
);
|
|
1918
|
+
} catch (cause) {
|
|
1919
|
+
throw toSessionsSdkError(cause);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1805
1923
|
async remember(input: GnoRememberInput): Promise<GnoRememberResult> {
|
|
1806
1924
|
return this.withMemoryService(input?.collection, (service) =>
|
|
1807
1925
|
service.remember(input)
|
|
@@ -1823,98 +1941,76 @@ class GnoClientImpl implements GnoClient {
|
|
|
1823
1941
|
`Collection not found: ${options.collection}`
|
|
1824
1942
|
);
|
|
1825
1943
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
});
|
|
1832
|
-
}
|
|
1833
|
-
const { overwrite: _unsupportedOverwrite, ...captureOptions } =
|
|
1834
|
-
options as GnoCaptureOptions & { overwrite?: unknown };
|
|
1944
|
+
const {
|
|
1945
|
+
overwrite: _unsupportedOverwrite,
|
|
1946
|
+
requestId,
|
|
1947
|
+
...captureOptions
|
|
1948
|
+
} = options as GnoCaptureOptions & { overwrite?: unknown };
|
|
1835
1949
|
if (_unsupportedOverwrite !== undefined) {
|
|
1836
1950
|
throw sdkError(
|
|
1837
1951
|
"VALIDATION",
|
|
1838
1952
|
"overwrite is not supported by client.capture(); use collisionPolicy instead"
|
|
1839
1953
|
);
|
|
1840
1954
|
}
|
|
1955
|
+
const input = { ...captureOptions, collection: collection.name };
|
|
1841
1956
|
|
|
1842
|
-
let plan: CapturePlan;
|
|
1843
1957
|
try {
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1958
|
+
const published = await publishCapture({
|
|
1959
|
+
collection,
|
|
1960
|
+
store: this.store,
|
|
1961
|
+
lockPath: this.requestLedger().lockPath,
|
|
1962
|
+
reportSyncFailure: true,
|
|
1963
|
+
config: this.config,
|
|
1964
|
+
plan: async () => {
|
|
1965
|
+
const existingList = await this.store.listDocuments(collection.name);
|
|
1966
|
+
if (!existingList.ok) {
|
|
1967
|
+
throw sdkError("STORE", existingList.error.message, {
|
|
1968
|
+
cause: existingList.error.cause,
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
try {
|
|
1972
|
+
return planCapture({
|
|
1973
|
+
input,
|
|
1974
|
+
existingRelPaths: existingList.value.map((doc) => doc.relPath),
|
|
1975
|
+
diskRelPaths: await listCaptureDiskRelPaths(collection.path),
|
|
1976
|
+
});
|
|
1977
|
+
} catch (error) {
|
|
1978
|
+
throw sdkError(
|
|
1979
|
+
"VALIDATION",
|
|
1980
|
+
error instanceof Error ? error.message : String(error)
|
|
1981
|
+
);
|
|
1982
|
+
}
|
|
1848
1983
|
},
|
|
1849
|
-
|
|
1850
|
-
|
|
1984
|
+
request:
|
|
1985
|
+
requestId === undefined
|
|
1986
|
+
? undefined
|
|
1987
|
+
: { ...this.requestLedger(), requestId, input },
|
|
1851
1988
|
});
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
)
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
if (plan.openedExisting) {
|
|
1861
|
-
const existingDoc = await this.store.getDocument(
|
|
1862
|
-
collection.name,
|
|
1863
|
-
plan.relPath
|
|
1864
|
-
);
|
|
1865
|
-
if (!existingDoc.ok) {
|
|
1866
|
-
throw sdkError("STORE", existingDoc.error.message, {
|
|
1867
|
-
cause: existingDoc.error.cause,
|
|
1989
|
+
return published.request
|
|
1990
|
+
? { ...published.receipt, request: published.request }
|
|
1991
|
+
: published.receipt;
|
|
1992
|
+
} catch (cause) {
|
|
1993
|
+
if (cause instanceof CaptureSyncError) {
|
|
1994
|
+
throw sdkError("RUNTIME", cause.message, {
|
|
1995
|
+
cause,
|
|
1996
|
+
details: { code: cause.code, absPath: cause.absPath },
|
|
1868
1997
|
});
|
|
1869
1998
|
}
|
|
1870
|
-
|
|
1871
|
-
plan,
|
|
1872
|
-
absPath: fullPath,
|
|
1873
|
-
docid: existingDoc.value?.docid,
|
|
1874
|
-
sync: existingDoc.value
|
|
1875
|
-
? { status: "completed" }
|
|
1876
|
-
: {
|
|
1877
|
-
status: "skipped",
|
|
1878
|
-
reason: "Existing file is not indexed yet.",
|
|
1879
|
-
},
|
|
1880
|
-
});
|
|
1999
|
+
throw toRequestSdkError(cause);
|
|
1881
2000
|
}
|
|
2001
|
+
}
|
|
1882
2002
|
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
this.config
|
|
1895
|
-
)
|
|
1896
|
-
);
|
|
1897
|
-
const syncResult = syncResults[0];
|
|
1898
|
-
const docResult = await this.store.getDocument(
|
|
1899
|
-
collection.name,
|
|
1900
|
-
plan.relPath
|
|
1901
|
-
);
|
|
1902
|
-
const docid = docResult.ok ? docResult.value?.docid : undefined;
|
|
1903
|
-
return buildCaptureReceipt({
|
|
1904
|
-
plan,
|
|
1905
|
-
absPath: fullPath,
|
|
1906
|
-
docid: syncResult?.docid ?? docid,
|
|
1907
|
-
sync:
|
|
1908
|
-
syncResult?.status === "error"
|
|
1909
|
-
? {
|
|
1910
|
-
status: "failed",
|
|
1911
|
-
error:
|
|
1912
|
-
syncResult.errorMessage ??
|
|
1913
|
-
syncResult.errorCode ??
|
|
1914
|
-
"Unknown sync error",
|
|
1915
|
-
}
|
|
1916
|
-
: { status: "completed" },
|
|
1917
|
-
});
|
|
2003
|
+
private requestLedger() {
|
|
2004
|
+
return localRequestLedger(this.dbPath);
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
async requestStatus(requestId: string): Promise<GnoRequestStatusResult> {
|
|
2008
|
+
this.assertOpen();
|
|
2009
|
+
try {
|
|
2010
|
+
return await readRequestStatus({ ...this.requestLedger(), requestId });
|
|
2011
|
+
} catch (cause) {
|
|
2012
|
+
throw toRequestSdkError(cause);
|
|
2013
|
+
}
|
|
1918
2014
|
}
|
|
1919
2015
|
|
|
1920
2016
|
async createFolder(
|
package/src/sdk/index.ts
CHANGED
|
@@ -62,10 +62,16 @@ export type {
|
|
|
62
62
|
GnoRecallResult,
|
|
63
63
|
GnoRememberInput,
|
|
64
64
|
GnoRememberResult,
|
|
65
|
+
GnoRequestStatusResult,
|
|
65
66
|
GnoRenameNoteApplyOptions,
|
|
66
67
|
GnoRenameNoteOptions,
|
|
67
68
|
GnoProjectHintOptions,
|
|
68
69
|
GnoSearchOptions,
|
|
70
|
+
GnoSessionsDiscovery,
|
|
71
|
+
GnoSessionsImportInput,
|
|
72
|
+
GnoSessionsImportReceipt,
|
|
73
|
+
GnoSessionsAutomationRunResult,
|
|
74
|
+
GnoSessionsStatus,
|
|
69
75
|
GnoSkippedDocument,
|
|
70
76
|
GnoUpdateOptions,
|
|
71
77
|
GnoVectorSearchOptions,
|
package/src/sdk/types.ts
CHANGED
|
@@ -67,6 +67,10 @@ import type {
|
|
|
67
67
|
} from "../core/memory";
|
|
68
68
|
import type { NoteCollisionPolicy } from "../core/note-creation";
|
|
69
69
|
import type { NotePresetId } from "../core/note-presets";
|
|
70
|
+
import type {
|
|
71
|
+
RequestReceiptInfo,
|
|
72
|
+
RequestStatusResult,
|
|
73
|
+
} from "../core/request-receipts";
|
|
70
74
|
import type {
|
|
71
75
|
RetrievalTraceDeleteResult,
|
|
72
76
|
RetrievalTraceDetail,
|
|
@@ -94,6 +98,13 @@ import type {
|
|
|
94
98
|
SearchOptions,
|
|
95
99
|
SearchResults,
|
|
96
100
|
} from "../pipeline/types";
|
|
101
|
+
import type { SessionImportInput } from "../sessions/service";
|
|
102
|
+
import type {
|
|
103
|
+
SessionAutomationRunResult,
|
|
104
|
+
SessionImportReceipt,
|
|
105
|
+
SessionsDiscovery,
|
|
106
|
+
SessionsStatus,
|
|
107
|
+
} from "../sessions/types";
|
|
97
108
|
import type { IndexStatus } from "../store/types";
|
|
98
109
|
|
|
99
110
|
export type {
|
|
@@ -263,11 +274,25 @@ export interface GnoCreateNoteResult {
|
|
|
263
274
|
createdWithSuffix?: boolean;
|
|
264
275
|
}
|
|
265
276
|
|
|
266
|
-
export interface GnoCaptureOptions extends Omit<CaptureInput, "overwrite"> {
|
|
277
|
+
export interface GnoCaptureOptions extends Omit<CaptureInput, "overwrite"> {
|
|
278
|
+
/** Opt-in retry identity; reuse it only to retry this same capture. */
|
|
279
|
+
requestId?: string;
|
|
280
|
+
}
|
|
267
281
|
|
|
268
|
-
export type GnoCaptureResult = CaptureReceipt
|
|
282
|
+
export type GnoCaptureResult = CaptureReceipt & {
|
|
283
|
+
/** Present when the call carried a requestId. */
|
|
284
|
+
request?: RequestReceiptInfo;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
/** Lookup of a capture/remember request ID in the local-owner namespace. */
|
|
288
|
+
export type GnoRequestStatusResult = RequestStatusResult;
|
|
269
289
|
|
|
270
290
|
/** Shared memory contract (identical on CLI, MCP, REST, and SDK). */
|
|
291
|
+
export type GnoSessionsStatus = SessionsStatus;
|
|
292
|
+
export type GnoSessionsDiscovery = SessionsDiscovery;
|
|
293
|
+
export type GnoSessionsImportReceipt = SessionImportReceipt;
|
|
294
|
+
export type GnoSessionsImportInput = SessionImportInput;
|
|
295
|
+
export type GnoSessionsAutomationRunResult = SessionAutomationRunResult;
|
|
271
296
|
export type GnoRememberInput = RememberInput;
|
|
272
297
|
export type GnoRememberResult = RememberResult;
|
|
273
298
|
export type GnoRecallInput = RecallInput;
|
|
@@ -414,6 +439,11 @@ export interface GnoClient {
|
|
|
414
439
|
embed(options?: GnoEmbedOptions): Promise<GnoEmbedResult>;
|
|
415
440
|
index(options?: GnoIndexOptions): Promise<GnoIndexResult>;
|
|
416
441
|
capture(options: GnoCaptureOptions): Promise<GnoCaptureResult>;
|
|
442
|
+
/**
|
|
443
|
+
* Look up a capture/remember `requestId` before retrying it: pending,
|
|
444
|
+
* committed (with a content-free result pointer), expired, or not_found.
|
|
445
|
+
*/
|
|
446
|
+
requestStatus(requestId: string): Promise<GnoRequestStatusResult>;
|
|
417
447
|
/**
|
|
418
448
|
* Store one fact in a memory-managed collection, or propose candidates when
|
|
419
449
|
* `decision` is omitted. Requires caller + session identity and explicit
|
|
@@ -425,6 +455,28 @@ export interface GnoClient {
|
|
|
425
455
|
* The result carries a content-free fencing receipt.
|
|
426
456
|
*/
|
|
427
457
|
recall(input: GnoRecallInput): Promise<GnoRecallResult>;
|
|
458
|
+
/**
|
|
459
|
+
* Session-archive status for a client opened on the dedicated archive
|
|
460
|
+
* config/index pair. Throws VALIDATION (`details.code`
|
|
461
|
+
* SESSIONS_NOT_CONFIGURED) on any other config.
|
|
462
|
+
*/
|
|
463
|
+
sessionsStatus(): Promise<GnoSessionsStatus>;
|
|
464
|
+
/** Preview supported local session sources on this host. Never imports. */
|
|
465
|
+
discoverSessions(): Promise<GnoSessionsDiscovery>;
|
|
466
|
+
/**
|
|
467
|
+
* Manually import a registered source (`sourceId`) or explicit local paths
|
|
468
|
+
* (`paths` + `collection`) into the archive. Returns the shared receipt.
|
|
469
|
+
*/
|
|
470
|
+
importSessions(
|
|
471
|
+
input: GnoSessionsImportInput
|
|
472
|
+
): Promise<GnoSessionsImportReceipt>;
|
|
473
|
+
/**
|
|
474
|
+
* Run one configured automation profile now through the manual importer.
|
|
475
|
+
* Hooks and schedules are enabled only from the CLI or a same-host browser.
|
|
476
|
+
*/
|
|
477
|
+
runSessionsAutomation(input: {
|
|
478
|
+
profileId: string;
|
|
479
|
+
}): Promise<GnoSessionsAutomationRunResult>;
|
|
428
480
|
createNote(options: GnoCreateNoteOptions): Promise<GnoCreateNoteResult>;
|
|
429
481
|
createFolder(options: GnoCreateFolderOptions): Promise<GnoCreateFolderResult>;
|
|
430
482
|
previewRenameNote(
|