@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.
Files changed (56) hide show
  1. package/README.md +10 -4
  2. package/assets/skill/SKILL.md +29 -17
  3. package/browser-extension/artifacts/{gno-browser-clipper-v1.25.1.zip → gno-browser-clipper-v1.26.0.zip} +0 -0
  4. package/browser-extension/artifacts/gno-browser-clipper-v1.26.0.zip.sha256 +1 -0
  5. package/browser-extension/dist/manifest.json +1 -1
  6. package/package.json +1 -1
  7. package/spec/cli.md +146 -4
  8. package/spec/db/schema.sql +1 -1
  9. package/spec/output-schemas/project-profile-apply.schema.json +209 -0
  10. package/spec/output-schemas/project-profile-command.schema.json +160 -0
  11. package/spec/output-schemas/query-diagnose.schema.json +7 -1
  12. package/spec/output-schemas/setup-profile-result.schema.json +87 -0
  13. package/spec/project-profile.schema.json +301 -0
  14. package/src/cli/commands/collection/add.ts +39 -45
  15. package/src/cli/commands/collection/remove.ts +28 -28
  16. package/src/cli/commands/collection/rename.ts +55 -73
  17. package/src/cli/commands/context/add.ts +37 -26
  18. package/src/cli/commands/context/rm.ts +47 -20
  19. package/src/cli/commands/init.ts +55 -125
  20. package/src/cli/commands/models/use.ts +43 -38
  21. package/src/cli/commands/profile-apply.ts +334 -0
  22. package/src/cli/commands/profile.ts +409 -0
  23. package/src/cli/commands/setup-activation.ts +205 -54
  24. package/src/cli/commands/setup-profile.ts +223 -0
  25. package/src/cli/commands/setup.ts +3 -0
  26. package/src/cli/program.ts +110 -9
  27. package/src/config/index.ts +3 -0
  28. package/src/config/project-profile.ts +367 -0
  29. package/src/config/saver.ts +16 -7
  30. package/src/config/types.ts +42 -0
  31. package/src/core/config-mutation.ts +138 -76
  32. package/src/core/config-write-lock.ts +89 -0
  33. package/src/core/context-identity.ts +16 -0
  34. package/src/core/context-resolver.ts +2 -12
  35. package/src/core/folder-setup-planning.ts +6 -21
  36. package/src/core/folder-setup.ts +30 -2
  37. package/src/core/path-rules.ts +53 -0
  38. package/src/core/project-affinity-surface.ts +102 -7
  39. package/src/core/project-profile-apply-state.ts +268 -0
  40. package/src/core/project-profile-apply-validation.ts +95 -0
  41. package/src/core/project-profile-apply.ts +408 -0
  42. package/src/core/project-profile-canonical.ts +71 -0
  43. package/src/core/project-profile-diff.ts +302 -0
  44. package/src/core/project-profile-discovery.ts +519 -0
  45. package/src/core/project-profile-file.ts +37 -0
  46. package/src/core/project-profile-parser.ts +98 -0
  47. package/src/core/project-profile.ts +490 -0
  48. package/src/ingestion/walker.ts +85 -44
  49. package/src/llm/cache.ts +21 -0
  50. package/src/serve/config-sync.ts +2 -2
  51. package/src/serve/resident-runtime.ts +1 -0
  52. package/src/serve/routes/api.ts +1 -0
  53. package/src/store/migrations/021-multi-context-identity.ts +37 -0
  54. package/src/store/migrations/index.ts +2 -0
  55. package/src/store/sqlite/adapter.ts +83 -0
  56. package/browser-extension/artifacts/gno-browser-clipper-v1.25.1.zip.sha256 +0 -1
