@gmickel/gno 1.22.0 → 1.24.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 +33 -12
- package/assets/skill/SKILL.md +41 -19
- package/package.json +1 -1
- package/spec/cli.md +127 -20
- package/spec/evals-agentic.md +35 -0
- package/spec/evals.md +6 -0
- package/spec/mcp.md +18 -0
- package/spec/output-schemas/query-diagnose-v1.schema.json +123 -0
- package/spec/output-schemas/query-diagnose.schema.json +89 -2
- package/spec/output-schemas/setup-activation-result.schema.json +456 -0
- package/spec/output-schemas/setup-command-result.schema.json +93 -0
- package/spec/output-schemas/setup-receipt.schema.json +258 -0
- package/spec/output-schemas/setup-semantic-receipt.schema.json +195 -0
- package/src/app/context-runtime-types.ts +3 -0
- package/src/app/context-runtime.ts +1 -0
- package/src/app/context-surface.ts +4 -2
- package/src/cli/commands/ask.ts +31 -20
- package/src/cli/commands/completion/scripts.ts +2 -0
- package/src/cli/commands/context-build.ts +17 -7
- package/src/cli/commands/embed.ts +7 -2
- package/src/cli/commands/query.ts +58 -37
- package/src/cli/commands/search.ts +29 -19
- package/src/cli/commands/setup-activation.ts +324 -0
- package/src/cli/commands/setup-semantic.ts +591 -0
- package/src/cli/commands/setup.ts +410 -0
- package/src/cli/commands/vsearch.ts +31 -22
- package/src/cli/options.ts +39 -0
- package/src/cli/program.ts +112 -0
- package/src/cli/setup-semantic-worker.ts +177 -0
- package/src/config/defaults.ts +10 -1
- package/src/config/types.ts +71 -0
- package/src/core/config-mutation.ts +94 -64
- package/src/core/file-lock.ts +70 -31
- package/src/core/folder-setup-planning.ts +453 -0
- package/src/core/folder-setup.ts +490 -0
- package/src/core/project-affinity-surface.ts +114 -0
- package/src/core/project-affinity.ts +330 -0
- package/src/core/setup-activation.ts +309 -0
- package/src/core/setup-receipt.ts +321 -0
- package/src/core/validation.ts +20 -1
- package/src/mcp/tools/ask.ts +10 -1
- package/src/mcp/tools/context.ts +18 -0
- package/src/mcp/tools/index.ts +13 -2
- package/src/mcp/tools/query.ts +12 -0
- package/src/mcp/tools/search.ts +7 -0
- package/src/mcp/tools/vsearch.ts +7 -0
- package/src/pipeline/diagnose.ts +48 -3
- package/src/pipeline/explain.ts +54 -13
- package/src/pipeline/hybrid.ts +100 -59
- package/src/pipeline/project-affinity.ts +162 -0
- package/src/pipeline/search.ts +76 -10
- package/src/pipeline/types.ts +9 -0
- package/src/pipeline/vsearch.ts +117 -91
- package/src/sdk/client.ts +80 -20
- package/src/sdk/index.ts +2 -0
- package/src/sdk/types.ts +20 -7
- package/src/serve/connectors.ts +29 -2
- package/src/serve/context-capsule.ts +18 -1
- package/src/serve/routes/api.ts +69 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Context Capsule build command over the shared application runtime. */
|
|
2
2
|
|
|
3
3
|
import type { ContextCapsuleBuildInput } from "../../app/context-runtime";
|
|
4
|
+
import type { CliProjectAffinityRequest } from "../../core/project-affinity-surface";
|
|
4
5
|
import type { RetrievalTraceSession } from "../../core/retrieval-trace-session";
|
|
5
6
|
import type { EmbeddingPort, RerankPort } from "../../llm/types";
|
|
6
7
|
import type { VectorIndexPort } from "../../store/vector";
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
canonicalBuiltContextCapsuleJson,
|
|
12
13
|
validateContextCapsuleBuildInput,
|
|
13
14
|
} from "../../app/context-runtime";
|
|
15
|
+
import { resolveCliProjectAffinity } from "../../core/project-affinity-surface";
|
|
14
16
|
import {
|
|
15
17
|
finishRetrievalTraceAfterError,
|
|
16
18
|
startRetrievalTraceRequest,
|
|
@@ -27,10 +29,8 @@ import {
|
|
|
27
29
|
} from "../progress";
|
|
28
30
|
import { initStore } from "./shared";
|
|
29
31
|
|
|
30
|
-
export interface ContextBuildCommandOptions
|
|
31
|
-
ContextCapsuleBuildInput,
|
|
32
|
-
"goal"
|
|
33
|
-
> {
|
|
32
|
+
export interface ContextBuildCommandOptions
|
|
33
|
+
extends Omit<ContextCapsuleBuildInput, "goal">, CliProjectAffinityRequest {
|
|
34
34
|
configPath?: string;
|
|
35
35
|
format: "json" | "md";
|
|
36
36
|
}
|
|
@@ -64,8 +64,12 @@ export const contextBuild = async (
|
|
|
64
64
|
goal: string,
|
|
65
65
|
options: ContextBuildCommandOptions
|
|
66
66
|
): Promise<string> => {
|
|
67
|
+
const { projectAffinityDisabled, projectRoots, ...contextOptions } = options;
|
|
67
68
|
try {
|
|
68
|
-
validateContextCapsuleBuildInput(
|
|
69
|
+
validateContextCapsuleBuildInput(
|
|
70
|
+
{ goal, ...contextOptions },
|
|
71
|
+
options.indexName
|
|
72
|
+
);
|
|
69
73
|
} catch (error) {
|
|
70
74
|
throw contextCliError(error);
|
|
71
75
|
}
|
|
@@ -84,8 +88,13 @@ export const contextBuild = async (
|
|
|
84
88
|
let vectorIndex: VectorIndexPort | null = null;
|
|
85
89
|
let traceSession: RetrievalTraceSession | undefined;
|
|
86
90
|
try {
|
|
91
|
+
const projectAffinity = await resolveCliProjectAffinity(config, {
|
|
92
|
+
cwd: process.cwd(),
|
|
93
|
+
disabled: projectAffinityDisabled,
|
|
94
|
+
projectRoots,
|
|
95
|
+
});
|
|
87
96
|
validateContextCapsuleBuildInput(
|
|
88
|
-
{ goal, ...
|
|
97
|
+
{ goal, ...contextOptions },
|
|
89
98
|
options.indexName,
|
|
90
99
|
config.collections.map((collection) => collection.name)
|
|
91
100
|
);
|
|
@@ -163,7 +172,7 @@ export const contextBuild = async (
|
|
|
163
172
|
if (showProgress && progress) process.stderr.write("\n");
|
|
164
173
|
}
|
|
165
174
|
const capsule = await buildContextCapsule(
|
|
166
|
-
{ goal, ...
|
|
175
|
+
{ goal, ...contextOptions },
|
|
167
176
|
{
|
|
168
177
|
store,
|
|
169
178
|
config,
|
|
@@ -171,6 +180,7 @@ export const contextBuild = async (
|
|
|
171
180
|
vectorIndex,
|
|
172
181
|
embedPort,
|
|
173
182
|
rerankPort,
|
|
183
|
+
projectAffinity,
|
|
174
184
|
traceSession,
|
|
175
185
|
}
|
|
176
186
|
);
|
|
@@ -68,6 +68,8 @@ export interface EmbedOptions {
|
|
|
68
68
|
json?: boolean;
|
|
69
69
|
/** Verbose error logging */
|
|
70
70
|
verbose?: boolean;
|
|
71
|
+
/** Use cached models only (also used by the standalone setup worker). */
|
|
72
|
+
offline?: boolean;
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
export type EmbedResult =
|
|
@@ -469,9 +471,12 @@ export async function embed(options: EmbedOptions = {}): Promise<EmbedResult> {
|
|
|
469
471
|
}
|
|
470
472
|
|
|
471
473
|
// Create LLM adapter and embedding port with auto-download
|
|
472
|
-
|
|
474
|
+
let offline = options.offline;
|
|
475
|
+
if (offline === undefined) {
|
|
476
|
+
offline = getGlobals().offline;
|
|
477
|
+
}
|
|
473
478
|
const policy = resolveDownloadPolicy(process.env, {
|
|
474
|
-
offline
|
|
479
|
+
offline,
|
|
475
480
|
});
|
|
476
481
|
|
|
477
482
|
// Create progress renderer for model download (throttled to avoid spam)
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @module src/cli/commands/query
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { CliProjectAffinityRequest } from "../../core/project-affinity-surface";
|
|
8
9
|
import type { RetrievalTraceSurfaceMetadata } from "../../core/retrieval-trace-session";
|
|
9
10
|
import type { RetrievalTraceSession } from "../../core/retrieval-trace-session";
|
|
10
11
|
import type {
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
fingerprintContentTypeRules,
|
|
19
20
|
normalizeContentTypes,
|
|
20
21
|
} from "../../config";
|
|
22
|
+
import { resolveCliProjectAffinity } from "../../core/project-affinity-surface";
|
|
21
23
|
import {
|
|
22
24
|
finishRetrievalTraceAfterError,
|
|
23
25
|
retrievalTraceFilters,
|
|
@@ -46,30 +48,31 @@ import { decorateSearchResultsForIndex, initStore } from "./shared";
|
|
|
46
48
|
// Types
|
|
47
49
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
48
50
|
|
|
49
|
-
export type QueryCommandOptions = HybridSearchOptions &
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
51
|
+
export type QueryCommandOptions = Omit<HybridSearchOptions, "projectAffinity"> &
|
|
52
|
+
CliProjectAffinityRequest & {
|
|
53
|
+
/** Override config path */
|
|
54
|
+
configPath?: string;
|
|
55
|
+
/** Index name */
|
|
56
|
+
indexName?: string;
|
|
57
|
+
/** Override embedding model */
|
|
58
|
+
embedModel?: string;
|
|
59
|
+
/** Override expansion model */
|
|
60
|
+
expandModel?: string;
|
|
61
|
+
/** Deprecated alias for expansion model */
|
|
62
|
+
genModel?: string;
|
|
63
|
+
/** Override rerank model */
|
|
64
|
+
rerankModel?: string;
|
|
65
|
+
/** Output as JSON */
|
|
66
|
+
json?: boolean;
|
|
67
|
+
/** Output as Markdown */
|
|
68
|
+
md?: boolean;
|
|
69
|
+
/** Output as CSV */
|
|
70
|
+
csv?: boolean;
|
|
71
|
+
/** Output as XML */
|
|
72
|
+
xml?: boolean;
|
|
73
|
+
/** Output files only */
|
|
74
|
+
files?: boolean;
|
|
75
|
+
};
|
|
73
76
|
|
|
74
77
|
export interface QueryFormatOptions {
|
|
75
78
|
format: "terminal" | "json" | "files" | "csv" | "md" | "xml";
|
|
@@ -86,16 +89,20 @@ export type QueryResult =
|
|
|
86
89
|
}
|
|
87
90
|
| { success: false; error: string };
|
|
88
91
|
|
|
89
|
-
export type QueryDiagnoseCommandOptions =
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
export type QueryDiagnoseCommandOptions = Omit<
|
|
93
|
+
HybridSearchOptions,
|
|
94
|
+
"projectAffinity"
|
|
95
|
+
> &
|
|
96
|
+
CliProjectAffinityRequest & {
|
|
97
|
+
target: string;
|
|
98
|
+
configPath?: string;
|
|
99
|
+
indexName?: string;
|
|
100
|
+
embedModel?: string;
|
|
101
|
+
expandModel?: string;
|
|
102
|
+
genModel?: string;
|
|
103
|
+
rerankModel?: string;
|
|
104
|
+
json?: boolean;
|
|
105
|
+
};
|
|
99
106
|
|
|
100
107
|
export interface QueryDiagnoseFormatOptions {
|
|
101
108
|
format: "terminal" | "json";
|
|
@@ -140,6 +147,12 @@ export async function query(
|
|
|
140
147
|
let traceSession: RetrievalTraceSession | undefined;
|
|
141
148
|
|
|
142
149
|
try {
|
|
150
|
+
const { projectAffinityDisabled, projectRoots, ...queryOptions } = options;
|
|
151
|
+
const projectAffinity = await resolveCliProjectAffinity(config, {
|
|
152
|
+
cwd: process.cwd(),
|
|
153
|
+
disabled: projectAffinityDisabled,
|
|
154
|
+
projectRoots,
|
|
155
|
+
});
|
|
143
156
|
const embedUri = resolveModelUri(
|
|
144
157
|
config,
|
|
145
158
|
"embed",
|
|
@@ -167,7 +180,7 @@ export async function query(
|
|
|
167
180
|
store,
|
|
168
181
|
config,
|
|
169
182
|
query: queryText,
|
|
170
|
-
filters: retrievalTraceFilters({ ...
|
|
183
|
+
filters: retrievalTraceFilters({ ...queryOptions, limit }),
|
|
171
184
|
pipeline: "hybrid",
|
|
172
185
|
indexName: options.indexName,
|
|
173
186
|
modelUris: [embedUri, expandUri, rerankUri].filter(
|
|
@@ -261,8 +274,9 @@ export async function query(
|
|
|
261
274
|
rerankPort,
|
|
262
275
|
};
|
|
263
276
|
const result = await searchHybrid(deps, queryText, {
|
|
264
|
-
...
|
|
277
|
+
...queryOptions,
|
|
265
278
|
limit,
|
|
279
|
+
projectAffinity,
|
|
266
280
|
traceSession,
|
|
267
281
|
});
|
|
268
282
|
|
|
@@ -318,6 +332,12 @@ export async function queryDiagnose(
|
|
|
318
332
|
let rerankPort: RerankPort | null = null;
|
|
319
333
|
|
|
320
334
|
try {
|
|
335
|
+
const { projectAffinityDisabled, projectRoots, ...queryOptions } = options;
|
|
336
|
+
const projectAffinity = await resolveCliProjectAffinity(config, {
|
|
337
|
+
cwd: process.cwd(),
|
|
338
|
+
disabled: projectAffinityDisabled,
|
|
339
|
+
projectRoots,
|
|
340
|
+
});
|
|
321
341
|
const globals = getGlobals();
|
|
322
342
|
const policy = resolveDownloadPolicy(process.env, {
|
|
323
343
|
offline: globals.offline,
|
|
@@ -415,7 +435,8 @@ export async function queryDiagnose(
|
|
|
415
435
|
rerankPort,
|
|
416
436
|
};
|
|
417
437
|
const result = await diagnoseQueryTarget(deps, queryText, {
|
|
418
|
-
...
|
|
438
|
+
...queryOptions,
|
|
439
|
+
projectAffinity,
|
|
419
440
|
contentTypeRules,
|
|
420
441
|
contentTypeRulesFingerprint:
|
|
421
442
|
fingerprintContentTypeRules(contentTypeRules),
|
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
* @module src/cli/commands/search
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { CliProjectAffinityRequest } from "../../core/project-affinity-surface";
|
|
8
9
|
import type {
|
|
9
10
|
RetrievalTraceSession,
|
|
10
11
|
RetrievalTraceSurfaceMetadata,
|
|
11
12
|
} from "../../core/retrieval-trace-session";
|
|
12
13
|
import type { SearchOptions, SearchResults } from "../../pipeline/types";
|
|
13
14
|
|
|
15
|
+
import { resolveCliProjectAffinity } from "../../core/project-affinity-surface";
|
|
14
16
|
import {
|
|
15
17
|
finishRetrievalTraceAfterError,
|
|
16
18
|
startRetrievalTraceRequest,
|
|
@@ -26,24 +28,25 @@ import { decorateSearchResultsForIndex, initStore } from "./shared";
|
|
|
26
28
|
// Types
|
|
27
29
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
28
30
|
|
|
29
|
-
export type SearchCommandOptions = SearchOptions &
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
31
|
+
export type SearchCommandOptions = Omit<SearchOptions, "projectAffinity"> &
|
|
32
|
+
CliProjectAffinityRequest & {
|
|
33
|
+
/** Override config path */
|
|
34
|
+
configPath?: string;
|
|
35
|
+
/** Index name */
|
|
36
|
+
indexName?: string;
|
|
37
|
+
/** Output as JSON */
|
|
38
|
+
json?: boolean;
|
|
39
|
+
/** Output as Markdown */
|
|
40
|
+
md?: boolean;
|
|
41
|
+
/** Output as CSV */
|
|
42
|
+
csv?: boolean;
|
|
43
|
+
/** Output as XML */
|
|
44
|
+
xml?: boolean;
|
|
45
|
+
/** Output files only */
|
|
46
|
+
files?: boolean;
|
|
47
|
+
/** Terminal hyperlink policy */
|
|
48
|
+
terminalLinks?: FormatOptions["terminalLinks"];
|
|
49
|
+
};
|
|
47
50
|
|
|
48
51
|
export type SearchResult =
|
|
49
52
|
| {
|
|
@@ -84,6 +87,12 @@ export async function search(
|
|
|
84
87
|
let traceSession: RetrievalTraceSession | undefined;
|
|
85
88
|
|
|
86
89
|
try {
|
|
90
|
+
const { projectAffinityDisabled, projectRoots, ...searchOptions } = options;
|
|
91
|
+
const projectAffinity = await resolveCliProjectAffinity(config, {
|
|
92
|
+
cwd: process.cwd(),
|
|
93
|
+
disabled: projectAffinityDisabled,
|
|
94
|
+
projectRoots,
|
|
95
|
+
});
|
|
87
96
|
const started = await startRetrievalTraceRequest({
|
|
88
97
|
store,
|
|
89
98
|
config,
|
|
@@ -109,8 +118,9 @@ export async function search(
|
|
|
109
118
|
if (!started.ok) return { success: false, error: started.error.message };
|
|
110
119
|
traceSession = started.value ?? undefined;
|
|
111
120
|
const result = await searchBm25(store, query, {
|
|
112
|
-
...
|
|
121
|
+
...searchOptions,
|
|
113
122
|
limit,
|
|
123
|
+
projectAffinity,
|
|
114
124
|
traceSession,
|
|
115
125
|
});
|
|
116
126
|
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
SetupConnectorCompositionDeps,
|
|
3
|
+
SetupConnectorDefinition,
|
|
4
|
+
SetupConnectorResult,
|
|
5
|
+
SetupConnectorState,
|
|
6
|
+
} from "../../core/setup-activation";
|
|
7
|
+
import type { SqliteAdapter } from "../../store/sqlite/adapter";
|
|
8
|
+
import type {
|
|
9
|
+
SetupCommandOptions,
|
|
10
|
+
SetupCommandOutcome,
|
|
11
|
+
SetupCommandResult,
|
|
12
|
+
} from "./setup";
|
|
13
|
+
|
|
14
|
+
import { getIndexDbPath } from "../../app/constants";
|
|
15
|
+
import { getConfigPaths, loadConfig, toAbsolutePath } from "../../config";
|
|
16
|
+
import {
|
|
17
|
+
composeSetupConnectors,
|
|
18
|
+
SETUP_ACTIVATION_SCHEMA_VERSION,
|
|
19
|
+
unavailableSetupConnectorComposition,
|
|
20
|
+
} from "../../core/setup-activation";
|
|
21
|
+
import {
|
|
22
|
+
getConnectorDefinition,
|
|
23
|
+
getConnectorStatuses,
|
|
24
|
+
installConnector,
|
|
25
|
+
verifyInstalledConnector,
|
|
26
|
+
} from "../../serve/connectors";
|
|
27
|
+
import { SqliteAdapter as DefaultSqliteAdapter } from "../../store/sqlite/adapter";
|
|
28
|
+
import {
|
|
29
|
+
formatSetupResult,
|
|
30
|
+
lexicalSuccessIsProven,
|
|
31
|
+
SETUP_COMMAND_SCHEMA_VERSION,
|
|
32
|
+
setup,
|
|
33
|
+
} from "./setup";
|
|
34
|
+
|
|
35
|
+
export interface SetupActivationResult {
|
|
36
|
+
schemaVersion: typeof SETUP_ACTIVATION_SCHEMA_VERSION;
|
|
37
|
+
status: "completed" | "completed_with_actions" | "failed";
|
|
38
|
+
setup: SetupCommandResult;
|
|
39
|
+
connectors: SetupConnectorResult[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type SetupOutputResult = SetupCommandResult | SetupActivationResult;
|
|
43
|
+
|
|
44
|
+
export interface SetupOutputOutcome {
|
|
45
|
+
result: SetupOutputResult;
|
|
46
|
+
exitCode: 0 | 1 | 2;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface SetupProfileAdvisoryInput {
|
|
50
|
+
folder: string;
|
|
51
|
+
collection: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface SetupActivationCommandOptions extends SetupCommandOptions {
|
|
55
|
+
connectorIds?: string[];
|
|
56
|
+
connectorWorkspace?: { cwd?: string; homeDir?: string };
|
|
57
|
+
connectorDeps?: SetupConnectorCompositionDeps;
|
|
58
|
+
createActivationStore?: () => SqliteAdapter;
|
|
59
|
+
discoverProfileAdvisory?: (
|
|
60
|
+
input: SetupProfileAdvisoryInput
|
|
61
|
+
) => Promise<unknown>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function dedupeConnectorIds(connectorIds: string[]): string[] {
|
|
65
|
+
return [...new Set(connectorIds)];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function connectorStateFromStatus(
|
|
69
|
+
status: Awaited<ReturnType<typeof getConnectorStatuses>>[number]
|
|
70
|
+
): SetupConnectorState {
|
|
71
|
+
return {
|
|
72
|
+
id: status.id,
|
|
73
|
+
kind: status.installKind,
|
|
74
|
+
target: status.target,
|
|
75
|
+
scope: status.scope,
|
|
76
|
+
installed: status.installed,
|
|
77
|
+
configurationError: Boolean(status.error),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function connectorDefinitions(
|
|
82
|
+
connectorIds: string[]
|
|
83
|
+
): SetupConnectorDefinition[] | null {
|
|
84
|
+
const definitions: SetupConnectorDefinition[] = [];
|
|
85
|
+
for (const connectorId of connectorIds) {
|
|
86
|
+
const definition = getConnectorDefinition(connectorId);
|
|
87
|
+
if (!definition) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
definitions.push(definition);
|
|
91
|
+
}
|
|
92
|
+
return definitions;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function invalidConnectorOutcome(connectorIds: string[]): SetupCommandOutcome {
|
|
96
|
+
const unknown = connectorIds.find(
|
|
97
|
+
(connectorId) => getConnectorDefinition(connectorId) === null
|
|
98
|
+
);
|
|
99
|
+
return {
|
|
100
|
+
result: {
|
|
101
|
+
schemaVersion: SETUP_COMMAND_SCHEMA_VERSION,
|
|
102
|
+
status: "failed",
|
|
103
|
+
lexical: {
|
|
104
|
+
receipt: null,
|
|
105
|
+
error: {
|
|
106
|
+
code: "invalid_connector",
|
|
107
|
+
message: `Unknown connector: ${unknown ?? ""}`.trim(),
|
|
108
|
+
remediation:
|
|
109
|
+
"Run `gno setup --help` and pass one documented connector ID.",
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
semantic: null,
|
|
113
|
+
},
|
|
114
|
+
exitCode: 1,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function failedSetupActivationOutcome(
|
|
119
|
+
setupOutcome: SetupCommandOutcome
|
|
120
|
+
): SetupOutputOutcome {
|
|
121
|
+
return {
|
|
122
|
+
result: {
|
|
123
|
+
schemaVersion: SETUP_ACTIVATION_SCHEMA_VERSION,
|
|
124
|
+
status: "failed",
|
|
125
|
+
setup: setupOutcome.result,
|
|
126
|
+
connectors: [],
|
|
127
|
+
},
|
|
128
|
+
exitCode: setupOutcome.exitCode,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function defaultConnectorDeps(
|
|
133
|
+
workspace: { cwd?: string; homeDir?: string } | undefined
|
|
134
|
+
): SetupConnectorCompositionDeps {
|
|
135
|
+
return {
|
|
136
|
+
getStates: async () =>
|
|
137
|
+
(await getConnectorStatuses(workspace)).map(connectorStateFromStatus),
|
|
138
|
+
install: async (connectorId, context) =>
|
|
139
|
+
connectorStateFromStatus(
|
|
140
|
+
await installConnector(
|
|
141
|
+
connectorId,
|
|
142
|
+
{ reinstall: false },
|
|
143
|
+
{
|
|
144
|
+
...workspace,
|
|
145
|
+
indexName: context.indexName,
|
|
146
|
+
configPath: context.configPath,
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
),
|
|
150
|
+
verify: async (connectorId, store, collection) =>
|
|
151
|
+
verifyInstalledConnector(
|
|
152
|
+
connectorId,
|
|
153
|
+
store,
|
|
154
|
+
collection,
|
|
155
|
+
undefined,
|
|
156
|
+
workspace
|
|
157
|
+
),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function discoverProfileAdvisory(
|
|
162
|
+
discover: SetupActivationCommandOptions["discoverProfileAdvisory"],
|
|
163
|
+
input: SetupProfileAdvisoryInput
|
|
164
|
+
): Promise<void> {
|
|
165
|
+
if (!discover) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
await discover(input);
|
|
170
|
+
} catch {
|
|
171
|
+
// Advisory discovery cannot mutate or fail verified setup.
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function withUnavailableConnectors(
|
|
176
|
+
setupResult: SetupCommandResult,
|
|
177
|
+
definitions: SetupConnectorDefinition[]
|
|
178
|
+
): SetupOutputOutcome {
|
|
179
|
+
const unavailable = unavailableSetupConnectorComposition(definitions);
|
|
180
|
+
return {
|
|
181
|
+
result: {
|
|
182
|
+
schemaVersion: SETUP_ACTIVATION_SCHEMA_VERSION,
|
|
183
|
+
status: unavailable.status,
|
|
184
|
+
setup: setupResult,
|
|
185
|
+
connectors: unavailable.connectors,
|
|
186
|
+
},
|
|
187
|
+
exitCode: 0,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function closeActivationStore(
|
|
192
|
+
store: SqliteAdapter | null
|
|
193
|
+
): Promise<void> {
|
|
194
|
+
if (!store) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
await store.close();
|
|
199
|
+
} catch {
|
|
200
|
+
// Connector cleanup cannot replace proven lexical success.
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Add opt-in connector onboarding beside the unchanged setup result.
|
|
206
|
+
* No-connector calls retain setup-command-result@1.0; connector-mode failures
|
|
207
|
+
* wrap the unchanged failed setup result without running connector actions.
|
|
208
|
+
*/
|
|
209
|
+
export async function setupWithActivation(
|
|
210
|
+
options: SetupActivationCommandOptions
|
|
211
|
+
): Promise<SetupOutputOutcome> {
|
|
212
|
+
const requestedIds = dedupeConnectorIds(options.connectorIds ?? []);
|
|
213
|
+
const definitions = connectorDefinitions(requestedIds);
|
|
214
|
+
if (!definitions) {
|
|
215
|
+
return failedSetupActivationOutcome(invalidConnectorOutcome(requestedIds));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const {
|
|
219
|
+
connectorIds: _connectorIds,
|
|
220
|
+
connectorWorkspace: _connectorWorkspace,
|
|
221
|
+
connectorDeps: _connectorDeps,
|
|
222
|
+
createActivationStore: _createActivationStore,
|
|
223
|
+
discoverProfileAdvisory: _discoverProfileAdvisory,
|
|
224
|
+
...setupOptions
|
|
225
|
+
} = options;
|
|
226
|
+
const setupOutcome = await setup(setupOptions);
|
|
227
|
+
if (
|
|
228
|
+
setupOutcome.exitCode !== 0 ||
|
|
229
|
+
setupOutcome.result.status !== "completed"
|
|
230
|
+
) {
|
|
231
|
+
return definitions.length > 0
|
|
232
|
+
? failedSetupActivationOutcome(setupOutcome)
|
|
233
|
+
: setupOutcome;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const lexicalReceipt = setupOutcome.result.lexical.receipt;
|
|
237
|
+
const collection = lexicalReceipt?.collection.name;
|
|
238
|
+
if (
|
|
239
|
+
!lexicalReceipt ||
|
|
240
|
+
!collection ||
|
|
241
|
+
!lexicalSuccessIsProven(lexicalReceipt)
|
|
242
|
+
) {
|
|
243
|
+
return setupOutcome;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
await discoverProfileAdvisory(options.discoverProfileAdvisory, {
|
|
247
|
+
folder: lexicalReceipt.input.folder,
|
|
248
|
+
collection,
|
|
249
|
+
});
|
|
250
|
+
if (definitions.length === 0) {
|
|
251
|
+
return setupOutcome;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
let store: SqliteAdapter | null = null;
|
|
255
|
+
try {
|
|
256
|
+
const paths = getConfigPaths();
|
|
257
|
+
const configPath = toAbsolutePath(options.configPath ?? paths.configFile);
|
|
258
|
+
const indexName = options.indexName ?? "default";
|
|
259
|
+
const configResult = await loadConfig(configPath);
|
|
260
|
+
if (!configResult.ok) {
|
|
261
|
+
return withUnavailableConnectors(setupOutcome.result, definitions);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
store =
|
|
265
|
+
options.createActivationStore?.() ??
|
|
266
|
+
(new DefaultSqliteAdapter() as SqliteAdapter);
|
|
267
|
+
store.setConfigPath(configPath);
|
|
268
|
+
const opened = await store.open(
|
|
269
|
+
getIndexDbPath(indexName),
|
|
270
|
+
configResult.value.ftsTokenizer
|
|
271
|
+
);
|
|
272
|
+
if (!opened.ok) {
|
|
273
|
+
return withUnavailableConnectors(setupOutcome.result, definitions);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const composition = await composeSetupConnectors({
|
|
277
|
+
connectorIds: requestedIds,
|
|
278
|
+
definitions,
|
|
279
|
+
collection,
|
|
280
|
+
store,
|
|
281
|
+
installContext: { indexName, configPath },
|
|
282
|
+
deps:
|
|
283
|
+
options.connectorDeps ??
|
|
284
|
+
defaultConnectorDeps(options.connectorWorkspace),
|
|
285
|
+
});
|
|
286
|
+
return {
|
|
287
|
+
result: {
|
|
288
|
+
schemaVersion: SETUP_ACTIVATION_SCHEMA_VERSION,
|
|
289
|
+
status: composition.status,
|
|
290
|
+
setup: setupOutcome.result,
|
|
291
|
+
connectors: composition.connectors,
|
|
292
|
+
},
|
|
293
|
+
exitCode: 0,
|
|
294
|
+
};
|
|
295
|
+
} catch {
|
|
296
|
+
return withUnavailableConnectors(setupOutcome.result, definitions);
|
|
297
|
+
} finally {
|
|
298
|
+
await closeActivationStore(store);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function isSetupActivationResult(
|
|
303
|
+
result: SetupOutputResult
|
|
304
|
+
): result is SetupActivationResult {
|
|
305
|
+
return "setup" in result;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function formatSetupOutputResult(
|
|
309
|
+
result: SetupOutputResult,
|
|
310
|
+
options: { json: boolean }
|
|
311
|
+
): string {
|
|
312
|
+
if (options.json) {
|
|
313
|
+
return JSON.stringify(result, null, 2);
|
|
314
|
+
}
|
|
315
|
+
if (!isSetupActivationResult(result)) {
|
|
316
|
+
return formatSetupResult(result, options);
|
|
317
|
+
}
|
|
318
|
+
const setupOutput = formatSetupResult(result.setup, options);
|
|
319
|
+
const connectorOutput = result.connectors.map(
|
|
320
|
+
(connector) =>
|
|
321
|
+
`connector=${connector.connectorId} installation=${connector.installation} verification=${connector.verification} code=${connector.code} remediation=${connector.remediation}`
|
|
322
|
+
);
|
|
323
|
+
return [setupOutput, ...connectorOutput].join("\n");
|
|
324
|
+
}
|