@gmickel/gno 2.5.1 → 2.7.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 +80 -4
- package/assets/skill/cli-reference.md +132 -2
- package/assets/skill/examples.md +30 -0
- package/assets/skill/mcp-reference.md +54 -1
- 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.7.0.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.7.0.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +2 -1
- package/spec/cli.md +449 -35
- package/spec/mcp.md +234 -4
- package/spec/output-schemas/ask.schema.json +1 -1
- package/spec/output-schemas/capture-receipt.schema.json +4 -1
- package/spec/output-schemas/doctor.schema.json +88 -0
- package/spec/output-schemas/error.schema.json +11 -2
- package/spec/output-schemas/get.schema.json +1 -1
- package/spec/output-schemas/mcp-capture-result.schema.json +4 -2
- package/spec/output-schemas/memory-remember.schema.json +10 -4
- package/spec/output-schemas/multi-get.schema.json +4 -1
- package/spec/output-schemas/peek.schema.json +2 -9
- package/spec/output-schemas/request-status.schema.json +113 -0
- package/spec/output-schemas/resident-status.schema.json +22 -0
- package/spec/output-schemas/search-result.schema.json +1 -1
- package/spec/output-schemas/search-results.schema.json +1 -1
- 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/spec/output-schemas/status.schema.json +98 -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/doctor.ts +54 -20
- package/src/cli/commands/embed.ts +41 -3
- package/src/cli/commands/ls.ts +3 -0
- package/src/cli/commands/memory.ts +12 -3
- package/src/cli/commands/query.ts +5 -0
- 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/commands/status.ts +63 -5
- package/src/cli/commands/vec.ts +54 -0
- package/src/cli/detach.ts +29 -1
- package/src/cli/errors.ts +13 -9
- package/src/cli/program.ts +441 -2
- 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 +12 -2
- package/src/core/host-paths.ts +31 -0
- package/src/core/memory-remember.ts +234 -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/core/shutdown-budget.ts +6 -0
- package/src/core/vector-partition-status.ts +52 -0
- package/src/embed/backlog.ts +124 -18
- package/src/embed/fingerprint.ts +6 -3
- package/src/embed/retry.ts +66 -27
- package/src/embed/variant-backlog.ts +15 -10
- package/src/embed/variant-retry.ts +31 -22
- package/src/index.ts +30 -2
- package/src/llm/native-worker/dispatcher.ts +2 -0
- package/src/llm/native-worker/embedding-identity.ts +42 -0
- package/src/llm/native-worker/protocol.ts +1 -0
- package/src/llm/types.ts +3 -0
- package/src/mcp/context.ts +17 -0
- package/src/mcp/http-egress.ts +4 -0
- package/src/mcp/http-transport.ts +2 -0
- package/src/mcp/resources/index.ts +6 -5
- package/src/mcp/tool-descriptions-core.ts +1 -1
- package/src/mcp/tools/capture.ts +87 -85
- package/src/mcp/tools/index.ts +77 -4
- package/src/mcp/tools/memory-remember.ts +8 -1
- 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/mcp/tools/status.ts +4 -0
- package/src/pipeline/hybrid.ts +37 -7
- package/src/pipeline/vsearch.ts +14 -2
- 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/embed-scheduler.ts +133 -19
- package/src/serve/host-path-redaction.ts +79 -0
- 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/globals.built.css +1 -1
- package/src/serve/public/hooks/use-api.ts +26 -3
- package/src/serve/public/lib/request-intent.ts +77 -0
- package/src/serve/public/lib/snippet.tsx +52 -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 +22 -9
- package/src/serve/public/pages/DocView.tsx +25 -6
- package/src/serve/public/pages/DocumentEditor.tsx +224 -104
- package/src/serve/public/pages/Search.tsx +1 -41
- package/src/serve/public/pages/Sessions.tsx +350 -0
- package/src/serve/resident-runtime.ts +69 -4
- package/src/serve/resident-status.ts +13 -1
- 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 +215 -10
- package/src/serve/session-automation.ts +146 -0
- package/src/serve/status-model.ts +16 -0
- package/src/serve/status.ts +2 -0
- package/src/serve/watch-reconciliation-shared.ts +3 -0
- package/src/serve/watch-service-events.ts +3 -2
- package/src/serve/watch-service-run-flush.ts +35 -2
- package/src/serve/watch-service.ts +5 -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/migrations/031-runtime-independent-vectors.ts +29 -0
- package/src/store/migrations/032-vector-runtime-callers.ts +17 -0
- package/src/store/migrations/index.ts +4 -0
- package/src/store/sqlite/adapter.ts +76 -16
- package/src/store/sqlite/scoped-index.ts +9 -0
- package/src/store/types.ts +11 -1
- package/src/store/vector/lazy.ts +46 -43
- package/src/store/vector/runtime-compat.ts +651 -0
- package/src/store/vector/sqlite-vec.ts +20 -2
- package/src/store/vector/status.ts +276 -35
- package/src/store/vector/types.ts +2 -0
- package/src/store/vector/variant-search.ts +71 -23
- package/src/store/vector/variants.ts +49 -14
- package/browser-extension/artifacts/gno-browser-clipper-v2.5.1.zip.sha256 +0 -1
package/src/cli/program.ts
CHANGED
|
@@ -41,7 +41,11 @@ import {
|
|
|
41
41
|
type GlobalOptions,
|
|
42
42
|
parseGlobalOptions,
|
|
43
43
|
} from "./context";
|
|
44
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
DETACHED_CHILD_FLAG,
|
|
46
|
+
formatBackgroundIssue,
|
|
47
|
+
residentIssues,
|
|
48
|
+
} from "./detach";
|
|
45
49
|
import { CliError } from "./errors";
|
|
46
50
|
import {
|
|
47
51
|
assertFormatSupported,
|
|
@@ -344,7 +348,7 @@ export function createProgram(): Command {
|
|
|
344
348
|
.option("--no-pager", "disable automatic paging of long output");
|
|
345
349
|
|
|
346
350
|
// Resolve globals ONCE before any command runs (ensures consistency)
|
|
347
|
-
program.hook("preAction", (thisCommand) => {
|
|
351
|
+
program.hook("preAction", async (thisCommand) => {
|
|
348
352
|
const rootOpts = thisCommand.optsWithGlobals();
|
|
349
353
|
const globals = parseGlobalOptions(rootOpts);
|
|
350
354
|
if (!isValidIndexName(globals.index)) {
|
|
@@ -355,6 +359,8 @@ export function createProgram(): Command {
|
|
|
355
359
|
}
|
|
356
360
|
applyGlobalOptions(globals);
|
|
357
361
|
globalState.current = globals;
|
|
362
|
+
const { assertCliSessionBinding } = await import("./session-binding");
|
|
363
|
+
await assertCliSessionBinding(globals.config, globals.index);
|
|
358
364
|
});
|
|
359
365
|
|
|
360
366
|
// Wire command groups
|
|
@@ -362,6 +368,7 @@ export function createProgram(): Command {
|
|
|
362
368
|
wireOnboardingCommands(program);
|
|
363
369
|
wireCaptureCommand(program);
|
|
364
370
|
wireMemoryCommands(program);
|
|
371
|
+
wireSessionsCommands(program);
|
|
365
372
|
wireManagementCommands(program);
|
|
366
373
|
wireTraceCommands(program);
|
|
367
374
|
wirePublishCommand(program);
|
|
@@ -1874,6 +1881,10 @@ function wireCaptureCommand(program: Command): void {
|
|
|
1874
1881
|
.option("--source-author <author>", "source author")
|
|
1875
1882
|
.option("--source-date <date>", "source observed date/time")
|
|
1876
1883
|
.option("--source-id <id>", "source external id")
|
|
1884
|
+
.option(
|
|
1885
|
+
"--request-id <id>",
|
|
1886
|
+
"retry identity: reuse it to retry this same capture after a lost response"
|
|
1887
|
+
)
|
|
1877
1888
|
.option("--json", "JSON output")
|
|
1878
1889
|
.action(
|
|
1879
1890
|
async (contentParts: string[], cmdOpts: Record<string, unknown>) => {
|
|
@@ -1902,6 +1913,7 @@ function wireCaptureCommand(program: Command): void {
|
|
|
1902
1913
|
sourceAuthor: cmdOpts.sourceAuthor as string | undefined,
|
|
1903
1914
|
sourceDate: cmdOpts.sourceDate as string | undefined,
|
|
1904
1915
|
sourceId: cmdOpts.sourceId as string | undefined,
|
|
1916
|
+
requestId: cmdOpts.requestId as string | undefined,
|
|
1905
1917
|
});
|
|
1906
1918
|
const output = formatCaptureReceipt(receipt, {
|
|
1907
1919
|
json: format === "json",
|
|
@@ -1910,6 +1922,27 @@ function wireCaptureCommand(program: Command): void {
|
|
|
1910
1922
|
await writeOutput(output, format);
|
|
1911
1923
|
}
|
|
1912
1924
|
);
|
|
1925
|
+
|
|
1926
|
+
program
|
|
1927
|
+
.command("request-status <request-id>")
|
|
1928
|
+
.description(
|
|
1929
|
+
"Show whether a capture/remember request ID is pending, committed, or unknown"
|
|
1930
|
+
)
|
|
1931
|
+
.option("--json", "JSON output")
|
|
1932
|
+
.action(async (requestId: string, cmdOpts: Record<string, unknown>) => {
|
|
1933
|
+
const format = getFormat(cmdOpts);
|
|
1934
|
+
const globals = getGlobals();
|
|
1935
|
+
const { formatRequestStatusOutput, requestStatus } =
|
|
1936
|
+
await import("./commands/request-status");
|
|
1937
|
+
const result = await requestStatus({
|
|
1938
|
+
requestId,
|
|
1939
|
+
indexName: globals.index,
|
|
1940
|
+
});
|
|
1941
|
+
await writeOutput(
|
|
1942
|
+
formatRequestStatusOutput(result, { json: format === "json" }),
|
|
1943
|
+
format
|
|
1944
|
+
);
|
|
1945
|
+
});
|
|
1913
1946
|
}
|
|
1914
1947
|
|
|
1915
1948
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1957,6 +1990,10 @@ function wireMemoryCommands(program: Command): void {
|
|
|
1957
1990
|
"--session <id>",
|
|
1958
1991
|
"session identity (default: $GNO_MEMORY_SESSION or ppid:<pid>)"
|
|
1959
1992
|
)
|
|
1993
|
+
.option(
|
|
1994
|
+
"--request-id <id>",
|
|
1995
|
+
"retry identity: reuse it to retry this same write after a lost response"
|
|
1996
|
+
)
|
|
1960
1997
|
.option("--json", "JSON output")
|
|
1961
1998
|
.action(async (text: string, cmdOpts: Record<string, unknown>) => {
|
|
1962
1999
|
const format = getFormat(cmdOpts);
|
|
@@ -1979,6 +2016,7 @@ function wireMemoryCommands(program: Command): void {
|
|
|
1979
2016
|
source: cmdOpts.source as string | undefined,
|
|
1980
2017
|
caller: cmdOpts.caller as string | undefined,
|
|
1981
2018
|
session: cmdOpts.session as string | undefined,
|
|
2019
|
+
requestId: cmdOpts.requestId as string | undefined,
|
|
1982
2020
|
});
|
|
1983
2021
|
await writeOutput(
|
|
1984
2022
|
formatRememberResult(result, {
|
|
@@ -2038,6 +2076,358 @@ function wireMemoryCommands(program: Command): void {
|
|
|
2038
2076
|
});
|
|
2039
2077
|
}
|
|
2040
2078
|
|
|
2079
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2080
|
+
// Session archive commands (manual import only)
|
|
2081
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2082
|
+
|
|
2083
|
+
function wireSessionsCommands(program: Command): void {
|
|
2084
|
+
const sessionsCmd = program
|
|
2085
|
+
.command("sessions")
|
|
2086
|
+
.description(
|
|
2087
|
+
"Discover and manually import local agent sessions into a dedicated archive"
|
|
2088
|
+
);
|
|
2089
|
+
const context = () => {
|
|
2090
|
+
const globals = getGlobals();
|
|
2091
|
+
return { configPath: globals.config, indexName: globals.index };
|
|
2092
|
+
};
|
|
2093
|
+
const asJson = (cmdOpts: Record<string, unknown>) =>
|
|
2094
|
+
getFormat(cmdOpts) === "json";
|
|
2095
|
+
|
|
2096
|
+
sessionsCmd
|
|
2097
|
+
.command("discover", { isDefault: true })
|
|
2098
|
+
.description("Preview supported local session sources (never imports)")
|
|
2099
|
+
.option("--json", "JSON output")
|
|
2100
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
2101
|
+
const { discoverSessions, formatDiscovery } =
|
|
2102
|
+
await import("./commands/sessions");
|
|
2103
|
+
const result = await discoverSessions(context());
|
|
2104
|
+
await writeOutput(
|
|
2105
|
+
formatDiscovery(result, asJson(cmdOpts)),
|
|
2106
|
+
getFormat(cmdOpts)
|
|
2107
|
+
);
|
|
2108
|
+
});
|
|
2109
|
+
|
|
2110
|
+
sessionsCmd
|
|
2111
|
+
.command("init")
|
|
2112
|
+
.description("Create or extend the dedicated archive config/index pair")
|
|
2113
|
+
.option(
|
|
2114
|
+
"--archive <dir>",
|
|
2115
|
+
"absolute archive directory (outside the curated vault)"
|
|
2116
|
+
)
|
|
2117
|
+
.option("--collection <name>", "archive collection to create")
|
|
2118
|
+
.option("--json", "JSON output")
|
|
2119
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
2120
|
+
const { initSessions } = await import("./commands/sessions");
|
|
2121
|
+
const result = await initSessions(context(), {
|
|
2122
|
+
archive: cmdOpts.archive as string | undefined,
|
|
2123
|
+
collection: cmdOpts.collection as string | undefined,
|
|
2124
|
+
});
|
|
2125
|
+
await writeOutput(
|
|
2126
|
+
asJson(cmdOpts)
|
|
2127
|
+
? JSON.stringify(result, null, 2)
|
|
2128
|
+
: `Session archive ${result.created ? "created" : "ready"}: ${result.archiveRoot} (collection ${result.collection}, index ${result.index}, config ${result.configPath})`,
|
|
2129
|
+
getFormat(cmdOpts)
|
|
2130
|
+
);
|
|
2131
|
+
});
|
|
2132
|
+
|
|
2133
|
+
const sourceCmd = sessionsCmd
|
|
2134
|
+
.command("source")
|
|
2135
|
+
.description("Register or unregister owner session sources");
|
|
2136
|
+
sourceCmd
|
|
2137
|
+
.command("add <id>")
|
|
2138
|
+
.description("Register a harness session root for manual import")
|
|
2139
|
+
.option("--harness <harness>", "codex | claude-code | openclaw | hermes")
|
|
2140
|
+
.option("--path <path>", "absolute harness session root, file or database")
|
|
2141
|
+
.option("--collection <name>", "default archive collection")
|
|
2142
|
+
.option(
|
|
2143
|
+
"--project <prefix=collection>",
|
|
2144
|
+
"owner-approved working-directory mapping (repeatable)",
|
|
2145
|
+
collectRepeatableValue,
|
|
2146
|
+
[]
|
|
2147
|
+
)
|
|
2148
|
+
.option("--json", "JSON output")
|
|
2149
|
+
.action(async (id: string, cmdOpts: Record<string, unknown>) => {
|
|
2150
|
+
const { addSource } = await import("./commands/sessions");
|
|
2151
|
+
const result = await addSource(context(), {
|
|
2152
|
+
id,
|
|
2153
|
+
harness: cmdOpts.harness as string | undefined,
|
|
2154
|
+
path: cmdOpts.path as string | undefined,
|
|
2155
|
+
collection: cmdOpts.collection as string | undefined,
|
|
2156
|
+
projects: cmdOpts.project as string[],
|
|
2157
|
+
});
|
|
2158
|
+
await writeOutput(
|
|
2159
|
+
asJson(cmdOpts)
|
|
2160
|
+
? JSON.stringify(result, null, 2)
|
|
2161
|
+
: `Source ${result.id} registered. Nothing was imported.`,
|
|
2162
|
+
getFormat(cmdOpts)
|
|
2163
|
+
);
|
|
2164
|
+
});
|
|
2165
|
+
sourceCmd
|
|
2166
|
+
.command("remove <id>")
|
|
2167
|
+
.description("Unregister a source (its archive is retained)")
|
|
2168
|
+
.option("--json", "JSON output")
|
|
2169
|
+
.action(async (id: string, cmdOpts: Record<string, unknown>) => {
|
|
2170
|
+
const { removeSource } = await import("./commands/sessions");
|
|
2171
|
+
const result = await removeSource(context(), id);
|
|
2172
|
+
await writeOutput(
|
|
2173
|
+
asJson(cmdOpts)
|
|
2174
|
+
? JSON.stringify(result, null, 2)
|
|
2175
|
+
: `Source ${result.id} removed; archived sessions were retained.`,
|
|
2176
|
+
getFormat(cmdOpts)
|
|
2177
|
+
);
|
|
2178
|
+
});
|
|
2179
|
+
|
|
2180
|
+
sessionsCmd
|
|
2181
|
+
.command("import [paths...]")
|
|
2182
|
+
.description("Import selected sources or paths into the archive (manual)")
|
|
2183
|
+
.option("--source <id>", "registered source to import")
|
|
2184
|
+
.option(
|
|
2185
|
+
"--collection <name>",
|
|
2186
|
+
"destination archive collection (path imports)"
|
|
2187
|
+
)
|
|
2188
|
+
.option("--format <harness>", "codex | claude-code | openclaw | hermes")
|
|
2189
|
+
.option("--dry-run", "parse and report without writing archive or index")
|
|
2190
|
+
.option("--limit <n>", "maximum changed units processed this run")
|
|
2191
|
+
.option("--json", "JSON output")
|
|
2192
|
+
.action(async (paths: string[], cmdOpts: Record<string, unknown>) => {
|
|
2193
|
+
const { formatImportReceipt, importSessions } =
|
|
2194
|
+
await import("./commands/sessions");
|
|
2195
|
+
const receipt = await importSessions(context(), {
|
|
2196
|
+
paths,
|
|
2197
|
+
source: cmdOpts.source as string | undefined,
|
|
2198
|
+
collection: cmdOpts.collection as string | undefined,
|
|
2199
|
+
format: cmdOpts.format as string | undefined,
|
|
2200
|
+
dryRun: Boolean(cmdOpts.dryRun),
|
|
2201
|
+
limit: cmdOpts.limit,
|
|
2202
|
+
});
|
|
2203
|
+
await writeOutput(
|
|
2204
|
+
formatImportReceipt(receipt, asJson(cmdOpts)),
|
|
2205
|
+
getFormat(cmdOpts)
|
|
2206
|
+
);
|
|
2207
|
+
if (receipt.status === "failed") {
|
|
2208
|
+
const unsupportedOnly =
|
|
2209
|
+
receipt.counts.unsupported > 0 &&
|
|
2210
|
+
receipt.counts.failed === 0 &&
|
|
2211
|
+
receipt.counts.incomplete === 0;
|
|
2212
|
+
throw unsupportedOnly
|
|
2213
|
+
? new CliError(
|
|
2214
|
+
"VALIDATION",
|
|
2215
|
+
"No selected unit is a supported session format; see receipt.",
|
|
2216
|
+
{ details: { sessionsCode: "SESSIONS_UNSUPPORTED_FORMAT" } }
|
|
2217
|
+
)
|
|
2218
|
+
: new CliError("RUNTIME", "Session import failed; see receipt.", {
|
|
2219
|
+
details: { sessionsCode: "SESSIONS_IMPORT_FAILED" },
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
});
|
|
2223
|
+
|
|
2224
|
+
sessionsCmd
|
|
2225
|
+
.command("status")
|
|
2226
|
+
.description("Show archive, source and checkpoint status")
|
|
2227
|
+
.option("--json", "JSON output")
|
|
2228
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
2229
|
+
const { formatStatus, sessionsStatus } =
|
|
2230
|
+
await import("./commands/sessions");
|
|
2231
|
+
const result = await sessionsStatus(context());
|
|
2232
|
+
await writeOutput(
|
|
2233
|
+
formatStatus(result, asJson(cmdOpts)),
|
|
2234
|
+
getFormat(cmdOpts)
|
|
2235
|
+
);
|
|
2236
|
+
});
|
|
2237
|
+
|
|
2238
|
+
wireSessionsAutomationCommands(sessionsCmd, context, asJson);
|
|
2239
|
+
|
|
2240
|
+
sessionsCmd
|
|
2241
|
+
.command("prune")
|
|
2242
|
+
.description(
|
|
2243
|
+
"Preview (or --apply) removal of archives whose source is gone"
|
|
2244
|
+
)
|
|
2245
|
+
.option("--source <id>", "source to prune")
|
|
2246
|
+
.option("--apply", "delete the previewed archive files")
|
|
2247
|
+
.option("--json", "JSON output")
|
|
2248
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
2249
|
+
const { formatPrune, pruneSessions } =
|
|
2250
|
+
await import("./commands/sessions");
|
|
2251
|
+
const result = await pruneSessions(context(), {
|
|
2252
|
+
source: cmdOpts.source as string | undefined,
|
|
2253
|
+
apply: Boolean(cmdOpts.apply),
|
|
2254
|
+
});
|
|
2255
|
+
await writeOutput(
|
|
2256
|
+
formatPrune(result, asJson(cmdOpts)),
|
|
2257
|
+
getFormat(cmdOpts)
|
|
2258
|
+
);
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
/** Opt-in automation: profiles, explicit trigger switches, run-now, host hook. */
|
|
2263
|
+
function wireSessionsAutomationCommands(
|
|
2264
|
+
sessionsCmd: Command,
|
|
2265
|
+
context: () => { configPath?: string; indexName: string },
|
|
2266
|
+
asJson: (cmdOpts: Record<string, unknown>) => boolean
|
|
2267
|
+
): void {
|
|
2268
|
+
const automationCmd = sessionsCmd
|
|
2269
|
+
.command("automation")
|
|
2270
|
+
.description(
|
|
2271
|
+
"Opt-in hooks and daemon schedules for registered sources (off until enabled)"
|
|
2272
|
+
);
|
|
2273
|
+
|
|
2274
|
+
automationCmd
|
|
2275
|
+
.command("set <profile>")
|
|
2276
|
+
.description(
|
|
2277
|
+
"Create or reconfigure a profile (sources, cadence, budget); enables nothing"
|
|
2278
|
+
)
|
|
2279
|
+
.option(
|
|
2280
|
+
"--source <id>",
|
|
2281
|
+
"registered source to include (repeatable)",
|
|
2282
|
+
collectRepeatableValue,
|
|
2283
|
+
[]
|
|
2284
|
+
)
|
|
2285
|
+
.option("--cadence <n>", "elapsed schedule cadence <n>s|m|h|d (min 1m)")
|
|
2286
|
+
.option("--limit <n>", "changed units per source per run")
|
|
2287
|
+
.option("--retries <n>", "automatic retries after a failed run")
|
|
2288
|
+
.option("--json", "JSON output")
|
|
2289
|
+
.action(async (id: string, cmdOpts: Record<string, unknown>) => {
|
|
2290
|
+
const { formatAutomationPreview, setAutomation } =
|
|
2291
|
+
await import("./commands/sessions");
|
|
2292
|
+
const preview = await setAutomation(context(), id, {
|
|
2293
|
+
sources: cmdOpts.source as string[],
|
|
2294
|
+
cadence: cmdOpts.cadence as string | undefined,
|
|
2295
|
+
limit: cmdOpts.limit,
|
|
2296
|
+
retries: cmdOpts.retries,
|
|
2297
|
+
});
|
|
2298
|
+
await writeOutput(
|
|
2299
|
+
formatAutomationPreview(preview, asJson(cmdOpts)),
|
|
2300
|
+
getFormat(cmdOpts)
|
|
2301
|
+
);
|
|
2302
|
+
});
|
|
2303
|
+
|
|
2304
|
+
automationCmd
|
|
2305
|
+
.command("preview <profile>")
|
|
2306
|
+
.description(
|
|
2307
|
+
"Show sources, destinations, hook command, schedule and daemon prerequisite"
|
|
2308
|
+
)
|
|
2309
|
+
.option("--settings <path>", "Claude Code settings file to preview")
|
|
2310
|
+
.option("--json", "JSON output")
|
|
2311
|
+
.action(async (id: string, cmdOpts: Record<string, unknown>) => {
|
|
2312
|
+
const { formatAutomationPreview, previewAutomation } =
|
|
2313
|
+
await import("./commands/sessions");
|
|
2314
|
+
const preview = await previewAutomation(context(), id, {
|
|
2315
|
+
settings: cmdOpts.settings as string | undefined,
|
|
2316
|
+
});
|
|
2317
|
+
await writeOutput(
|
|
2318
|
+
formatAutomationPreview(preview, asJson(cmdOpts)),
|
|
2319
|
+
getFormat(cmdOpts)
|
|
2320
|
+
);
|
|
2321
|
+
});
|
|
2322
|
+
|
|
2323
|
+
automationCmd
|
|
2324
|
+
.command("enable <profile>")
|
|
2325
|
+
.description(
|
|
2326
|
+
"Explicitly switch on a host hook and/or the daemon schedule for a profile"
|
|
2327
|
+
)
|
|
2328
|
+
.option("--hook <harness>", "install the owned hook (claude-code)")
|
|
2329
|
+
.option(
|
|
2330
|
+
"--settings <path>",
|
|
2331
|
+
"Claude Code settings file (default: $CLAUDE_CONFIG_DIR or ~/.claude settings.json)"
|
|
2332
|
+
)
|
|
2333
|
+
.option("--schedule", "run on the daemon's elapsed cadence")
|
|
2334
|
+
.option("--cadence <n>", "elapsed cadence <n>s|m|h|d (min 1m)")
|
|
2335
|
+
.option("--json", "JSON output")
|
|
2336
|
+
.action(async (id: string, cmdOpts: Record<string, unknown>) => {
|
|
2337
|
+
const { enableAutomationCli, formatAutomationPreview } =
|
|
2338
|
+
await import("./commands/sessions");
|
|
2339
|
+
const preview = await enableAutomationCli(context(), id, {
|
|
2340
|
+
hook: cmdOpts.hook as string | undefined,
|
|
2341
|
+
settings: cmdOpts.settings as string | undefined,
|
|
2342
|
+
schedule: Boolean(cmdOpts.schedule),
|
|
2343
|
+
cadence: cmdOpts.cadence as string | undefined,
|
|
2344
|
+
});
|
|
2345
|
+
await writeOutput(
|
|
2346
|
+
formatAutomationPreview(preview, asJson(cmdOpts)),
|
|
2347
|
+
getFormat(cmdOpts)
|
|
2348
|
+
);
|
|
2349
|
+
});
|
|
2350
|
+
|
|
2351
|
+
automationCmd
|
|
2352
|
+
.command("disable <profile>")
|
|
2353
|
+
.description(
|
|
2354
|
+
"Pause: switch triggers off, remove the owned hook entry, clear pending work"
|
|
2355
|
+
)
|
|
2356
|
+
.option("--hook", "only the hook")
|
|
2357
|
+
.option("--schedule", "only the schedule")
|
|
2358
|
+
.option("--json", "JSON output")
|
|
2359
|
+
.action(async (id: string, cmdOpts: Record<string, unknown>) => {
|
|
2360
|
+
const { disableAutomationCli, formatAutomationChange } =
|
|
2361
|
+
await import("./commands/sessions");
|
|
2362
|
+
const change = await disableAutomationCli(context(), id, {
|
|
2363
|
+
hook: Boolean(cmdOpts.hook),
|
|
2364
|
+
schedule: Boolean(cmdOpts.schedule),
|
|
2365
|
+
});
|
|
2366
|
+
await writeOutput(
|
|
2367
|
+
formatAutomationChange(change, asJson(cmdOpts)),
|
|
2368
|
+
getFormat(cmdOpts)
|
|
2369
|
+
);
|
|
2370
|
+
});
|
|
2371
|
+
|
|
2372
|
+
automationCmd
|
|
2373
|
+
.command("remove <profile>")
|
|
2374
|
+
.description(
|
|
2375
|
+
"Uninstall owned integrations and delete the profile (archive retained)"
|
|
2376
|
+
)
|
|
2377
|
+
.option("--json", "JSON output")
|
|
2378
|
+
.action(async (id: string, cmdOpts: Record<string, unknown>) => {
|
|
2379
|
+
const { formatAutomationChange, removeAutomation } =
|
|
2380
|
+
await import("./commands/sessions");
|
|
2381
|
+
const change = await removeAutomation(context(), id);
|
|
2382
|
+
await writeOutput(
|
|
2383
|
+
formatAutomationChange(change, asJson(cmdOpts)),
|
|
2384
|
+
getFormat(cmdOpts)
|
|
2385
|
+
);
|
|
2386
|
+
});
|
|
2387
|
+
|
|
2388
|
+
automationCmd
|
|
2389
|
+
.command("run <profile>")
|
|
2390
|
+
.description("Run a profile now through the manual importer")
|
|
2391
|
+
.option("--json", "JSON output")
|
|
2392
|
+
.action(async (id: string, cmdOpts: Record<string, unknown>) => {
|
|
2393
|
+
const { formatAutomationRun, runAutomation } =
|
|
2394
|
+
await import("./commands/sessions");
|
|
2395
|
+
const result = await runAutomation(context(), id);
|
|
2396
|
+
await writeOutput(
|
|
2397
|
+
formatAutomationRun(result, asJson(cmdOpts)),
|
|
2398
|
+
getFormat(cmdOpts)
|
|
2399
|
+
);
|
|
2400
|
+
if (result.outcome === "failed" && result.reason === "busy") {
|
|
2401
|
+
throw new CliError(
|
|
2402
|
+
"BUSY",
|
|
2403
|
+
"The archive is busy (another import or index writer); the run is recorded; a running daemon retries it, or run it again once the archive is free.",
|
|
2404
|
+
{ details: { sessionsCode: "SESSIONS_BUSY" } }
|
|
2405
|
+
);
|
|
2406
|
+
}
|
|
2407
|
+
if (result.outcome === "failed") {
|
|
2408
|
+
throw new CliError(
|
|
2409
|
+
"RUNTIME",
|
|
2410
|
+
`Automation run failed (${result.reason ?? "unknown"}); see gno sessions status.`,
|
|
2411
|
+
{ details: { sessionsCode: "SESSIONS_IMPORT_FAILED" } }
|
|
2412
|
+
);
|
|
2413
|
+
}
|
|
2414
|
+
});
|
|
2415
|
+
|
|
2416
|
+
sessionsCmd
|
|
2417
|
+
.command("hook <harness>")
|
|
2418
|
+
.description(
|
|
2419
|
+
"Host hook entrypoint: durably mark a profile pending (installed by automation enable)"
|
|
2420
|
+
)
|
|
2421
|
+
.option("--profile <id>", "automation profile")
|
|
2422
|
+
.action(async (harness: string, cmdOpts: Record<string, unknown>) => {
|
|
2423
|
+
const { runSessionsHook } = await import("./commands/sessions");
|
|
2424
|
+
const line = await runSessionsHook(context(), harness, {
|
|
2425
|
+
profile: cmdOpts.profile as string | undefined,
|
|
2426
|
+
});
|
|
2427
|
+
process.stdout.write(`${line}\n`);
|
|
2428
|
+
});
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2041
2431
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2042
2432
|
// Retrieval Commands (get, multi-get, ls)
|
|
2043
2433
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -2169,6 +2559,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
2169
2559
|
const { ls, formatLs } = await import("./commands/ls");
|
|
2170
2560
|
const result = await ls(scope, {
|
|
2171
2561
|
configPath: globals.config,
|
|
2562
|
+
indexName: globals.index,
|
|
2172
2563
|
limit: cmdOpts.limit as number | undefined,
|
|
2173
2564
|
offset: cmdOpts.offset as number | undefined,
|
|
2174
2565
|
json: format === "json",
|
|
@@ -3157,6 +3548,10 @@ function wireManagementCommands(program: Command): void {
|
|
|
3157
3548
|
.option("--model <uri>", "embedding model URI")
|
|
3158
3549
|
.option("--batch-size <num>", "batch size", "32")
|
|
3159
3550
|
.option("--force", "regenerate all embeddings")
|
|
3551
|
+
.option(
|
|
3552
|
+
"--new-partition",
|
|
3553
|
+
"confirm building a separate vector partition for an incompatible runtime"
|
|
3554
|
+
)
|
|
3160
3555
|
.option("--dry-run", "show what would be done")
|
|
3161
3556
|
.option("--json", "JSON output")
|
|
3162
3557
|
).action(
|
|
@@ -3180,6 +3575,7 @@ function wireManagementCommands(program: Command): void {
|
|
|
3180
3575
|
force: Boolean(cmdOpts.force),
|
|
3181
3576
|
dryRun: Boolean(cmdOpts.dryRun),
|
|
3182
3577
|
yes: globals.yes,
|
|
3578
|
+
newPartition: Boolean(cmdOpts.newPartition),
|
|
3183
3579
|
json: format === "json",
|
|
3184
3580
|
verbose: globals.verbose,
|
|
3185
3581
|
offline: globals.offline,
|
|
@@ -3288,6 +3684,43 @@ function wireVecCommands(program: Command): void {
|
|
|
3288
3684
|
);
|
|
3289
3685
|
});
|
|
3290
3686
|
|
|
3687
|
+
// vec drop
|
|
3688
|
+
addWriteLeaseFlags(
|
|
3689
|
+
vecCmd
|
|
3690
|
+
.command("drop <partition>")
|
|
3691
|
+
.description(
|
|
3692
|
+
"Drop an abandoned shadow vector partition (id prefix from gno status)"
|
|
3693
|
+
)
|
|
3694
|
+
.option("--json", "JSON output")
|
|
3695
|
+
).action(async (partition: string, cmdOpts: Record<string, unknown>) => {
|
|
3696
|
+
const format = getFormat(cmdOpts);
|
|
3697
|
+
const globals = getGlobals();
|
|
3698
|
+
|
|
3699
|
+
const { vecDrop, formatVecDrop } = await import("./commands/vec");
|
|
3700
|
+
const lease = parseWriteLeaseFlags(cmdOpts);
|
|
3701
|
+
const result = await withCliWriteLease(
|
|
3702
|
+
{
|
|
3703
|
+
indexName: globals.index,
|
|
3704
|
+
lockWaitMs: lease.lockWaitMs,
|
|
3705
|
+
noWait: lease.noWait,
|
|
3706
|
+
},
|
|
3707
|
+
() =>
|
|
3708
|
+
vecDrop(partition, {
|
|
3709
|
+
configPath: globals.config,
|
|
3710
|
+
indexName: globals.index,
|
|
3711
|
+
})
|
|
3712
|
+
);
|
|
3713
|
+
throwIfWriteLeaseBusy(result, format === "json");
|
|
3714
|
+
|
|
3715
|
+
if (!result.success) {
|
|
3716
|
+
throw new CliError("VALIDATION", result.error);
|
|
3717
|
+
}
|
|
3718
|
+
|
|
3719
|
+
process.stdout.write(
|
|
3720
|
+
`${formatVecDrop(result, { json: format === "json" })}\n`
|
|
3721
|
+
);
|
|
3722
|
+
});
|
|
3723
|
+
|
|
3291
3724
|
// vec rebuild
|
|
3292
3725
|
addWriteLeaseFlags(
|
|
3293
3726
|
vecCmd
|
|
@@ -4630,6 +5063,9 @@ async function runDaemonStatus(deps: DaemonStatusDeps): Promise<void> {
|
|
|
4630
5063
|
} else {
|
|
4631
5064
|
process.stdout.write(` (${status.log_size_bytes} bytes)\n`);
|
|
4632
5065
|
}
|
|
5066
|
+
for (const issue of residentIssues(status)) {
|
|
5067
|
+
process.stdout.write(` issue ${formatBackgroundIssue(issue)}\n`);
|
|
5068
|
+
}
|
|
4633
5069
|
if (findings) {
|
|
4634
5070
|
process.stdout.write(
|
|
4635
5071
|
` findings ${formatFindingsRunStatusLine(findings)}\n`
|
|
@@ -4985,6 +5421,9 @@ async function runServeStatus(deps: ServeStatusDeps): Promise<void> {
|
|
|
4985
5421
|
} else {
|
|
4986
5422
|
process.stdout.write(` (${status.log_size_bytes} bytes)\n`);
|
|
4987
5423
|
}
|
|
5424
|
+
for (const issue of residentIssues(status)) {
|
|
5425
|
+
process.stdout.write(` issue ${formatBackgroundIssue(issue)}\n`);
|
|
5426
|
+
}
|
|
4988
5427
|
|
|
4989
5428
|
if (foreign) {
|
|
4990
5429
|
// Terminal mode: emit the operator-facing warning on stderr. JSON
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI-wide enforcement of the session-archive config/index binding.
|
|
3
|
+
*
|
|
4
|
+
* Runs before every command and again whenever a command opens an index
|
|
5
|
+
* (`initStore`, which also covers indexes named by a `?index=` URI): a config
|
|
6
|
+
* bound to a session archive index cannot be used with another index, and an
|
|
7
|
+
* archive index cannot be opened with a different config.
|
|
8
|
+
*
|
|
9
|
+
* @module src/cli/session-binding
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { Config } from "../config/types";
|
|
13
|
+
|
|
14
|
+
import { getIndexDbPath } from "../app/constants";
|
|
15
|
+
import { getConfigPaths, loadConfig } from "../config";
|
|
16
|
+
import { assertSessionBinding } from "../sessions/binding";
|
|
17
|
+
import { SessionsError } from "../sessions/types";
|
|
18
|
+
import { CliError } from "./errors";
|
|
19
|
+
|
|
20
|
+
export async function assertCliSessionBinding(
|
|
21
|
+
configPath: string | undefined,
|
|
22
|
+
indexName: string,
|
|
23
|
+
loadedConfig?: Config
|
|
24
|
+
): Promise<void> {
|
|
25
|
+
const path = configPath ?? getConfigPaths().configFile;
|
|
26
|
+
let config = loadedConfig;
|
|
27
|
+
if (!config) {
|
|
28
|
+
if (!(await Bun.file(path).exists())) return;
|
|
29
|
+
const loaded = await loadConfig(path);
|
|
30
|
+
// Unreadable configs are reported by the command itself.
|
|
31
|
+
if (!loaded.ok) return;
|
|
32
|
+
config = loaded.value;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
await assertSessionBinding({
|
|
36
|
+
config,
|
|
37
|
+
configPath: path,
|
|
38
|
+
indexName,
|
|
39
|
+
dbPath: getIndexDbPath(indexName),
|
|
40
|
+
});
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error instanceof SessionsError) {
|
|
43
|
+
throw new CliError("VALIDATION", error.message, {
|
|
44
|
+
details: { sessionsCode: error.code },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/config/types.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { z } from "zod";
|
|
|
12
12
|
import { URI_PREFIX } from "../app/constants";
|
|
13
13
|
import { JsonlFieldMappingSchema } from "../converters/adapters/jsonl/config";
|
|
14
14
|
import { MCP_TOOL_PROFILES } from "../mcp/tool-profile";
|
|
15
|
+
import { SessionsConfigSchema } from "../sessions/config";
|
|
15
16
|
import { ChunkingConfigSchema, type ChunkingParams } from "./chunking";
|
|
16
17
|
import { RetrievalTraceConfigSchema } from "./retrieval-traces";
|
|
17
18
|
|
|
@@ -614,6 +615,13 @@ export const ConfigSchema = z.object({
|
|
|
614
615
|
/** Bounded project-aware retrieval affinity. */
|
|
615
616
|
projectAffinity: ProjectAffinityConfigSchema.optional(),
|
|
616
617
|
|
|
618
|
+
/**
|
|
619
|
+
* Session-archive binding. Present only in a dedicated archive config; it
|
|
620
|
+
* binds the file to one index name and archive root and lists
|
|
621
|
+
* owner-registered session sources.
|
|
622
|
+
*/
|
|
623
|
+
sessions: SessionsConfigSchema.optional(),
|
|
624
|
+
|
|
617
625
|
/** Machine-local, timestamp-free project profile provenance. */
|
|
618
626
|
projectProfileBindings: z
|
|
619
627
|
.array(ProjectProfileBindingSchema)
|