@@ -0,0 +1,160 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "gno://schemas/project-profile-command@1.0",
4
+ "title": "GNO Project Profile Read Command",
5
+ "description": "Deterministic, path-redacted result shared by profile check, show, and diff.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "schemaVersion",
10
+ "command",
11
+ "status",
12
+ "valid",
13
+ "discovery",
14
+ "profile",
15
+ "diff",
16
+ "diagnostics"
17
+ ],
18
+ "properties": {
19
+ "schemaVersion": { "const": "1.0" },
20
+ "command": { "enum": ["check", "show", "diff"] },
21
+ "status": { "enum": ["valid", "invalid", "not_found", "disabled"] },
22
+ "valid": { "type": "boolean" },
23
+ "discovery": { "$ref": "#/definitions/discovery" },
24
+ "profile": {
25
+ "oneOf": [{ "$ref": "#/definitions/profile" }, { "type": "null" }]
26
+ },
27
+ "diff": {
28
+ "oneOf": [{ "$ref": "#/definitions/diff" }, { "type": "null" }]
29
+ },
30
+ "diagnostics": {
31
+ "type": "array",
32
+ "items": { "$ref": "#/definitions/diagnostic" }
33
+ }
34
+ },
35
+ "definitions": {
36
+ "diagnostic": {
37
+ "type": "object",
38
+ "additionalProperties": false,
39
+ "required": ["code", "severity", "path", "message", "remediation"],
40
+ "properties": {
41
+ "code": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$" },
42
+ "severity": { "enum": ["error", "warning"] },
43
+ "path": { "type": "string" },
44
+ "message": { "type": "string", "minLength": 1 },
45
+ "remediation": { "type": "string", "minLength": 1 }
46
+ }
47
+ },
48
+ "discovery": {
49
+ "type": "object",
50
+ "additionalProperties": false,
51
+ "required": [
52
+ "status",
53
+ "source",
54
+ "boundary",
55
+ "profile",
56
+ "ambiguous",
57
+ "shadowedProfiles"
58
+ ],
59
+ "properties": {
60
+ "status": { "enum": ["found", "not_found", "disabled", "error"] },
61
+ "source": { "enum": ["cwd", "override", "remote"] },
62
+ "boundary": {
63
+ "enum": ["repository", "filesystem", "explicit", "remote"]
64
+ },
65
+ "profile": {
66
+ "type": ["string", "null"],
67
+ "enum": [".gno/index.yml", null]
68
+ },
69
+ "ambiguous": { "type": "boolean" },
70
+ "shadowedProfiles": { "type": "integer", "minimum": 0 }
71
+ }
72
+ },
73
+ "profile": {
74
+ "type": "object",
75
+ "additionalProperties": false,
76
+ "required": ["fingerprint", "desiredState"],
77
+ "properties": {
78
+ "fingerprint": {
79
+ "type": "string",
80
+ "pattern": "^[a-f0-9]{64}$"
81
+ },
82
+ "desiredState": {
83
+ "oneOf": [{ "type": "object" }, { "type": "null" }]
84
+ }
85
+ }
86
+ },
87
+ "change": {
88
+ "type": "object",
89
+ "additionalProperties": false,
90
+ "required": ["action", "field", "destructive", "summary"],
91
+ "properties": {
92
+ "action": { "enum": ["add", "update", "repair", "review"] },
93
+ "field": { "type": "string", "minLength": 1 },
94
+ "destructive": { "type": "boolean" },
95
+ "summary": { "type": "string", "minLength": 1 }
96
+ }
97
+ },
98
+ "staleMapping": {
99
+ "type": "object",
100
+ "additionalProperties": false,
101
+ "required": ["collection", "reason", "choices"],
102
+ "properties": {
103
+ "collection": { "type": "string", "minLength": 1 },
104
+ "reason": { "enum": ["name_changed", "root_changed"] },
105
+ "choices": {
106
+ "type": "array",
107
+ "minItems": 2,
108
+ "maxItems": 2,
109
+ "items": { "enum": ["repair", "remove_explicitly"] }
110
+ }
111
+ }
112
+ },
113
+ "diff": {
114
+ "type": "object",
115
+ "additionalProperties": false,
116
+ "required": ["status", "changes", "staleMappings"],
117
+ "properties": {
118
+ "status": { "enum": ["in_sync", "changes_required"] },
119
+ "changes": {
120
+ "type": "array",
121
+ "items": { "$ref": "#/definitions/change" }
122
+ },
123
+ "staleMappings": {
124
+ "type": "array",
125
+ "items": { "$ref": "#/definitions/staleMapping" }
126
+ }
127
+ }
128
+ }
129
+ },
130
+ "allOf": [
131
+ {
132
+ "if": {
133
+ "properties": { "valid": { "const": true } },
134
+ "required": ["valid"]
135
+ },
136
+ "then": {
137
+ "properties": {
138
+ "status": { "const": "valid" },
139
+ "profile": { "$ref": "#/definitions/profile" }
140
+ }
141
+ }
142
+ },
143
+ {
144
+ "if": {
145
+ "properties": { "command": { "const": "diff" } },
146
+ "required": ["command"]
147
+ },
148
+ "then": {
149
+ "properties": {
150
+ "diff": {
151
+ "oneOf": [{ "$ref": "#/definitions/diff" }, { "type": "null" }]
152
+ }
153
+ }
154
+ },
155
+ "else": {
156
+ "properties": { "diff": { "type": "null" } }
157
+ }
158
+ }
159
+ ]
160
+ }
@@ -149,7 +149,13 @@
149
149
  },
