@gmickel/gno 2.3.3 → 2.5.1
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 +22 -3
- package/assets/skill/SKILL.md +53 -0
- package/assets/skill/cli-reference.md +29 -0
- package/assets/skill/examples.md +30 -0
- package/assets/skill/mcp-reference.md +26 -0
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/{gno-browser-clipper-v2.3.3.zip → gno-browser-clipper-v2.5.1.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.5.1.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +1 -1
- package/spec/cli.md +41 -0
- package/spec/compiled-context.md +68 -0
- package/spec/db/schema.sql +2 -0
- package/spec/evals.md +48 -0
- package/spec/mcp.md +37 -0
- package/spec/output-schemas/ask.schema.json +12 -0
- package/spec/output-schemas/compiled-context-check.schema.json +44 -0
- package/spec/output-schemas/compiled-context-file.schema.json +165 -0
- package/spec/output-schemas/compiled-context-preview.schema.json +142 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +205 -32
- package/spec/output-schemas/context-capsule-verification.schema.json +32 -9
- package/spec/output-schemas/evidence-fixtures.schema.json +176 -0
- package/spec/output-schemas/evidence-report.schema.json +322 -0
- package/spec/output-schemas/evidence-run.schema.json +277 -0
- package/spec/output-schemas/metadata-predicate.schema.json +460 -0
- package/spec/output-schemas/retrieval-trace-filters.schema.json +13 -4
- package/spec/output-schemas/search-results.schema.json +12 -0
- package/spec/output-schemas/status.schema.json +37 -6
- package/src/app/compiled-context-files.ts +361 -0
- package/src/app/compiled-context.ts +240 -0
- package/src/app/context-runtime-contract.ts +33 -2
- package/src/app/context-runtime-input.ts +17 -0
- package/src/app/context-runtime-types.ts +2 -0
- package/src/app/context-runtime.ts +27 -3
- package/src/app/context-surface.ts +7 -0
- package/src/app/verified-ask.ts +1 -0
- package/src/cli/commands/ask.ts +1 -0
- package/src/cli/commands/audit.ts +4 -0
- package/src/cli/commands/context-build.ts +1 -0
- package/src/cli/commands/context-compiled.ts +136 -0
- package/src/cli/commands/search.ts +1 -0
- package/src/cli/commands/status.ts +10 -0
- package/src/cli/errors.ts +10 -3
- package/src/cli/options.ts +19 -0
- package/src/cli/program.ts +82 -0
- package/src/converters/types.ts +2 -0
- package/src/core/compiled-context.ts +254 -0
- package/src/core/context-budget.ts +2 -10
- package/src/core/context-capsule-retrieval-schema.ts +8 -0
- package/src/core/context-capsule-schema.ts +47 -3
- package/src/core/context-capsule-validation.ts +14 -2
- package/src/core/context-capsule-verification.ts +1 -0
- package/src/core/context-capsule.ts +16 -2
- package/src/core/context-compiler.ts +3 -0
- package/src/core/file-lock.ts +22 -5
- package/src/core/folder-setup-planning.ts +2 -1
- package/src/core/network-boundary-inventory.ts +8 -0
- package/src/core/record-metadata.ts +1 -1
- package/src/core/retrieval-replay-candidate.ts +5 -0
- package/src/core/retrieval-trace-filter-normalization.ts +4 -0
- package/src/core/retrieval-trace-request.ts +1 -0
- package/src/core/retrieval-trace-session.ts +5 -1
- package/src/core/retrieval-trace.ts +2 -0
- package/src/core/setup-receipt.ts +27 -20
- package/src/core/typed-metadata.ts +228 -0
- package/src/core/validation.ts +9 -2
- package/src/core/windows-private-path.ts +96 -0
- package/src/index.ts +2 -2
- package/src/ingestion/compiled-context.ts +15 -0
- package/src/ingestion/record-adapter-canonical.ts +13 -2
- package/src/ingestion/record-container.ts +9 -0
- package/src/ingestion/sync.ts +51 -9
- package/src/ingestion/typed-metadata.ts +55 -0
- package/src/ingestion/walker.ts +5 -4
- package/src/llm/nodeLlamaCpp/simulator-install.ts +6 -2
- package/src/mcp/http-egress.ts +11 -3
- package/src/mcp/retrieval-warnings.ts +24 -0
- package/src/mcp/tools/ask.ts +23 -2
- package/src/mcp/tools/context.ts +47 -2
- package/src/mcp/tools/index.ts +58 -1
- package/src/mcp/tools/query.ts +16 -1
- package/src/mcp/tools/search.ts +12 -1
- package/src/mcp/tools/status.ts +4 -0
- package/src/mcp/tools/vsearch.ts +12 -1
- package/src/pipeline/diagnose.ts +6 -0
- package/src/pipeline/filters.ts +65 -0
- package/src/pipeline/graph-retrieval.ts +9 -1
- package/src/pipeline/hybrid.ts +22 -2
- package/src/pipeline/search.ts +11 -0
- package/src/pipeline/types.ts +7 -1
- package/src/pipeline/vsearch.ts +21 -1
- package/src/sdk/client.ts +98 -3
- package/src/sdk/index.ts +11 -0
- package/src/sdk/types.ts +35 -1
- package/src/serve/compiled-context.ts +84 -0
- package/src/serve/context-capsule.ts +1 -0
- package/src/serve/public/app.tsx +12 -1
- package/src/serve/public/components/MetadataFilter.tsx +186 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/lib/metadata-filter.ts +28 -0
- package/src/serve/public/lib/retrieval-filters.ts +3 -0
- package/src/serve/public/lib/workspace-tabs.ts +2 -0
- package/src/serve/public/pages/Ask.tsx +48 -3
- package/src/serve/public/pages/CompiledContext.tsx +364 -0
- package/src/serve/public/pages/Dashboard.tsx +7 -0
- package/src/serve/public/pages/DocView.tsx +33 -0
- package/src/serve/public/pages/Search.tsx +44 -1
- package/src/serve/routes/api.ts +50 -0
- package/src/serve/server.ts +43 -2
- package/src/serve/spa-production-build.ts +6 -5
- package/src/store/migrations/030-typed-metadata.ts +13 -0
- package/src/store/migrations/index.ts +2 -0
- package/src/store/sqlite/adapter.ts +69 -5
- package/src/store/sqlite/eligibility.ts +12 -0
- package/src/store/sqlite/metadata-predicate.ts +71 -0
- package/src/store/types.ts +11 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.3.3.zip.sha256 +0 -1
|
@@ -63,6 +63,7 @@ export const buildContextCapsule = async (
|
|
|
63
63
|
deps.config.collections.map((collection) => collection.name)
|
|
64
64
|
);
|
|
65
65
|
const noRerank = normalized.depthPolicy === "fast" || normalized.noRerank;
|
|
66
|
+
let metadataCoverageIncomplete = false;
|
|
66
67
|
const plan = await compileContextEvidence<ContextCapsuleV1>(
|
|
67
68
|
{
|
|
68
69
|
goal: normalized.goal,
|
|
@@ -74,6 +75,7 @@ export const buildContextCapsule = async (
|
|
|
74
75
|
tagsAll: normalized.tagsAll,
|
|
75
76
|
tagsAny: normalized.tagsAny,
|
|
76
77
|
categories: normalized.categories,
|
|
78
|
+
filter: normalized.filter,
|
|
77
79
|
author: normalized.author ?? undefined,
|
|
78
80
|
lang: normalized.lang ?? undefined,
|
|
79
81
|
intent: normalized.intent ?? undefined,
|
|
@@ -104,8 +106,14 @@ export const buildContextCapsule = async (
|
|
|
104
106
|
store: deps.store,
|
|
105
107
|
hydration: deps.hydration,
|
|
106
108
|
config: deps.config,
|
|
107
|
-
vectorIndex:
|
|
108
|
-
|
|
109
|
+
vectorIndex:
|
|
110
|
+
normalized.depthPolicy === "fast"
|
|
111
|
+
? null
|
|
112
|
+
: (deps.vectorIndex ?? null),
|
|
113
|
+
embedPort:
|
|
114
|
+
normalized.depthPolicy === "fast"
|
|
115
|
+
? null
|
|
116
|
+
: (deps.embedPort ?? null),
|
|
109
117
|
expandPort: null,
|
|
110
118
|
rerankPort: requestNoRerank ? null : (deps.rerankPort ?? null),
|
|
111
119
|
},
|
|
@@ -124,10 +132,26 @@ export const buildContextCapsule = async (
|
|
|
124
132
|
result.error.cause
|
|
125
133
|
);
|
|
126
134
|
}
|
|
135
|
+
if (
|
|
136
|
+
normalized.filter &&
|
|
137
|
+
result.value.meta.warnings?.some(
|
|
138
|
+
(warning) =>
|
|
139
|
+
warning.code === "METADATA_COVERAGE_UNKNOWN" ||
|
|
140
|
+
warning.code === "METADATA_COVERAGE_INCOMPLETE"
|
|
141
|
+
)
|
|
142
|
+
) {
|
|
143
|
+
metadataCoverageIncomplete = true;
|
|
144
|
+
}
|
|
127
145
|
return result.value;
|
|
128
146
|
},
|
|
129
147
|
projectCanonical: (draft, snapshots) =>
|
|
130
|
-
projectContextCapsule(
|
|
148
|
+
projectContextCapsule(
|
|
149
|
+
draft,
|
|
150
|
+
snapshots,
|
|
151
|
+
normalized,
|
|
152
|
+
deps,
|
|
153
|
+
metadataCoverageIncomplete
|
|
154
|
+
),
|
|
131
155
|
}
|
|
132
156
|
);
|
|
133
157
|
if (!plan.projection) {
|
|
@@ -5,6 +5,10 @@ import { z } from "zod";
|
|
|
5
5
|
import type { ContextCapsuleBuildInput } from "./context-runtime-types";
|
|
6
6
|
|
|
7
7
|
import { ContextCapsuleContractError } from "../core/context-capsule";
|
|
8
|
+
import {
|
|
9
|
+
metadataPredicateSchema,
|
|
10
|
+
METADATA_FILTER_DESCRIPTION,
|
|
11
|
+
} from "../core/typed-metadata";
|
|
8
12
|
|
|
9
13
|
const queryModeSchema = z
|
|
10
14
|
.object({
|
|
@@ -28,6 +32,9 @@ export const contextBuildSurfaceSchema = z
|
|
|
28
32
|
tagsAll: stringList.optional(),
|
|
29
33
|
tagsAny: stringList.optional(),
|
|
30
34
|
categories: stringList.optional(),
|
|
35
|
+
filter: metadataPredicateSchema
|
|
36
|
+
.optional()
|
|
37
|
+
.describe(METADATA_FILTER_DESCRIPTION),
|
|
31
38
|
author: z.string().optional(),
|
|
32
39
|
lang: z.string().optional(),
|
|
33
40
|
intent: z.string().optional(),
|
package/src/app/verified-ask.ts
CHANGED
package/src/cli/commands/ask.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import { runWorkspaceAudit } from "../../core/audit-workspace";
|
|
22
22
|
import { normalizeTag, validateTag } from "../../core/tags";
|
|
23
23
|
import { normalizeCollectionName } from "../../core/validation";
|
|
24
|
+
import { windowsPrivatePath } from "../../core/windows-private-path";
|
|
24
25
|
import { SqliteAdapter } from "../../store/sqlite/adapter";
|
|
25
26
|
|
|
26
27
|
export interface AuditCommandOptions {
|
|
@@ -218,12 +219,15 @@ export const writeAuditReport = async (
|
|
|
218
219
|
);
|
|
219
220
|
const temporaryPath = join(temporaryDirectory, "report");
|
|
220
221
|
try {
|
|
222
|
+
if (process.platform === "win32")
|
|
223
|
+
await windowsPrivatePath(temporaryDirectory, true);
|
|
221
224
|
await Bun.write(temporaryPath, `${formatAuditReport(report, options)}\n`, {
|
|
222
225
|
createPath: false,
|
|
223
226
|
mode: 0o600,
|
|
224
227
|
});
|
|
225
228
|
await chmod(temporaryPath, 0o600);
|
|
226
229
|
await rename(temporaryPath, path);
|
|
230
|
+
if (process.platform === "win32") await windowsPrivatePath(path);
|
|
227
231
|
} finally {
|
|
228
232
|
await unlink(temporaryPath).catch(() => undefined);
|
|
229
233
|
await rmdir(temporaryDirectory).catch(() => undefined);
|
|
@@ -124,6 +124,7 @@ export const contextBuild = async (
|
|
|
124
124
|
until: options.until,
|
|
125
125
|
categories: options.categories,
|
|
126
126
|
author: options.author,
|
|
127
|
+
filter: options.filter,
|
|
127
128
|
graph: options.graph,
|
|
128
129
|
candidateLimit: options.candidateLimit,
|
|
129
130
|
queryModes: options.queryModes,
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { previewCompiledContext } from "../../app/compiled-context";
|
|
2
|
+
import {
|
|
3
|
+
compileContextFile,
|
|
4
|
+
checkContextFile,
|
|
5
|
+
refreshContextFile,
|
|
6
|
+
} from "../../app/compiled-context-files";
|
|
7
|
+
/** Explicit local compiled context operations. */
|
|
8
|
+
import { createGnoClient } from "../../sdk/client";
|
|
9
|
+
import { CliError } from "../errors";
|
|
10
|
+
import { contextCliError } from "./context-build";
|
|
11
|
+
import { initStore } from "./shared";
|
|
12
|
+
|
|
13
|
+
export interface CompiledCommandOptions {
|
|
14
|
+
configPath?: string;
|
|
15
|
+
indexName?: string;
|
|
16
|
+
capsulePath?: string;
|
|
17
|
+
capsuleOutputPath?: string;
|
|
18
|
+
outputPath?: string;
|
|
19
|
+
budgetTokens?: number;
|
|
20
|
+
budgetBytes?: number;
|
|
21
|
+
json?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function contextCompiled(
|
|
25
|
+
operation: "preview" | "compile" | "check" | "refresh",
|
|
26
|
+
options: CompiledCommandOptions
|
|
27
|
+
): Promise<{
|
|
28
|
+
output: string;
|
|
29
|
+
status?: "current" | "stale" | "conflict" | "unverifiable";
|
|
30
|
+
}> {
|
|
31
|
+
const initialized = await initStore({
|
|
32
|
+
configPath: options.configPath,
|
|
33
|
+
indexName: options.indexName,
|
|
34
|
+
syncConfig: false,
|
|
35
|
+
allowEmptyCollections: true,
|
|
36
|
+
});
|
|
37
|
+
if (!initialized.ok) throw new CliError("RUNTIME", initialized.error);
|
|
38
|
+
const deps = {
|
|
39
|
+
store: initialized.store,
|
|
40
|
+
config: initialized.config,
|
|
41
|
+
indexName: options.indexName,
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
if (operation === "check") {
|
|
45
|
+
if (!options.outputPath)
|
|
46
|
+
throw new CliError("VALIDATION", "Artifact path required");
|
|
47
|
+
const result = await checkContextFile(
|
|
48
|
+
{ outputPath: options.outputPath, capsulePath: options.capsulePath },
|
|
49
|
+
deps
|
|
50
|
+
);
|
|
51
|
+
return {
|
|
52
|
+
output: options.json
|
|
53
|
+
? JSON.stringify(result)
|
|
54
|
+
: `${result.status}: ${result.reasons.join("; ") || "verified current"}`,
|
|
55
|
+
status: result.status,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (operation === "refresh") {
|
|
59
|
+
if (!options.outputPath || !options.capsuleOutputPath)
|
|
60
|
+
throw new CliError(
|
|
61
|
+
"VALIDATION",
|
|
62
|
+
"Artifact and Capsule output paths required"
|
|
63
|
+
);
|
|
64
|
+
const result = await refreshContextFile(
|
|
65
|
+
{
|
|
66
|
+
outputPath: options.outputPath,
|
|
67
|
+
capsuleOutputPath: options.capsuleOutputPath,
|
|
68
|
+
},
|
|
69
|
+
deps,
|
|
70
|
+
async (request) => {
|
|
71
|
+
const client = await createGnoClient({
|
|
72
|
+
configPath: options.configPath,
|
|
73
|
+
indexName: options.indexName,
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
return await client.context(request);
|
|
77
|
+
} finally {
|
|
78
|
+
await client.close();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
return {
|
|
83
|
+
output: options.json
|
|
84
|
+
? JSON.stringify(result)
|
|
85
|
+
: `${result.status}: ${result.outputPath}`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (!options.capsulePath || !options.budgetTokens)
|
|
89
|
+
throw new CliError("VALIDATION", "Capsule path and budget required");
|
|
90
|
+
if (operation === "compile") {
|
|
91
|
+
if (!options.outputPath)
|
|
92
|
+
throw new CliError("VALIDATION", "Output path required");
|
|
93
|
+
const result = await compileContextFile(
|
|
94
|
+
{
|
|
95
|
+
capsulePath: options.capsulePath,
|
|
96
|
+
outputPath: options.outputPath,
|
|
97
|
+
budgetTokens: options.budgetTokens,
|
|
98
|
+
budgetBytes: options.budgetBytes,
|
|
99
|
+
},
|
|
100
|
+
deps
|
|
101
|
+
);
|
|
102
|
+
return {
|
|
103
|
+
output: options.json
|
|
104
|
+
? JSON.stringify(result)
|
|
105
|
+
: `${result.status}: ${result.outputPath}`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const source = Bun.file(options.capsulePath);
|
|
109
|
+
if (source.size > 4 * 1024 * 1024)
|
|
110
|
+
throw new CliError("VALIDATION", "Capsule exceeds byte limit");
|
|
111
|
+
const capsule: unknown = await source.json();
|
|
112
|
+
const result = await previewCompiledContext(
|
|
113
|
+
{
|
|
114
|
+
capsule,
|
|
115
|
+
budgetTokens: options.budgetTokens,
|
|
116
|
+
budgetBytes: options.budgetBytes,
|
|
117
|
+
},
|
|
118
|
+
deps
|
|
119
|
+
);
|
|
120
|
+
return { output: options.json ? JSON.stringify(result) : result.markdown };
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (error instanceof CliError) throw error;
|
|
123
|
+
if (
|
|
124
|
+
error instanceof SyntaxError ||
|
|
125
|
+
(error instanceof Error && error.name === "ZodError")
|
|
126
|
+
) {
|
|
127
|
+
throw new CliError(
|
|
128
|
+
"VALIDATION",
|
|
129
|
+
"Invalid compiled context input; provide a valid Capsule and budget"
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
throw contextCliError(error);
|
|
133
|
+
} finally {
|
|
134
|
+
await initialized.store.close();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -87,6 +87,11 @@ function formatTerminal(
|
|
|
87
87
|
): string {
|
|
88
88
|
const lines: string[] = [];
|
|
89
89
|
|
|
90
|
+
if (indexStatus.typedMetadata) {
|
|
91
|
+
lines.push(
|
|
92
|
+
`Typed metadata: ${indexStatus.typedMetadata.pending} pending sync, ${indexStatus.typedMetadata.invalid} invalid`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
90
95
|
lines.push(`Index: ${indexStatus.indexName}`);
|
|
91
96
|
lines.push(`Config: ${indexStatus.configPath}`);
|
|
92
97
|
lines.push(`Database: ${indexStatus.dbPath}`);
|
|
@@ -200,6 +205,10 @@ function formatMarkdown(
|
|
|
200
205
|
lines.push(`- **Documents**: ${indexStatus.activeDocuments}`);
|
|
201
206
|
lines.push(`- **Chunks**: ${indexStatus.totalChunks}`);
|
|
202
207
|
lines.push(`- **Embedding backlog**: ${indexStatus.embeddingBacklog}`);
|
|
208
|
+
if (indexStatus.typedMetadata)
|
|
209
|
+
lines.push(
|
|
210
|
+
`- **Typed metadata**: ${indexStatus.typedMetadata.pending} pending sync, ${indexStatus.typedMetadata.invalid} invalid`
|
|
211
|
+
);
|
|
203
212
|
lines.push(`- **Recent errors**: ${indexStatus.recentErrors}`);
|
|
204
213
|
|
|
205
214
|
const chunking = formatChunkingStatus(indexStatus.chunking);
|
|
@@ -347,6 +356,7 @@ export function formatStatus(
|
|
|
347
356
|
totalDocuments: s.activeDocuments,
|
|
348
357
|
totalChunks: s.totalChunks,
|
|
349
358
|
embeddingBacklog: s.embeddingBacklog,
|
|
359
|
+
typedMetadata: s.typedMetadata,
|
|
350
360
|
chunking: s.chunking,
|
|
351
361
|
lastUpdated: s.lastUpdatedAt,
|
|
352
362
|
healthy: isStatusHealthy(s, result.activation),
|
package/src/cli/errors.ts
CHANGED
|
@@ -15,7 +15,9 @@ export type CliErrorCode =
|
|
|
15
15
|
| "NOT_RUNNING"
|
|
16
16
|
| "BUSY"
|
|
17
17
|
| "AUDIT_FINDINGS"
|
|
18
|
-
| "AUDIT_PARTIAL"
|
|
18
|
+
| "AUDIT_PARTIAL"
|
|
19
|
+
| "CONTEXT_STALE"
|
|
20
|
+
| "CONTEXT_CONFLICT";
|
|
19
21
|
|
|
20
22
|
export interface CliErrorOptions {
|
|
21
23
|
details?: Record<string, unknown>;
|
|
@@ -72,10 +74,15 @@ export function exitCodeFor(err: CliError): 1 | 2 | 3 | 4 | 5 {
|
|
|
72
74
|
if (err.code === "VALIDATION") {
|
|
73
75
|
return 1;
|
|
74
76
|
}
|
|
75
|
-
if (err.code === "NOT_RUNNING") {
|
|
77
|
+
if (err.code === "NOT_RUNNING" || err.code === "CONTEXT_STALE") {
|
|
76
78
|
return 3;
|
|
77
79
|
}
|
|
78
|
-
if (
|
|
80
|
+
if (
|
|
81
|
+
err.code === "BUSY" ||
|
|
82
|
+
err.code === "AUDIT_FINDINGS" ||
|
|
83
|
+
err.code === "CONTEXT_CONFLICT"
|
|
84
|
+
)
|
|
85
|
+
return 4;
|
|
79
86
|
if (err.code === "AUDIT_PARTIAL") return 5;
|
|
80
87
|
return 2;
|
|
81
88
|
}
|
package/src/cli/options.ts
CHANGED
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
normalizeProjectAffinityValues,
|
|
10
10
|
ProjectAffinityInputError,
|
|
11
11
|
} from "../core/project-affinity-surface";
|
|
12
|
+
import {
|
|
13
|
+
normalizeMetadataPredicate,
|
|
14
|
+
type MetadataPredicate,
|
|
15
|
+
} from "../core/typed-metadata";
|
|
12
16
|
import { CliError } from "./errors";
|
|
13
17
|
|
|
14
18
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -259,3 +263,18 @@ export function parseOptionalFloat(
|
|
|
259
263
|
}
|
|
260
264
|
return num;
|
|
261
265
|
}
|
|
266
|
+
|
|
267
|
+
export const parseCliMetadataFilter = (
|
|
268
|
+
value: unknown
|
|
269
|
+
): MetadataPredicate | undefined => {
|
|
270
|
+
if (value === undefined) return undefined;
|
|
271
|
+
try {
|
|
272
|
+
if (typeof value !== "string") throw new Error("Expected JSON text");
|
|
273
|
+
return normalizeMetadataPredicate(JSON.parse(value));
|
|
274
|
+
} catch (error) {
|
|
275
|
+
throw new CliError(
|
|
276
|
+
"VALIDATION",
|
|
277
|
+
`filter: ${error instanceof Error ? error.message : "Invalid predicate"}`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
};
|
package/src/cli/program.ts
CHANGED
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
collectRepeatableValue,
|
|
50
50
|
getDefaultLimit,
|
|
51
51
|
parseCliProjectAffinityOptions,
|
|
52
|
+
parseCliMetadataFilter,
|
|
52
53
|
parseOptionalFloat,
|
|
53
54
|
parsePositiveInt,
|
|
54
55
|
} from "./options";
|
|
@@ -652,6 +653,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
652
653
|
"modified-at upper bound (ISO date/time or token)"
|
|
653
654
|
)
|
|
654
655
|
.option("--category <values>", "require category match (comma-separated)")
|
|
656
|
+
.option("--filter <json>", "typed custom metadata predicate (JSON)")
|
|
655
657
|
.option("--author <text>", "filter by author (case-insensitive contains)")
|
|
656
658
|
.option("--intent <text>", "disambiguating context for ambiguous queries")
|
|
657
659
|
.option(
|
|
@@ -736,6 +738,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
736
738
|
until: cmdOpts.until as string | undefined,
|
|
737
739
|
categories,
|
|
738
740
|
author: cmdOpts.author as string | undefined,
|
|
741
|
+
filter: parseCliMetadataFilter(cmdOpts.filter),
|
|
739
742
|
intent: cmdOpts.intent as string | undefined,
|
|
740
743
|
exclude,
|
|
741
744
|
tagsAll,
|
|
@@ -790,6 +793,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
790
793
|
"modified-at upper bound (ISO date/time or token)"
|
|
791
794
|
)
|
|
792
795
|
.option("--category <values>", "require category match (comma-separated)")
|
|
796
|
+
.option("--filter <json>", "typed custom metadata predicate (JSON)")
|
|
793
797
|
.option("--author <text>", "filter by author (case-insensitive contains)")
|
|
794
798
|
.option("--intent <text>", "disambiguating context for ambiguous queries")
|
|
795
799
|
.option(
|
|
@@ -864,6 +868,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
864
868
|
until: cmdOpts.until as string | undefined,
|
|
865
869
|
categories,
|
|
866
870
|
author: cmdOpts.author as string | undefined,
|
|
871
|
+
filter: parseCliMetadataFilter(cmdOpts.filter),
|
|
867
872
|
intent: cmdOpts.intent as string | undefined,
|
|
868
873
|
exclude,
|
|
869
874
|
tagsAll,
|
|
@@ -916,6 +921,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
916
921
|
"modified-at upper bound (ISO date/time or token)"
|
|
917
922
|
)
|
|
918
923
|
.option("--category <values>", "require category match (comma-separated)")
|
|
924
|
+
.option("--filter <json>", "typed custom metadata predicate (JSON)")
|
|
919
925
|
.option("--author <text>", "filter by author (case-insensitive contains)")
|
|
920
926
|
.option("--intent <text>", "disambiguating context for ambiguous queries")
|
|
921
927
|
.option(
|
|
@@ -1080,6 +1086,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
1080
1086
|
until: cmdOpts.until as string | undefined,
|
|
1081
1087
|
categories,
|
|
1082
1088
|
author: cmdOpts.author as string | undefined,
|
|
1089
|
+
filter: parseCliMetadataFilter(cmdOpts.filter),
|
|
1083
1090
|
intent: cmdOpts.intent as string | undefined,
|
|
1084
1091
|
exclude,
|
|
1085
1092
|
tagsAll,
|
|
@@ -1116,6 +1123,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
1116
1123
|
until: cmdOpts.until as string | undefined,
|
|
1117
1124
|
categories,
|
|
1118
1125
|
author: cmdOpts.author as string | undefined,
|
|
1126
|
+
filter: parseCliMetadataFilter(cmdOpts.filter),
|
|
1119
1127
|
intent: cmdOpts.intent as string | undefined,
|
|
1120
1128
|
exclude,
|
|
1121
1129
|
tagsAll,
|
|
@@ -1219,6 +1227,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
1219
1227
|
"modified-at upper bound (ISO date/time or token)"
|
|
1220
1228
|
)
|
|
1221
1229
|
.option("--category <values>", "require category match (comma-separated)")
|
|
1230
|
+
.option("--filter <json>", "typed custom metadata predicate (JSON)")
|
|
1222
1231
|
.option("--author <text>", "filter by author (case-insensitive contains)")
|
|
1223
1232
|
.option("--intent <text>", "disambiguating context for ambiguous queries")
|
|
1224
1233
|
.option(
|
|
@@ -1350,6 +1359,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
1350
1359
|
until: cmdOpts.until as string | undefined,
|
|
1351
1360
|
categories,
|
|
1352
1361
|
author: cmdOpts.author as string | undefined,
|
|
1362
|
+
filter: parseCliMetadataFilter(cmdOpts.filter),
|
|
1353
1363
|
intent: cmdOpts.intent as string | undefined,
|
|
1354
1364
|
exclude,
|
|
1355
1365
|
minScore,
|
|
@@ -2695,6 +2705,7 @@ function wireManagementCommands(program: Command): void {
|
|
|
2695
2705
|
.option("--tags-all <tags>", "require ALL tags (comma-separated)")
|
|
2696
2706
|
.option("--tags-any <tags>", "require ANY tag (comma-separated)")
|
|
2697
2707
|
.option("--category <values>", "require category match (comma-separated)")
|
|
2708
|
+
.option("--filter <json>", "typed custom metadata predicate (JSON)")
|
|
2698
2709
|
.option("--author <text>", "filter by author")
|
|
2699
2710
|
.option("--lang <code>", "language hint (BCP-47)")
|
|
2700
2711
|
.option("--since <date>", "modified-at lower bound")
|
|
@@ -2765,6 +2776,7 @@ function wireManagementCommands(program: Command): void {
|
|
|
2765
2776
|
tagsAny: parseCsvValues(cmdOpts.tagsAny),
|
|
2766
2777
|
categories: parseCsvValues(cmdOpts.category),
|
|
2767
2778
|
author: cmdOpts.author as string | undefined,
|
|
2779
|
+
filter: parseCliMetadataFilter(cmdOpts.filter),
|
|
2768
2780
|
lang: cmdOpts.lang as string | undefined,
|
|
2769
2781
|
since: cmdOpts.since as string | undefined,
|
|
2770
2782
|
until: cmdOpts.until as string | undefined,
|
|
@@ -2791,6 +2803,76 @@ function wireManagementCommands(program: Command): void {
|
|
|
2791
2803
|
await writeOutput(output, format === "json" ? "json" : "md");
|
|
2792
2804
|
});
|
|
2793
2805
|
|
|
2806
|
+
const compiledCmd = contextCmd
|
|
2807
|
+
.command("compiled")
|
|
2808
|
+
.description("Compile, check and refresh verified project context");
|
|
2809
|
+
for (const operation of ["preview", "compile", "check", "refresh"] as const) {
|
|
2810
|
+
const command = compiledCmd
|
|
2811
|
+
.command(
|
|
2812
|
+
operation === "check" || operation === "refresh"
|
|
2813
|
+
? `${operation} <file>`
|
|
2814
|
+
: operation
|
|
2815
|
+
)
|
|
2816
|
+
.description(`${operation} a separate managed context artifact`)
|
|
2817
|
+
.option("--json", "JSON output");
|
|
2818
|
+
if (operation === "preview" || operation === "compile") {
|
|
2819
|
+
command
|
|
2820
|
+
.requiredOption("--capsule <file>", "explicit Capsule JSON file")
|
|
2821
|
+
.requiredOption("--budget <tokens>", "whole-output token budget")
|
|
2822
|
+
.option("--bytes <bytes>", "whole-output byte budget");
|
|
2823
|
+
}
|
|
2824
|
+
if (operation === "compile")
|
|
2825
|
+
command.requiredOption(
|
|
2826
|
+
"--output <file>",
|
|
2827
|
+
"new *.gno-context.md artifact"
|
|
2828
|
+
);
|
|
2829
|
+
if (operation === "check")
|
|
2830
|
+
command.option("--capsule <file>", "relocated Capsule JSON file");
|
|
2831
|
+
if (operation === "refresh")
|
|
2832
|
+
command.requiredOption(
|
|
2833
|
+
"--capsule-output <file>",
|
|
2834
|
+
"explicit refreshed Capsule destination"
|
|
2835
|
+
);
|
|
2836
|
+
command.action(async (...args: unknown[]) => {
|
|
2837
|
+
const file =
|
|
2838
|
+
operation === "check" || operation === "refresh"
|
|
2839
|
+
? (args[0] as string)
|
|
2840
|
+
: undefined;
|
|
2841
|
+
const opts = args[file === undefined ? 0 : 1] as Record<string, unknown>;
|
|
2842
|
+
const globals = getGlobals();
|
|
2843
|
+
const { contextCompiled } = await import("./commands/context-compiled");
|
|
2844
|
+
const result = await contextCompiled(operation, {
|
|
2845
|
+
configPath: globals.config,
|
|
2846
|
+
indexName: globals.index,
|
|
2847
|
+
capsulePath: opts.capsule as string | undefined,
|
|
2848
|
+
capsuleOutputPath: opts.capsuleOutput as string | undefined,
|
|
2849
|
+
outputPath: file ?? (opts.output as string | undefined),
|
|
2850
|
+
budgetTokens:
|
|
2851
|
+
opts.budget === undefined
|
|
2852
|
+
? undefined
|
|
2853
|
+
: parseContextInteger("budget", opts.budget),
|
|
2854
|
+
budgetBytes:
|
|
2855
|
+
opts.bytes === undefined
|
|
2856
|
+
? undefined
|
|
2857
|
+
: parseContextInteger("bytes", opts.bytes),
|
|
2858
|
+
json: Boolean(opts.json || globals.json),
|
|
2859
|
+
});
|
|
2860
|
+
await writeOutput(
|
|
2861
|
+
result.output,
|
|
2862
|
+
opts.json || globals.json ? "json" : "terminal"
|
|
2863
|
+
);
|
|
2864
|
+
if (result.status && result.status !== "current") {
|
|
2865
|
+
const code =
|
|
2866
|
+
result.status === "stale"
|
|
2867
|
+
? "CONTEXT_STALE"
|
|
2868
|
+
: result.status === "conflict"
|
|
2869
|
+
? "CONTEXT_CONFLICT"
|
|
2870
|
+
: "RUNTIME";
|
|
2871
|
+
throw new CliError(code, result.status, { silent: true });
|
|
2872
|
+
}
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2794
2876
|
contextCmd
|
|
2795
2877
|
.command("verify <file>")
|
|
2796
2878
|
.description("Verify a saved Context Capsule without rebuilding it")
|
package/src/converters/types.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TypedMetadata } from "../core/typed-metadata";
|
|
1
2
|
/**
|
|
2
3
|
* Converter subsystem types.
|
|
3
4
|
* PRD §8.2 - Converter interfaces
|
|
@@ -157,6 +158,7 @@ export const RECORD_METADATA_LIMITS = {
|
|
|
157
158
|
|
|
158
159
|
/** Metadata shared by export adapters and later search/get projections. */
|
|
159
160
|
export interface RecordMetadata {
|
|
161
|
+
custom?: TypedMetadata;
|
|
160
162
|
author?: string;
|
|
161
163
|
participants?: string[];
|
|
162
164
|
categories?: string[];
|