@gmickel/gno 1.25.1 → 1.26.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 +10 -4
- package/assets/skill/SKILL.md +29 -17
- package/browser-extension/artifacts/{gno-browser-clipper-v1.25.1.zip → gno-browser-clipper-v1.26.0.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.26.0.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +1 -1
- package/spec/cli.md +146 -4
- package/spec/db/schema.sql +1 -1
- package/spec/output-schemas/project-profile-apply.schema.json +209 -0
- package/spec/output-schemas/project-profile-command.schema.json +160 -0
- package/spec/output-schemas/query-diagnose.schema.json +7 -1
- package/spec/output-schemas/setup-profile-result.schema.json +87 -0
- package/spec/project-profile.schema.json +301 -0
- package/src/cli/commands/collection/add.ts +39 -45
- package/src/cli/commands/collection/remove.ts +28 -28
- package/src/cli/commands/collection/rename.ts +55 -73
- package/src/cli/commands/context/add.ts +37 -26
- package/src/cli/commands/context/rm.ts +47 -20
- package/src/cli/commands/init.ts +55 -125
- package/src/cli/commands/models/use.ts +43 -38
- package/src/cli/commands/profile-apply.ts +334 -0
- package/src/cli/commands/profile.ts +409 -0
- package/src/cli/commands/setup-activation.ts +205 -54
- package/src/cli/commands/setup-profile.ts +223 -0
- package/src/cli/commands/setup.ts +3 -0
- package/src/cli/program.ts +110 -9
- package/src/config/index.ts +3 -0
- package/src/config/project-profile.ts +367 -0
- package/src/config/saver.ts +16 -7
- package/src/config/types.ts +42 -0
- package/src/core/config-mutation.ts +138 -76
- package/src/core/config-write-lock.ts +89 -0
- package/src/core/context-identity.ts +16 -0
- package/src/core/context-resolver.ts +2 -12
- package/src/core/folder-setup-planning.ts +6 -21
- package/src/core/folder-setup.ts +30 -2
- package/src/core/path-rules.ts +53 -0
- package/src/core/project-affinity-surface.ts +102 -7
- package/src/core/project-profile-apply-state.ts +268 -0
- package/src/core/project-profile-apply-validation.ts +95 -0
- package/src/core/project-profile-apply.ts +408 -0
- package/src/core/project-profile-canonical.ts +71 -0
- package/src/core/project-profile-diff.ts +302 -0
- package/src/core/project-profile-discovery.ts +519 -0
- package/src/core/project-profile-file.ts +37 -0
- package/src/core/project-profile-parser.ts +98 -0
- package/src/core/project-profile.ts +490 -0
- package/src/ingestion/walker.ts +85 -44
- package/src/llm/cache.ts +21 -0
- package/src/serve/config-sync.ts +2 -2
- package/src/serve/resident-runtime.ts +1 -0
- package/src/serve/routes/api.ts +1 -0
- package/src/store/migrations/021-multi-context-identity.ts +37 -0
- package/src/store/migrations/index.ts +2 -0
- package/src/store/sqlite/adapter.ts +83 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.25.1.zip.sha256 +0 -1
|
@@ -5,11 +5,10 @@ import type {
|
|
|
5
5
|
SetupConnectorState,
|
|
6
6
|
} from "../../core/setup-activation";
|
|
7
7
|
import type { SqliteAdapter } from "../../store/sqlite/adapter";
|
|
8
|
-
import type {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from "./setup";
|
|
8
|
+
import type { ProjectProfileCommandResult } from "./profile";
|
|
9
|
+
import type { ProjectProfileApplyCommandResult } from "./profile-apply";
|
|
10
|
+
import type { SetupCommandOutcome, SetupCommandResult } from "./setup";
|
|
11
|
+
import type { SetupProfileIntegrationOptions } from "./setup-profile";
|
|
13
12
|
|
|
14
13
|
import { getIndexDbPath } from "../../app/constants";
|
|
15
14
|
import { getConfigPaths, loadConfig, toAbsolutePath } from "../../config";
|
|
@@ -31,6 +30,16 @@ import {
|
|
|
31
30
|
SETUP_COMMAND_SCHEMA_VERSION,
|
|
32
31
|
setup,
|
|
33
32
|
} from "./setup";
|
|
33
|
+
import {
|
|
34
|
+
applySetupProfile,
|
|
35
|
+
inspectSetupProfile,
|
|
36
|
+
profileApplyFailureOutcome,
|
|
37
|
+
profileApplySucceeded,
|
|
38
|
+
profileInspectionFailureOutcome,
|
|
39
|
+
setupOptionsAfterProfileApply,
|
|
40
|
+
} from "./setup-profile";
|
|
41
|
+
|
|
42
|
+
export { formatSetupProfileAdvisory } from "./setup-profile";
|
|
34
43
|
|
|
35
44
|
export interface SetupActivationResult {
|
|
36
45
|
schemaVersion: typeof SETUP_ACTIVATION_SCHEMA_VERSION;
|
|
@@ -39,26 +48,38 @@ export interface SetupActivationResult {
|
|
|
39
48
|
connectors: SetupConnectorResult[];
|
|
40
49
|
}
|
|
41
50
|
|
|
42
|
-
export
|
|
51
|
+
export interface SetupProfileResult {
|
|
52
|
+
schemaVersion: "1.0";
|
|
53
|
+
status: "completed" | "completed_with_actions" | "failed";
|
|
54
|
+
profile: {
|
|
55
|
+
check: ProjectProfileCommandResult;
|
|
56
|
+
apply: ProjectProfileApplyCommandResult | null;
|
|
57
|
+
};
|
|
58
|
+
setup: SetupCommandResult;
|
|
59
|
+
connectors: SetupConnectorResult[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type SetupOutputResult =
|
|
63
|
+
| SetupCommandResult
|
|
64
|
+
| SetupActivationResult
|
|
65
|
+
| SetupProfileResult;
|
|
43
66
|
|
|
44
67
|
export interface SetupOutputOutcome {
|
|
45
68
|
result: SetupOutputResult;
|
|
46
69
|
exitCode: 0 | 1 | 2;
|
|
47
70
|
}
|
|
48
71
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
72
|
+
function isComposedSetupResult(
|
|
73
|
+
result: SetupOutputResult
|
|
74
|
+
): result is SetupActivationResult | SetupProfileResult {
|
|
75
|
+
return "setup" in result;
|
|
52
76
|
}
|
|
53
77
|
|
|
54
|
-
export interface SetupActivationCommandOptions extends
|
|
78
|
+
export interface SetupActivationCommandOptions extends SetupProfileIntegrationOptions {
|
|
55
79
|
connectorIds?: string[];
|
|
56
80
|
connectorWorkspace?: { cwd?: string; homeDir?: string };
|
|
57
81
|
connectorDeps?: SetupConnectorCompositionDeps;
|
|
58
82
|
createActivationStore?: () => SqliteAdapter;
|
|
59
|
-
discoverProfileAdvisory?: (
|
|
60
|
-
input: SetupProfileAdvisoryInput
|
|
61
|
-
) => Promise<unknown>;
|
|
62
83
|
}
|
|
63
84
|
|
|
64
85
|
function dedupeConnectorIds(connectorIds: string[]): string[] {
|
|
@@ -115,6 +136,27 @@ function invalidConnectorOutcome(connectorIds: string[]): SetupCommandOutcome {
|
|
|
115
136
|
};
|
|
116
137
|
}
|
|
117
138
|
|
|
139
|
+
function profileOptionConflictOutcome(): SetupCommandOutcome {
|
|
140
|
+
return {
|
|
141
|
+
result: {
|
|
142
|
+
schemaVersion: SETUP_COMMAND_SCHEMA_VERSION,
|
|
143
|
+
status: "failed",
|
|
144
|
+
lexical: {
|
|
145
|
+
receipt: null,
|
|
146
|
+
error: {
|
|
147
|
+
code: "profile_option_conflict",
|
|
148
|
+
message:
|
|
149
|
+
"--apply-profile cannot be combined with explicit --name or --exclude options.",
|
|
150
|
+
remediation:
|
|
151
|
+
"Remove the explicit setup overrides or run setup without --apply-profile.",
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
semantic: null,
|
|
155
|
+
},
|
|
156
|
+
exitCode: 1,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
118
160
|
function failedSetupActivationOutcome(
|
|
119
161
|
setupOutcome: SetupCommandOutcome
|
|
120
162
|
): SetupOutputOutcome {
|
|
@@ -158,18 +200,37 @@ function defaultConnectorDeps(
|
|
|
158
200
|
};
|
|
159
201
|
}
|
|
160
202
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
203
|
+
function withProfileResult(
|
|
204
|
+
outcome: SetupOutputOutcome,
|
|
205
|
+
requested: boolean,
|
|
206
|
+
check: ProjectProfileCommandResult | null,
|
|
207
|
+
applied: ProjectProfileApplyCommandResult | null
|
|
208
|
+
): SetupOutputOutcome {
|
|
209
|
+
if (!requested || !check) return outcome;
|
|
210
|
+
const setupResult = isComposedSetupResult(outcome.result)
|
|
211
|
+
? outcome.result.setup
|
|
212
|
+
: outcome.result;
|
|
213
|
+
const connectors = isComposedSetupResult(outcome.result)
|
|
214
|
+
? outcome.result.connectors
|
|
215
|
+
: [];
|
|
216
|
+
const profileCompleted =
|
|
217
|
+
applied?.status === "applied" || applied?.status === "unchanged";
|
|
218
|
+
return {
|
|
219
|
+
exitCode: outcome.exitCode,
|
|
220
|
+
result: {
|
|
221
|
+
schemaVersion: "1.0",
|
|
222
|
+
status:
|
|
223
|
+
setupResult.status === "failed"
|
|
224
|
+
? "failed"
|
|
225
|
+
: outcome.result.status === "completed_with_actions" ||
|
|
226
|
+
!profileCompleted
|
|
227
|
+
? "completed_with_actions"
|
|
228
|
+
: "completed",
|
|
229
|
+
profile: { check, apply: applied },
|
|
230
|
+
setup: setupResult,
|
|
231
|
+
connectors,
|
|
232
|
+
},
|
|
233
|
+
};
|
|
173
234
|
}
|
|
174
235
|
|
|
175
236
|
function withUnavailableConnectors(
|
|
@@ -220,17 +281,87 @@ export async function setupWithActivation(
|
|
|
220
281
|
connectorWorkspace: _connectorWorkspace,
|
|
221
282
|
connectorDeps: _connectorDeps,
|
|
222
283
|
createActivationStore: _createActivationStore,
|
|
223
|
-
|
|
284
|
+
applyProfile: _applyProfile,
|
|
285
|
+
inspectProfileAdvisory: _inspectProfileAdvisory,
|
|
286
|
+
applyProfileAdvisory: _applyProfileAdvisory,
|
|
287
|
+
onProfileAdvisory: _onProfileAdvisory,
|
|
288
|
+
onProfileApply: _onProfileApply,
|
|
224
289
|
...setupOptions
|
|
225
290
|
} = options;
|
|
226
|
-
const
|
|
291
|
+
const profileInspection = await inspectSetupProfile(options);
|
|
292
|
+
const profileCheck = profileInspection.result;
|
|
293
|
+
if (options.applyProfile && profileInspection.failed) {
|
|
294
|
+
const failedInspection = profileInspectionFailureOutcome();
|
|
295
|
+
return definitions.length > 0
|
|
296
|
+
? failedSetupActivationOutcome(failedInspection)
|
|
297
|
+
: failedInspection;
|
|
298
|
+
}
|
|
299
|
+
if (
|
|
300
|
+
options.applyProfile &&
|
|
301
|
+
profileCheck?.status === "valid" &&
|
|
302
|
+
(options.name !== undefined || (options.exclude?.length ?? 0) > 0)
|
|
303
|
+
) {
|
|
304
|
+
return withProfileResult(
|
|
305
|
+
definitions.length > 0
|
|
306
|
+
? failedSetupActivationOutcome(profileOptionConflictOutcome())
|
|
307
|
+
: profileOptionConflictOutcome(),
|
|
308
|
+
true,
|
|
309
|
+
profileCheck,
|
|
310
|
+
null
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
const profileApplyOutcome = await applySetupProfile(options, profileCheck);
|
|
314
|
+
const profileApplySuccess = profileApplySucceeded(profileApplyOutcome);
|
|
315
|
+
const returnedProfileApply = profileApplyOutcome?.result ?? null;
|
|
316
|
+
const profileApply =
|
|
317
|
+
profileApplyOutcome?.exitCode === 0 && !profileApplySuccess
|
|
318
|
+
? null
|
|
319
|
+
: returnedProfileApply;
|
|
320
|
+
if (
|
|
321
|
+
options.applyProfile &&
|
|
322
|
+
profileCheck?.status === "valid" &&
|
|
323
|
+
!profileApplySuccess
|
|
324
|
+
) {
|
|
325
|
+
const failedApply = profileApplyFailureOutcome(profileApplyOutcome);
|
|
326
|
+
return withProfileResult(
|
|
327
|
+
definitions.length > 0
|
|
328
|
+
? failedSetupActivationOutcome(failedApply)
|
|
329
|
+
: failedApply,
|
|
330
|
+
true,
|
|
331
|
+
profileCheck,
|
|
332
|
+
profileApply
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
const effectiveSetupOptions = await setupOptionsAfterProfileApply(
|
|
336
|
+
setupOptions,
|
|
337
|
+
profileApply
|
|
338
|
+
);
|
|
339
|
+
if (effectiveSetupOptions === null) {
|
|
340
|
+
const failedApply = profileApplyFailureOutcome(profileApplyOutcome);
|
|
341
|
+
return withProfileResult(
|
|
342
|
+
definitions.length > 0
|
|
343
|
+
? failedSetupActivationOutcome(failedApply)
|
|
344
|
+
: failedApply,
|
|
345
|
+
true,
|
|
346
|
+
profileCheck,
|
|
347
|
+
profileApply
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
const setupOutcome = await setup(effectiveSetupOptions);
|
|
227
351
|
if (
|
|
228
352
|
setupOutcome.exitCode !== 0 ||
|
|
229
353
|
setupOutcome.result.status !== "completed"
|
|
230
354
|
) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
355
|
+
const failed =
|
|
356
|
+
definitions.length > 0
|
|
357
|
+
? failedSetupActivationOutcome(setupOutcome)
|
|
358
|
+
: setupOutcome;
|
|
359
|
+
return withProfileResult(
|
|
360
|
+
failed,
|
|
361
|
+
Boolean(options.applyProfile),
|
|
362
|
+
profileCheck,
|
|
363
|
+
profileApply
|
|
364
|
+
);
|
|
234
365
|
}
|
|
235
366
|
|
|
236
367
|
const lexicalReceipt = setupOutcome.result.lexical.receipt;
|
|
@@ -240,15 +371,21 @@ export async function setupWithActivation(
|
|
|
240
371
|
!collection ||
|
|
241
372
|
!lexicalSuccessIsProven(lexicalReceipt)
|
|
242
373
|
) {
|
|
243
|
-
return
|
|
374
|
+
return withProfileResult(
|
|
375
|
+
setupOutcome,
|
|
376
|
+
Boolean(options.applyProfile),
|
|
377
|
+
profileCheck,
|
|
378
|
+
profileApply
|
|
379
|
+
);
|
|
244
380
|
}
|
|
245
381
|
|
|
246
|
-
await discoverProfileAdvisory(options.discoverProfileAdvisory, {
|
|
247
|
-
folder: lexicalReceipt.input.folder,
|
|
248
|
-
collection,
|
|
249
|
-
});
|
|
250
382
|
if (definitions.length === 0) {
|
|
251
|
-
return
|
|
383
|
+
return withProfileResult(
|
|
384
|
+
setupOutcome,
|
|
385
|
+
Boolean(options.applyProfile),
|
|
386
|
+
profileCheck,
|
|
387
|
+
profileApply
|
|
388
|
+
);
|
|
252
389
|
}
|
|
253
390
|
|
|
254
391
|
let store: SqliteAdapter | null = null;
|
|
@@ -258,7 +395,12 @@ export async function setupWithActivation(
|
|
|
258
395
|
const indexName = options.indexName ?? "default";
|
|
259
396
|
const configResult = await loadConfig(configPath);
|
|
260
397
|
if (!configResult.ok) {
|
|
261
|
-
return
|
|
398
|
+
return withProfileResult(
|
|
399
|
+
withUnavailableConnectors(setupOutcome.result, definitions),
|
|
400
|
+
Boolean(options.applyProfile),
|
|
401
|
+
profileCheck,
|
|
402
|
+
profileApply
|
|
403
|
+
);
|
|
262
404
|
}
|
|
263
405
|
|
|
264
406
|
store =
|
|
@@ -270,7 +412,12 @@ export async function setupWithActivation(
|
|
|
270
412
|
configResult.value.ftsTokenizer
|
|
271
413
|
);
|
|
272
414
|
if (!opened.ok) {
|
|
273
|
-
return
|
|
415
|
+
return withProfileResult(
|
|
416
|
+
withUnavailableConnectors(setupOutcome.result, definitions),
|
|
417
|
+
Boolean(options.applyProfile),
|
|
418
|
+
profileCheck,
|
|
419
|
+
profileApply
|
|
420
|
+
);
|
|
274
421
|
}
|
|
275
422
|
|
|
276
423
|
const composition = await composeSetupConnectors({
|
|
@@ -283,28 +430,32 @@ export async function setupWithActivation(
|
|
|
283
430
|
options.connectorDeps ??
|
|
284
431
|
defaultConnectorDeps(options.connectorWorkspace),
|
|
285
432
|
});
|
|
286
|
-
return
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
433
|
+
return withProfileResult(
|
|
434
|
+
{
|
|
435
|
+
result: {
|
|
436
|
+
schemaVersion: SETUP_ACTIVATION_SCHEMA_VERSION,
|
|
437
|
+
status: composition.status,
|
|
438
|
+
setup: setupOutcome.result,
|
|
439
|
+
connectors: composition.connectors,
|
|
440
|
+
},
|
|
441
|
+
exitCode: 0,
|
|
292
442
|
},
|
|
293
|
-
|
|
294
|
-
|
|
443
|
+
Boolean(options.applyProfile),
|
|
444
|
+
profileCheck,
|
|
445
|
+
profileApply
|
|
446
|
+
);
|
|
295
447
|
} catch {
|
|
296
|
-
return
|
|
448
|
+
return withProfileResult(
|
|
449
|
+
withUnavailableConnectors(setupOutcome.result, definitions),
|
|
450
|
+
Boolean(options.applyProfile),
|
|
451
|
+
profileCheck,
|
|
452
|
+
profileApply
|
|
453
|
+
);
|
|
297
454
|
} finally {
|
|
298
455
|
await closeActivationStore(store);
|
|
299
456
|
}
|
|
300
457
|
}
|
|
301
458
|
|
|
302
|
-
function isSetupActivationResult(
|
|
303
|
-
result: SetupOutputResult
|
|
304
|
-
): result is SetupActivationResult {
|
|
305
|
-
return "setup" in result;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
459
|
export function formatSetupOutputResult(
|
|
309
460
|
result: SetupOutputResult,
|
|
310
461
|
options: { json: boolean }
|
|
@@ -312,7 +463,7 @@ export function formatSetupOutputResult(
|
|
|
312
463
|
if (options.json) {
|
|
313
464
|
return JSON.stringify(result, null, 2);
|
|
314
465
|
}
|
|
315
|
-
if (!
|
|
466
|
+
if (!isComposedSetupResult(result)) {
|
|
316
467
|
return formatSetupResult(result, options);
|
|
317
468
|
}
|
|
318
469
|
const setupOutput = formatSetupResult(result.setup, options);
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional project-profile composition for `gno setup`.
|
|
3
|
+
*
|
|
4
|
+
* Inspection is always read-only and non-fatal. Application requires the
|
|
5
|
+
* explicit `--apply-profile` request and reuses the lock-safe profile command.
|
|
6
|
+
*
|
|
7
|
+
* @module src/cli/commands/setup-profile
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
ProjectProfileCommandOutcome,
|
|
12
|
+
ProjectProfileCommandResult,
|
|
13
|
+
} from "./profile";
|
|
14
|
+
import type {
|
|
15
|
+
ProjectProfileApplyCommandOutcome,
|
|
16
|
+
ProjectProfileApplyCommandResult,
|
|
17
|
+
} from "./profile-apply";
|
|
18
|
+
import type { SetupCommandOptions, SetupCommandOutcome } from "./setup";
|
|
19
|
+
|
|
20
|
+
import { loadConfig } from "../../config";
|
|
21
|
+
import { isProjectProfileApplyReceipt } from "../../core/project-profile-apply-validation";
|
|
22
|
+
import { runProjectProfileCommand } from "./profile";
|
|
23
|
+
import { SETUP_COMMAND_SCHEMA_VERSION } from "./setup";
|
|
24
|
+
|
|
25
|
+
export interface SetupProfileAdvisoryInput {
|
|
26
|
+
folder: string;
|
|
27
|
+
configPath?: string;
|
|
28
|
+
offline?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface SetupProfileIntegrationOptions extends SetupCommandOptions {
|
|
32
|
+
applyProfile?: boolean;
|
|
33
|
+
inspectProfileAdvisory?: (
|
|
34
|
+
input: SetupProfileAdvisoryInput
|
|
35
|
+
) => Promise<ProjectProfileCommandOutcome>;
|
|
36
|
+
applyProfileAdvisory?: (
|
|
37
|
+
input: SetupProfileAdvisoryInput
|
|
38
|
+
) => Promise<ProjectProfileApplyCommandOutcome>;
|
|
39
|
+
onProfileAdvisory?: (result: ProjectProfileCommandResult) => void;
|
|
40
|
+
onProfileApply?: (result: ProjectProfileApplyCommandResult) => void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface SetupProfileInspectionOutcome {
|
|
44
|
+
result: ProjectProfileCommandResult | null;
|
|
45
|
+
failed: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function profileInspectionFailureOutcome(): SetupCommandOutcome {
|
|
49
|
+
return {
|
|
50
|
+
result: {
|
|
51
|
+
schemaVersion: SETUP_COMMAND_SCHEMA_VERSION,
|
|
52
|
+
status: "failed",
|
|
53
|
+
lexical: {
|
|
54
|
+
receipt: null,
|
|
55
|
+
error: {
|
|
56
|
+
code: "profile_inspection_failed",
|
|
57
|
+
message:
|
|
58
|
+
"The requested project profile could not be inspected safely before setup.",
|
|
59
|
+
remediation:
|
|
60
|
+
"Run `gno profile check` for diagnostics, repair the reported problem, and retry setup.",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
semantic: null,
|
|
64
|
+
},
|
|
65
|
+
exitCode: 2,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function profileApplyFailureOutcome(
|
|
70
|
+
outcome: ProjectProfileApplyCommandOutcome | null
|
|
71
|
+
): SetupCommandOutcome {
|
|
72
|
+
return {
|
|
73
|
+
result: {
|
|
74
|
+
schemaVersion: SETUP_COMMAND_SCHEMA_VERSION,
|
|
75
|
+
status: "failed",
|
|
76
|
+
lexical: {
|
|
77
|
+
receipt: null,
|
|
78
|
+
error: {
|
|
79
|
+
code: "profile_apply_failed",
|
|
80
|
+
message:
|
|
81
|
+
"The valid project profile could not be applied safely before setup.",
|
|
82
|
+
remediation:
|
|
83
|
+
"Run `gno profile apply` for diagnostics, repair the reported problem, and retry setup.",
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
semantic: null,
|
|
87
|
+
},
|
|
88
|
+
exitCode: outcome?.exitCode === 1 ? 1 : 2,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function profileApplySucceeded(
|
|
93
|
+
outcome: ProjectProfileApplyCommandOutcome | null
|
|
94
|
+
): boolean {
|
|
95
|
+
if (
|
|
96
|
+
outcome?.exitCode !== 0 ||
|
|
97
|
+
(outcome.result.status !== "applied" &&
|
|
98
|
+
outcome.result.status !== "unchanged")
|
|
99
|
+
) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const receipt = outcome.result.receipt;
|
|
103
|
+
if (
|
|
104
|
+
!isProjectProfileApplyReceipt(receipt) ||
|
|
105
|
+
receipt.status !== outcome.result.status ||
|
|
106
|
+
outcome.result.applied !== (outcome.result.status === "applied")
|
|
107
|
+
) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
const collectionResources = receipt.resources.filter(
|
|
111
|
+
(resource) => resource.kind === "collection"
|
|
112
|
+
);
|
|
113
|
+
return (
|
|
114
|
+
collectionResources.length === 1 &&
|
|
115
|
+
Boolean(collectionResources[0]?.id.trim())
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function inspectSetupProfile(
|
|
120
|
+
options: SetupProfileIntegrationOptions
|
|
121
|
+
): Promise<SetupProfileInspectionOutcome> {
|
|
122
|
+
try {
|
|
123
|
+
const outcome = await (
|
|
124
|
+
options.inspectProfileAdvisory ??
|
|
125
|
+
((input: SetupProfileAdvisoryInput) =>
|
|
126
|
+
runProjectProfileCommand({
|
|
127
|
+
command: "check",
|
|
128
|
+
cwd: input.folder,
|
|
129
|
+
configPath: input.configPath,
|
|
130
|
+
offline: input.offline,
|
|
131
|
+
}))
|
|
132
|
+
)({
|
|
133
|
+
folder: options.folder,
|
|
134
|
+
configPath: options.configPath,
|
|
135
|
+
offline: options.offline,
|
|
136
|
+
});
|
|
137
|
+
options.onProfileAdvisory?.(outcome.result);
|
|
138
|
+
return { result: outcome.result, failed: false };
|
|
139
|
+
} catch {
|
|
140
|
+
return { result: null, failed: true };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function applySetupProfile(
|
|
145
|
+
options: SetupProfileIntegrationOptions,
|
|
146
|
+
inspection: ProjectProfileCommandResult | null
|
|
147
|
+
): Promise<ProjectProfileApplyCommandOutcome | null> {
|
|
148
|
+
if (!options.applyProfile || inspection?.status !== "valid") return null;
|
|
149
|
+
try {
|
|
150
|
+
const outcome = await (
|
|
151
|
+
options.applyProfileAdvisory ??
|
|
152
|
+
((input: SetupProfileAdvisoryInput) =>
|
|
153
|
+
import("./profile-apply").then(({ runProjectProfileApplyCommand }) =>
|
|
154
|
+
runProjectProfileApplyCommand({
|
|
155
|
+
cwd: input.folder,
|
|
156
|
+
configPath: input.configPath,
|
|
157
|
+
indexName: options.indexName,
|
|
158
|
+
})
|
|
159
|
+
))
|
|
160
|
+
)({
|
|
161
|
+
folder: options.folder,
|
|
162
|
+
configPath: options.configPath,
|
|
163
|
+
offline: options.offline,
|
|
164
|
+
});
|
|
165
|
+
options.onProfileApply?.(outcome.result);
|
|
166
|
+
return outcome;
|
|
167
|
+
} catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function setupOptionsAfterProfileApply(
|
|
173
|
+
options: SetupCommandOptions,
|
|
174
|
+
applied: ProjectProfileApplyCommandResult | null
|
|
175
|
+
): Promise<SetupCommandOptions | null> {
|
|
176
|
+
if (
|
|
177
|
+
!applied ||
|
|
178
|
+
(applied.status !== "applied" && applied.status !== "unchanged")
|
|
179
|
+
) {
|
|
180
|
+
return options;
|
|
181
|
+
}
|
|
182
|
+
const collectionName = applied?.receipt?.resources.find(
|
|
183
|
+
(resource) => resource.kind === "collection"
|
|
184
|
+
)?.id;
|
|
185
|
+
if (!collectionName) return null;
|
|
186
|
+
const loaded = await loadConfig(options.configPath);
|
|
187
|
+
const collection = loaded.ok
|
|
188
|
+
? loaded.value.collections.find((item) => item.name === collectionName)
|
|
189
|
+
: undefined;
|
|
190
|
+
if (!collection) return null;
|
|
191
|
+
return {
|
|
192
|
+
...options,
|
|
193
|
+
folder: collection.path,
|
|
194
|
+
name: options.name ?? collection.name,
|
|
195
|
+
exclude: options.exclude,
|
|
196
|
+
additiveStoreProjection: true,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function formatSetupProfileAdvisory(
|
|
201
|
+
result: ProjectProfileCommandResult,
|
|
202
|
+
options: { applyRequested?: boolean } = {}
|
|
203
|
+
): string {
|
|
204
|
+
if (result.status === "not_found" || result.status === "disabled") return "";
|
|
205
|
+
if (result.status === "valid" && result.profile) {
|
|
206
|
+
return [
|
|
207
|
+
`setup: project profile valid (${result.discovery.profile}; fingerprint=${result.profile.fingerprint})`,
|
|
208
|
+
"setup: preview profile changes with `gno profile diff`",
|
|
209
|
+
options.applyRequested
|
|
210
|
+
? "setup: applying the profile before lexical setup"
|
|
211
|
+
: "setup: rerun with `--apply-profile` to apply it before lexical setup",
|
|
212
|
+
].join("\n");
|
|
213
|
+
}
|
|
214
|
+
const firstError = result.diagnostics.find(
|
|
215
|
+
(diagnostic) => diagnostic.severity === "error"
|
|
216
|
+
);
|
|
217
|
+
return [
|
|
218
|
+
`setup: project profile ${result.status}; continuing without applying it`,
|
|
219
|
+
firstError
|
|
220
|
+
? `setup: ${firstError.code}: ${firstError.message}`
|
|
221
|
+
: "setup: run `gno profile check` for repair guidance",
|
|
222
|
+
].join("\n");
|
|
223
|
+
}
|
|
@@ -65,6 +65,8 @@ export interface SetupCommandOptions {
|
|
|
65
65
|
yes?: boolean;
|
|
66
66
|
json?: boolean;
|
|
67
67
|
quiet?: boolean;
|
|
68
|
+
/** Internal composition flag used after an additive project-profile apply. */
|
|
69
|
+
additiveStoreProjection?: boolean;
|
|
68
70
|
stdinIsTTY?: boolean;
|
|
69
71
|
stderrIsTTY?: boolean;
|
|
70
72
|
progress?: (stage: SetupStageName, receipt: FolderSetupReceipt) => void;
|
|
@@ -297,6 +299,7 @@ async function executeSetup(
|
|
|
297
299
|
name: options.name,
|
|
298
300
|
exclude: options.exclude,
|
|
299
301
|
secretRiskAuthorized: authorized,
|
|
302
|
+
additiveStoreProjection: options.additiveStoreProjection,
|
|
300
303
|
receiptWriter,
|
|
301
304
|
});
|
|
302
305
|
|