150
150
  "source": {
151
151
  "type": ["string", "null"],
152
- "enum": ["cli_cwd", "cli_explicit", "cli_worktree", null]
152
+ "enum": [
153
+ "cli_cwd",
154
+ "cli_explicit",
155
+ "cli_worktree",
156
+ "project_profile",
157
+ null
158
+ ]
153
159
  }
154
160
  },
155
161
  "additionalProperties": false
@@ -0,0 +1,87 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "gno://schemas/setup-profile-result@1.0",
4
+ "title": "GNO Setup Profile Result",
5
+ "description": "Closed opt-in project-profile apply composition around verified setup and optional connectors.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schemaVersion", "status", "profile", "setup", "connectors"],
9
+ "properties": {
10
+ "schemaVersion": { "const": "1.0" },
11
+ "status": {
12
+ "enum": ["completed", "completed_with_actions", "failed"]
13
+ },
14
+ "profile": {
15
+ "type": "object",
16
+ "additionalProperties": false,
17
+ "required": ["check", "apply"],
18
+ "properties": {
19
+ "check": {
20
+ "allOf": [
21
+ { "$ref": "gno://schemas/project-profile-command@1.0" },
22
+ {
23
+ "type": "object",
24
+ "properties": { "command": { "const": "check" } },
25
+ "required": ["command"]
26
+ }
27
+ ]
28
+ },
29
+ "apply": {
30
+ "oneOf": [
31
+ { "$ref": "gno://schemas/project-profile-apply@1.0" },
32
+ { "type": "null" }
33
+ ]
34
+ }
35
+ }
36
+ },
37
+ "setup": { "$ref": "gno://schemas/setup-command-result@1.0" },
38
+ "connectors": {
39
+ "$ref": "gno://schemas/setup-activation-result@1.0#/properties/connectors"
40
+ }
41
+ },
42
+ "allOf": [
43
+ {
44
+ "if": {
45
+ "properties": { "status": { "const": "completed" } },
46
+ "required": ["status"]
47
+ },
48
+ "then": {
49
+ "properties": {
50
+ "profile": {
51
+ "type": "object",
52
+ "properties": {
53
+ "check": {
54
+ "type": "object",
55
+ "properties": { "status": { "const": "valid" } }
56
+ },
57
+ "apply": {
58
+ "type": "object",
59
+ "properties": {
60
+ "status": { "enum": ["applied", "unchanged"] }
61
+ }
62
+ }
63
+ }
64
+ },
65
+ "setup": {
66
+ "type": "object",
67
+ "properties": { "status": { "const": "completed" } }
68
+ }
69
+ }
70
+ }
71
+ },
72
+ {
73
+ "if": {
74
+ "properties": { "status": { "const": "failed" } },
75
+ "required": ["status"]
76
+ },
77
+ "then": {
78
+ "properties": {
79
+ "setup": {
80
+ "type": "object",
81
+ "properties": { "status": { "const": "failed" } }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ ]
87
+ }
@@ -0,0 +1,301 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://gno.sh/schemas/project-profile-1.0.json",
4
+ "title": "GNO project retrieval profile",
5
+ "description": "Portable, declarative retrieval state for a single project collection.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schemaVersion", "collection"],
9
+ "properties": {
10
+ "schemaVersion": {
11
+ "const": "1.0"
12
+ },
13
+ "collection": {
14
+ "$ref": "#/definitions/collection"
15
+ },
16
+ "contexts": {
17
+ "type": "array",
18
+ "maxItems": 64,
19
+ "uniqueItems": true,
20
+ "items": {
21
+ "$ref": "#/definitions/context"
22
+ },
23
+ "default": []
24
+ },
25
+ "contentTypes": {
26
+ "type": "object",
27
+ "maxProperties": 64,
28
+ "propertyNames": {
29
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$"
30
+ },
31
+ "additionalProperties": {
32
+ "$ref": "#/definitions/contentType"
33
+ },
34
+ "default": {}
35
+ },
36
+ "affinityDefaults": {
37
+ "$ref": "#/definitions/affinityDefaults"
38
+ },
39
+ "recommendedCapabilities": {
40
+ "type": "array",
41
+ "maxItems": 32,
42
+ "uniqueItems": true,
43
+ "items": {
44
+ "type": "string",
45
+ "pattern": "^[a-z][a-z0-9._-]{0,63}$"
46
+ },
47
+ "default": []
48
+ }
49
+ },
50
+ "definitions": {
51
+ "portableRule": {
52
+ "type": "string",
53
+ "minLength": 1,
54
+ "maxLength": 512,
55
+ "allOf": [
56
+ {
57
+ "not": {
58
+ "type": "string",
59
+ "pattern": "^(?:[/\\\\]|[A-Za-z]:|~)"
60
+ }
61
+ },
62
+ {
63
+ "not": {
64
+ "type": "string",
65
+ "pattern": "(?:^|[\\\\/])\\.\\.(?:[\\\\/]|$)"
66
+ }
67
+ },
68
+ {
69
+ "not": {
70
+ "type": "string",
71
+ "pattern": "[{}]"
72
+ }
73
+ },
74
+ {
75
+ "not": {
76
+ "type": "string",
77
+ "pattern": "^!"
78
+ }
79
+ },
80
+ {
81
+ "not": {
82
+ "type": "string",
83
+ "pattern": "[<>:\"|\\u0000-\\u001f]"
84
+ }
85
+ },
86
+ {
87
+ "not": {
88
+ "type": "string",
89
+ "pattern": "(?:^|[\\\\/])(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9])(?:\\.[^\\\\/]*)?(?:[\\\\/]|$)"
90
+ }
91
+ },
92
+ {
93
+ "not": {
94
+ "type": "string",
95
+ "pattern": "(?:^|[\\\\/])(?:[^.\\\\/][^\\\\/]*|\\.[^\\\\/]+)[. ](?:[\\\\/]|$)"
96
+ }
97
+ },
98
+ {
99
+ "not": {
100
+ "type": "string",
101
+ "pattern": "(?:\\$\\{|\\$[A-Za-z_]|%[A-Za-z_][A-Za-z0-9_]*%)"
102
+ }
103
+ },
104
+ {
105
+ "not": {
106
+ "type": "string",
107
+ "pattern": "\\u0000"
108
+ }
109
+ }
110
+ ]
111
+ },
112
+ "portablePath": {
113
+ "allOf": [
114
+ {
115
+ "$ref": "#/definitions/portableRule"
116
+ },
117
+ {
118
+ "not": {
119
+ "type": "string",
120
+ "pattern": "[*?\\[\\]{}]"
121
+ }
122
+ },
123
+ {
124
+ "not": {
125
+ "type": "string",
126
+ "pattern": "(?:^|[\\\\/])\\.[gG][nN][oO](?:[\\\\/]|$)"
127
+ }
128
+ },
129
+ {
130
+ "not": {
131
+ "type": "string",
132
+ "pattern": "\\.(?:[dD][bB]|[sS][qQ][lL][iI][tT][eE](?:3)?|[gG][gG][uU][fF]|[lL][oO][cC][kK])$"
133
+ }
134
+ }
135
+ ]
136
+ },
137
+ "portableInclude": {
138
+ "allOf": [
139
+ {
140
+ "$ref": "#/definitions/portableRule"
141
+ },
142
+ {
143
+ "not": {
144
+ "type": "string",
145
+ "pattern": "(?:^|[\\\\/])\\.[gG][nN][oO](?:[\\\\/]|$)|\\.(?:[dD][bB]|[sS][qQ][lL][iI][tT][eE](?:3)?|[gG][gG][uU][fF]|[lL][oO][cC][kK])$"
146
+ }
147
+ }
148
+ ]
149
+ },
150
+ "collection": {
151
+ "type": "object",
152
+ "additionalProperties": false,
153
+ "required": ["name"],
154
+ "properties": {
155
+ "name": {
156
+ "type": "string",
157
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$"
158
+ },
159
+ "root": {
160
+ "$ref": "#/definitions/portablePath",
161
+ "default": "."
162
+ },
163
+ "include": {
164
+ "type": "array",
165
+ "minItems": 1,
166
+ "maxItems": 128,
167
+ "uniqueItems": true,
168
+ "items": {
169
+ "$ref": "#/definitions/portableInclude"
170
+ },
171
+ "default": ["**/*"]
172
+ },
173
+ "exclude": {
174
+ "type": "array",
175
+ "maxItems": 128,
176
+ "uniqueItems": true,
177
+ "items": {
178
+ "$ref": "#/definitions/portableRule"
179
+ },
180
+ "default": []
181
+ },
182
+ "languageHint": {
183
+ "type": "string",
184
+ "pattern": "^[A-Za-z]{2,3}(?:-[A-Za-z]{2}|-[A-Za-z]{4})?$"
185
+ },
186
+ "modelPreset": {
187
+ "type": "string",
188
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$"
189
+ }
190
+ }
191
+ },
192
+ "inlineContext": {
193
+ "type": "object",
194
+ "additionalProperties": false,
195
+ "required": ["text"],
196
+ "properties": {
197
+ "text": {
198
+ "type": "string",
199
+ "minLength": 1,
200
+ "maxLength": 65536
201
+ }
202
+ }
203
+ },
204
+ "fileContext": {
205
+ "type": "object",
206
+ "additionalProperties": false,
207
+ "required": ["file"],
208
+ "properties": {
209
+ "file": {
210
+ "allOf": [
211
+ {
212
+ "$ref": "#/definitions/portablePath"
213
+ },
214
+ {
215
+ "not": {
216
+ "type": "string",
217
+ "pattern": "(?:^|[\\\\/])(?:\\.[eE][nN][vV](?:\\..*)?|[cC][rR][eE][dD][eE][nN][tT][iI][aA][lL][sS]?(?:\\..*)?|[iI][dD]_(?:[rR][sS][aA]|[dD][sS][aA]|[eE][cC][dD][sS][aA]|[eE][dD]25519)(?:\\..*)?|[sS][eE][cC][rR][eE][tT][sS]?(?:\\..*)?|[^\\\\/]+\\.(?:[kK][eE][yY]|[pP][eE][mM]|[pP]12|[pP][fF][xX]))$"
218
+ }
219
+ }
220
+ ]
221
+ }
222
+ }
223
+ },
224
+ "context": {
225
+ "oneOf": [
226
+ {
227
+ "$ref": "#/definitions/inlineContext"
228
+ },
229
+ {
230
+ "$ref": "#/definitions/fileContext"
231
+ }
232
+ ]
233
+ },
234
+ "contentType": {
235
+ "type": "object",
236
+ "additionalProperties": false,
237
+ "required": ["prefixes", "preset"],
238
+ "properties": {
239
+ "prefixes": {
240
+ "type": "array",
241
+ "minItems": 1,
242
+ "maxItems": 64,
243
+ "uniqueItems": true,
244
+ "items": {
245
+ "$ref": "#/definitions/portablePath"
246
+ }
247
+ },
248
+ "preset": {
249
+ "enum": [
250
+ "blank",
251
+ "project-note",
252
+ "research-note",
253
+ "decision-note",
254
+ "prompt-pattern",
255
+ "source-summary",
256
+ "idea-original",
257
+ "person",
258
+ "company-project",
259
+ "meeting"
260
+ ]
261
+ },
262
+ "graphHints": {
263
+ "type": "array",
264
+ "maxItems": 16,
265
+ "uniqueItems": true,
266
+ "items": {
267
+ "type": "string",
268
+ "minLength": 1,
269
+ "maxLength": 64
270
+ }
271
+ },
272
+ "searchBoost": {
273
+ "type": "number"
274
+ },
275
+ "temporal": {
276
+ "type": "boolean"
277
+ }
278
+ }
279
+ },
280
+ "affinityDefaults": {
281
+ "type": "object",
282
+ "additionalProperties": false,
283
+ "properties": {
284
+ "enabled": {
285
+ "type": "boolean",
286
+ "default": true
287
+ },
288
+ "contribution": {
289
+ "type": "number",
290
+ "minimum": 0,
291
+ "maximum": 0.03,
292
+ "default": 0.03
293
+ }
294
+ },
295
+ "default": {
296
+ "enabled": true,
297
+ "contribution": 0.03
298
+ }
299
+ }
300
+ }
301
+ }
@@ -3,12 +3,8 @@
3
3
  */
4
4
 
5
5
  import { addCollection } from "../../../collection";
6
- import {
7
- loadConfig,
8
- pathExists,
9
- saveConfig,
10
- toAbsolutePath,
11
- } from "../../../config";
6
+ import { pathExists, toAbsolutePath } from "../../../config";
7
+ import { applyConfigFileChange } from "../../../core/config-mutation";
12
8
  import { CliError } from "../../errors";
13
9
 
14
10
  interface AddOptions {
@@ -18,6 +14,7 @@ interface AddOptions {
18
14
  include?: string;
19
15
  exclude?: string;
20
16
  update?: string;
17
+ configPath?: string;
21
18
  }
22
19
 
23
20
  export async function collectionAdd(
@@ -36,52 +33,49 @@ export async function collectionAdd(
36
33
  throw new CliError("VALIDATION", `Path does not exist: ${absolutePath}`);
37
34
  }
38
35
 
39
- // Load config
40
- const configResult = await loadConfig();
41
- if (!configResult.ok) {
42
- throw new CliError(
43
- "RUNTIME",
44
- `Failed to load config: ${configResult.error.message}`
45
- );
46
- }
47
-
48
- // Add collection using shared module
49
- const result = await addCollection(configResult.value, {
50
- path,
51
- name: options.name,
52
- pattern: options.pattern,
53
- include: options.include,
54
- exclude: options.exclude,
55
- models: options.embedModel
56
- ? {
57
- embed: options.embedModel,
58
- }
59
- : undefined,
60
- updateCmd: options.update,
61
- });
36
+ const mutation = await applyConfigFileChange(
37
+ { configPath: options.configPath },
38
+ async (config) => {
39
+ const result = await addCollection(config, {
40
+ path,
41
+ name: options.name!,
42
+ pattern: options.pattern,
43
+ include: options.include,
44
+ exclude: options.exclude,
45
+ models: options.embedModel
46
+ ? {
47
+ embed: options.embedModel,
48
+ }
49
+ : undefined,
50
+ updateCmd: options.update,
51
+ });
52
+ return result.ok
53
+ ? {
54
+ ok: true as const,
55
+ config: result.config,
56
+ value: result.collection,
57
+ }
58
+ : {
59
+ ok: false as const,
60
+ error: result.message,
61
+ code: result.code,
62
+ };
63
+ }
64
+ );
62
65
 
63
- if (!result.ok) {
66
+ if (!mutation.ok) {
64
67
  // Map collection error codes to CLI error codes
65
68
  const cliCode =
66
- result.code === "VALIDATION" ||
67
- result.code === "PATH_NOT_FOUND" ||
68
- result.code === "DUPLICATE"
69
+ mutation.code === "VALIDATION" ||
70
+ mutation.code === "PATH_NOT_FOUND" ||
71
+ mutation.code === "DUPLICATE"
69
72
  ? "VALIDATION"
70
73
  : "RUNTIME";
71
- throw new CliError(cliCode, result.message);
72
- }
73
-
74
- // Save config
75
- const saveResult = await saveConfig(result.config);
76
- if (!saveResult.ok) {
77
- throw new CliError(
78
- "RUNTIME",
79
- `Failed to save config: ${saveResult.error.message}`
80
- );
74
+ throw new CliError(cliCode, mutation.error);
81
75
  }
82
76
 
83
77
  process.stdout.write(
84
- `Collection "${result.collection.name}" added successfully\n`
78
+ `Collection "${mutation.value?.name}" added successfully\n`
85
79
  );
86
- process.stdout.write(`Path: ${result.collection.path}\n`);
80
+ process.stdout.write(`Path: ${mutation.value?.path}\n`);
87
81
  }