@aiwg/cli 2026.9.15 → 2026.9.16

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 (33) hide show
  1. package/agentic/code/providers/capability-matrix.yaml +42 -0
  2. package/agentic/code/providers/model-capabilities.v1.json +119 -34
  3. package/agentic/code/providers/model-catalog.v1.json +259 -56
  4. package/dist/src/cli/handlers/sessions.js +159 -45
  5. package/dist/src/cli/handlers/use.js +20 -1
  6. package/dist/src/cli/scope-resolver.js +13 -0
  7. package/dist/src/cli/services/deployment-verification.js +33 -2
  8. package/dist/src/config/aiwg-config.js +39 -0
  9. package/dist/src/config/user-registry.js +9 -0
  10. package/dist/src/extensions/manifest.js +1 -0
  11. package/dist/src/models/model-capabilities.v1.json +119 -34
  12. package/dist/src/models/model-catalog.v1.json +259 -56
  13. package/dist/src/models/model-discovery.js +7 -0
  14. package/dist/src/models/provider-policy.js +1 -1
  15. package/dist/src/plugin/skill-command-translator.js +1 -0
  16. package/dist/src/providers/capability-matrix.yaml +42 -0
  17. package/dist/src/providers/grokbot-paths.js +103 -0
  18. package/dist/src/providers/provider-definitions.js +85 -1
  19. package/dist/src/providers/provider-inventory.js +1 -0
  20. package/dist/src/sessions/adapters/grokbot.js +49 -0
  21. package/dist/src/sessions/adapters/hermes.js +17 -9
  22. package/dist/src/sessions/adapters/opencode.js +12 -1
  23. package/dist/src/sessions/contracts.js +1 -1
  24. package/dist/src/sessions/export-plan.js +130 -4
  25. package/dist/src/sessions/fortemi-export-mapping.js +10 -6
  26. package/dist/src/sessions/fortemi-shard-blobs.js +78 -0
  27. package/dist/src/sessions/index.js +2 -0
  28. package/dist/src/sessions/workspace-discovery.js +1 -1
  29. package/dist/src/skills/deployer.js +17 -0
  30. package/dist/src/smiths/skillsmith/collision-detector.js +1 -0
  31. package/package.json +1 -1
  32. package/tools/agents/deploy-agents.mjs +3 -2
  33. package/tools/agents/providers/grokbot.mjs +285 -0
@@ -6,59 +6,150 @@
6
6
  "providers": {
7
7
  "antigravity": {
8
8
  "roles": {
9
- "reasoning": { "id": "configured/reasoning", "status": "unverified", "observed": false },
10
- "coding": { "id": "configured/coding", "status": "unverified", "observed": false },
11
- "efficiency": { "id": "configured/efficiency", "status": "unverified", "observed": false }
9
+ "reasoning": {
10
+ "id": "configured/reasoning",
11
+ "status": "unverified",
12
+ "observed": false
13
+ },
14
+ "coding": {
15
+ "id": "configured/coding",
16
+ "status": "unverified",
17
+ "observed": false
18
+ },
19
+ "efficiency": {
20
+ "id": "configured/efficiency",
21
+ "status": "unverified",
22
+ "observed": false
23
+ }
12
24
  },
13
- "sourceUrl": "https://antigravity.google/docs/cli/overview/", "verifiedAt": "2026-09-04"
25
+ "sourceUrl": "https://antigravity.google/docs/cli/overview/",
26
+ "verifiedAt": "2026-09-04"
14
27
  },
15
28
  "claude": {
16
29
  "roles": {
17
- "reasoning": { "id": "claude-opus-4-7", "status": "active", "observed": false },
18
- "coding": { "id": "claude-sonnet-4-6", "status": "active", "observed": false },
19
- "efficiency": { "id": "claude-haiku-4-5", "status": "active", "observed": false }
30
+ "reasoning": {
31
+ "id": "claude-opus-4-7",
32
+ "status": "active",
33
+ "observed": false
34
+ },
35
+ "coding": {
36
+ "id": "claude-sonnet-4-6",
37
+ "status": "active",
38
+ "observed": false
39
+ },
40
+ "efficiency": {
41
+ "id": "claude-haiku-4-5",
42
+ "status": "active",
43
+ "observed": false
44
+ }
20
45
  },
21
- "sourceUrl": "https://docs.anthropic.com/en/docs/about-claude/models/overview", "verifiedAt": "2026-07-20"
46
+ "sourceUrl": "https://docs.anthropic.com/en/docs/about-claude/models/overview",
47
+ "verifiedAt": "2026-07-20"
22
48
  },
23
49
  "codex": {
24
50
  "roles": {
25
- "reasoning": { "id": "gpt-5.4", "status": "active", "observed": true },
26
- "coding": { "id": "gpt-5.5", "status": "active", "observed": true },
27
- "efficiency": { "id": "gpt-5.4-mini", "status": "active", "observed": true }
51
+ "reasoning": {
52
+ "id": "gpt-5.4",
53
+ "status": "active",
54
+ "observed": true
55
+ },
56
+ "coding": {
57
+ "id": "gpt-5.5",
58
+ "status": "active",
59
+ "observed": true
60
+ },
61
+ "efficiency": {
62
+ "id": "gpt-5.4-mini",
63
+ "status": "active",
64
+ "observed": true
65
+ }
28
66
  },
29
- "sourceUrl": "https://learn.chatgpt.com/docs/agent-configuration/subagents", "verifiedAt": "2026-07-20"
67
+ "sourceUrl": "https://learn.chatgpt.com/docs/agent-configuration/subagents",
68
+ "verifiedAt": "2026-07-20"
30
69
  },
31
70
  "copilot": {
32
71
  "roles": {
33
- "reasoning": { "id": "claude-opus-4.6", "status": "unverified", "observed": false },
34
- "coding": { "id": "claude-sonnet-4.6", "status": "unverified", "observed": false },
35
- "efficiency": { "id": "gpt-5.1-codex-mini", "status": "unverified", "observed": false }
72
+ "reasoning": {
73
+ "id": "claude-opus-4.6",
74
+ "status": "unverified",
75
+ "observed": false
76
+ },
77
+ "coding": {
78
+ "id": "claude-sonnet-4.6",
79
+ "status": "unverified",
80
+ "observed": false
81
+ },
82
+ "efficiency": {
83
+ "id": "gpt-5.1-codex-mini",
84
+ "status": "unverified",
85
+ "observed": false
86
+ }
36
87
  },
37
- "sourceUrl": "https://docs.github.com/en/copilot/reference/ai-models/supported-models", "verifiedAt": "2026-07-20"
88
+ "sourceUrl": "https://docs.github.com/en/copilot/reference/ai-models/supported-models",
89
+ "verifiedAt": "2026-07-20"
38
90
  },
39
91
  "cursor": {
40
92
  "roles": {
41
- "reasoning": { "id": "claude-4.6-opus-high-thinking", "status": "unverified", "observed": false },
42
- "coding": { "id": "claude-4.6-sonnet", "status": "unverified", "observed": false },
43
- "efficiency": { "id": "auto", "status": "unverified", "observed": false }
93
+ "reasoning": {
94
+ "id": "claude-4.6-opus-high-thinking",
95
+ "status": "unverified",
96
+ "observed": false
97
+ },
98
+ "coding": {
99
+ "id": "claude-4.6-sonnet",
100
+ "status": "unverified",
101
+ "observed": false
102
+ },
103
+ "efficiency": {
104
+ "id": "auto",
105
+ "status": "unverified",
106
+ "observed": false
107
+ }
44
108
  },
45
- "sourceUrl": "https://cursor.com/docs/models", "verifiedAt": "2026-07-20"
109
+ "sourceUrl": "https://cursor.com/docs/models",
110
+ "verifiedAt": "2026-07-20"
46
111
  },
47
112
  "factory": {
48
113
  "roles": {
49
- "reasoning": { "id": "heavy", "status": "active", "observed": false },
50
- "coding": { "id": "medium", "status": "active", "observed": false },
51
- "efficiency": { "id": "light", "status": "active", "observed": false }
114
+ "reasoning": {
115
+ "id": "heavy",
116
+ "status": "active",
117
+ "observed": false
118
+ },
119
+ "coding": {
120
+ "id": "medium",
121
+ "status": "active",
122
+ "observed": false
123
+ },
124
+ "efficiency": {
125
+ "id": "light",
126
+ "status": "active",
127
+ "observed": false
128
+ }
52
129
  },
53
- "sourceUrl": "https://docs.factory.ai/cli/user-guides/choosing-your-model", "verifiedAt": "2026-07-20"
130
+ "sourceUrl": "https://docs.factory.ai/cli/user-guides/choosing-your-model",
131
+ "verifiedAt": "2026-07-20"
54
132
  },
55
133
  "opencode": {
56
134
  "roles": {
57
- "reasoning": { "id": "anthropic/claude-opus-4-7", "status": "unverified", "observed": false },
58
- "coding": { "id": "anthropic/claude-sonnet-4-6", "status": "unverified", "observed": false },
59
- "efficiency": { "id": "anthropic/claude-haiku-4-5", "status": "unverified", "observed": false }
135
+ "reasoning": {
136
+ "id": "anthropic/claude-opus-4-7",
137
+ "status": "unverified",
138
+ "observed": false
139
+ },
140
+ "coding": {
141
+ "id": "anthropic/claude-sonnet-4-6",
142
+ "status": "unverified",
143
+ "observed": false
144
+ },
145
+ "efficiency": {
146
+ "id": "anthropic/claude-haiku-4-5",
147
+ "status": "unverified",
148
+ "observed": false
149
+ }
60
150
  },
61
- "sourceUrl": "https://opencode.ai/docs/models", "verifiedAt": "2026-07-20"
151
+ "sourceUrl": "https://opencode.ai/docs/models",
152
+ "verifiedAt": "2026-07-20"
62
153
  },
63
154
  "omp": {
64
155
  "roles": {
@@ -83,59 +174,171 @@
83
174
  },
84
175
  "pi": {
85
176
  "roles": {
86
- "reasoning": { "id": "configured/reasoning", "status": "unverified", "observed": false },
87
- "coding": { "id": "configured/coding", "status": "unverified", "observed": false },
88
- "efficiency": { "id": "configured/efficiency", "status": "unverified", "observed": false }
177
+ "reasoning": {
178
+ "id": "configured/reasoning",
179
+ "status": "unverified",
180
+ "observed": false
181
+ },
182
+ "coding": {
183
+ "id": "configured/coding",
184
+ "status": "unverified",
185
+ "observed": false
186
+ },
187
+ "efficiency": {
188
+ "id": "configured/efficiency",
189
+ "status": "unverified",
190
+ "observed": false
191
+ }
89
192
  },
90
- "sourceUrl": "https://github.com/earendil-works/pi/tree/main/packages/coding-agent#providers--models", "verifiedAt": "2026-09-04"
193
+ "sourceUrl": "https://github.com/earendil-works/pi/tree/main/packages/coding-agent#providers--models",
194
+ "verifiedAt": "2026-09-04"
91
195
  },
92
196
  "deepseek-harness": {
93
197
  "roles": {
94
- "reasoning": { "id": "configured/reasoning", "status": "unverified", "observed": false },
95
- "coding": { "id": "configured/coding", "status": "unverified", "observed": false },
96
- "efficiency": { "id": "configured/efficiency", "status": "unverified", "observed": false }
198
+ "reasoning": {
199
+ "id": "configured/reasoning",
200
+ "status": "unverified",
201
+ "observed": false
202
+ },
203
+ "coding": {
204
+ "id": "configured/coding",
205
+ "status": "unverified",
206
+ "observed": false
207
+ },
208
+ "efficiency": {
209
+ "id": "configured/efficiency",
210
+ "status": "unverified",
211
+ "observed": false
212
+ }
97
213
  },
98
- "sourceUrl": "https://github.com/deepseek-ai/deepseek-harness", "verifiedAt": "2026-09-05"
214
+ "sourceUrl": "https://github.com/deepseek-ai/deepseek-harness",
215
+ "verifiedAt": "2026-09-05"
99
216
  },
100
217
  "warp": {
101
218
  "roles": {
102
- "reasoning": { "id": "profile-selected", "status": "unverified", "observed": false },
103
- "coding": { "id": "profile-selected", "status": "unverified", "observed": false },
104
- "efficiency": { "id": "profile-selected", "status": "unverified", "observed": false }
219
+ "reasoning": {
220
+ "id": "profile-selected",
221
+ "status": "unverified",
222
+ "observed": false
223
+ },
224
+ "coding": {
225
+ "id": "profile-selected",
226
+ "status": "unverified",
227
+ "observed": false
228
+ },
229
+ "efficiency": {
230
+ "id": "profile-selected",
231
+ "status": "unverified",
232
+ "observed": false
233
+ }
105
234
  },
106
- "sourceUrl": "https://docs.warp.dev/agent-platform/capabilities/agent-profiles-permissions", "verifiedAt": "2026-07-20"
235
+ "sourceUrl": "https://docs.warp.dev/agent-platform/capabilities/agent-profiles-permissions",
236
+ "verifiedAt": "2026-07-20"
107
237
  },
108
238
  "windsurf": {
109
239
  "roles": {
110
- "reasoning": { "id": "inherited", "status": "unverified", "observed": false },
111
- "coding": { "id": "inherited", "status": "unverified", "observed": false },
112
- "efficiency": { "id": "inherited", "status": "unverified", "observed": false }
240
+ "reasoning": {
241
+ "id": "inherited",
242
+ "status": "unverified",
243
+ "observed": false
244
+ },
245
+ "coding": {
246
+ "id": "inherited",
247
+ "status": "unverified",
248
+ "observed": false
249
+ },
250
+ "efficiency": {
251
+ "id": "inherited",
252
+ "status": "unverified",
253
+ "observed": false
254
+ }
113
255
  },
114
- "sourceUrl": "https://docs.devin.ai/desktop/cascade/models", "verifiedAt": "2026-07-20"
256
+ "sourceUrl": "https://docs.devin.ai/desktop/cascade/models",
257
+ "verifiedAt": "2026-07-20"
115
258
  },
116
259
  "openclaw": {
117
260
  "roles": {
118
- "reasoning": { "id": "configured/reasoning", "status": "unverified", "observed": false },
119
- "coding": { "id": "configured/coding", "status": "unverified", "observed": false },
120
- "efficiency": { "id": "configured/efficiency", "status": "unverified", "observed": false }
261
+ "reasoning": {
262
+ "id": "configured/reasoning",
263
+ "status": "unverified",
264
+ "observed": false
265
+ },
266
+ "coding": {
267
+ "id": "configured/coding",
268
+ "status": "unverified",
269
+ "observed": false
270
+ },
271
+ "efficiency": {
272
+ "id": "configured/efficiency",
273
+ "status": "unverified",
274
+ "observed": false
275
+ }
121
276
  },
122
- "sourceUrl": "https://docs.openclaw.ai/tools/subagents", "verifiedAt": "2026-07-20"
277
+ "sourceUrl": "https://docs.openclaw.ai/tools/subagents",
278
+ "verifiedAt": "2026-07-20"
279
+ },
280
+ "grokbot": {
281
+ "roles": {
282
+ "reasoning": {
283
+ "id": "global-delegation-model",
284
+ "status": "unverified",
285
+ "observed": false
286
+ },
287
+ "coding": {
288
+ "id": "global-delegation-model",
289
+ "status": "unverified",
290
+ "observed": false
291
+ },
292
+ "efficiency": {
293
+ "id": "global-delegation-model",
294
+ "status": "unverified",
295
+ "observed": false
296
+ }
297
+ },
298
+ "sourceUrl": "https://github.com/jmagly/aiwg/blob/main/docs/architecture/adr-grokbot-provider-target.md",
299
+ "verifiedAt": "2026-09-15"
123
300
  },
124
301
  "hermes": {
125
302
  "roles": {
126
- "reasoning": { "id": "global-delegation-model", "status": "unverified", "observed": false },
127
- "coding": { "id": "global-delegation-model", "status": "unverified", "observed": false },
128
- "efficiency": { "id": "global-delegation-model", "status": "unverified", "observed": false }
303
+ "reasoning": {
304
+ "id": "global-delegation-model",
305
+ "status": "unverified",
306
+ "observed": false
307
+ },
308
+ "coding": {
309
+ "id": "global-delegation-model",
310
+ "status": "unverified",
311
+ "observed": false
312
+ },
313
+ "efficiency": {
314
+ "id": "global-delegation-model",
315
+ "status": "unverified",
316
+ "observed": false
317
+ }
129
318
  },
130
- "sourceUrl": "https://hermes-agent.nousresearch.com/docs/user-guide/features/delegation", "verifiedAt": "2026-07-20"
319
+ "sourceUrl": "https://hermes-agent.nousresearch.com/docs/user-guide/features/delegation",
320
+ "verifiedAt": "2026-07-20"
131
321
  },
132
322
  "openhuman": {
133
323
  "roles": {
134
- "reasoning": { "id": "Hint(reasoning)", "status": "active", "observed": false },
135
- "coding": { "id": "Hint(coding)", "status": "active", "observed": false },
136
- "efficiency": { "id": "Hint(efficiency)", "status": "active", "observed": false }
324
+ "reasoning": {
325
+ "id": "Hint(reasoning)",
326
+ "status": "active",
327
+ "observed": false
328
+ },
329
+ "coding": {
330
+ "id": "Hint(coding)",
331
+ "status": "active",
332
+ "observed": false
333
+ },
334
+ "efficiency": {
335
+ "id": "Hint(efficiency)",
336
+ "status": "active",
337
+ "observed": false
338
+ }
137
339
  },
138
- "sourceUrl": "https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/harness/definition.rs", "verifiedAt": "2026-07-20"
340
+ "sourceUrl": "https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/harness/definition.rs",
341
+ "verifiedAt": "2026-07-20"
139
342
  }
140
343
  }
141
344
  }
@@ -39,6 +39,13 @@ export const PROVIDER_DISCOVERY_DECISIONS = {
39
39
  reason: 'Droid exposes model selection through policy and interactive surfaces, but no documented non-interactive model-list command.',
40
40
  documentation: 'https://docs.factory.ai/cli/configuration/models',
41
41
  },
42
+ grokbot: {
43
+ provider: 'grokbot',
44
+ status: 'unsupported',
45
+ interface: null,
46
+ reason: 'Grok Bot is a desktop multi-agent runtime with no verified non-interactive model-list command; AIWG does not invent xAI/Grok API enumeration as Grok Bot entitlement.',
47
+ documentation: 'https://github.com/jmagly/aiwg/blob/main/docs/architecture/adr-grokbot-provider-target.md',
48
+ },
42
49
  hermes: {
43
50
  provider: 'hermes',
44
51
  status: 'unsupported',
@@ -26,7 +26,7 @@ function requireModelResource(filename) {
26
26
  const capabilityData = requireModelResource('model-capabilities.v1.json');
27
27
  const catalogData = requireModelResource('model-catalog.v1.json');
28
28
  const ProviderSchema = z.enum([
29
- 'antigravity', 'claude', 'codex', 'copilot', 'cursor', 'deepseek-harness', 'factory', 'hermes',
29
+ 'antigravity', 'claude', 'codex', 'copilot', 'cursor', 'deepseek-harness', 'factory', 'grokbot', 'hermes',
30
30
  'opencode', 'openclaw', 'openhuman', 'omp', 'pi', 'warp', 'windsurf',
31
31
  ]);
32
32
  const OutcomeSchema = z.enum([
@@ -92,6 +92,7 @@ const SKILLS_ONLY_PROVIDERS = new Set([
92
92
  'antigravity',
93
93
  'claude',
94
94
  'cursor',
95
+ 'grokbot',
95
96
  'hermes',
96
97
  'openhuman',
97
98
  'pi',
@@ -359,6 +359,48 @@ providers:
359
359
  deploy_target: project
360
360
  aggregated_output: true
361
361
 
362
+ grokbot:
363
+ display_name: Grok Bot
364
+ status: stable
365
+ # Multi-agent desktop assistant runtime. Distinct from Cursor IDE and from
366
+ # xAI Grok Build / API. Native skill root is operator-configured via
367
+ # AIWG_GROKBOT_SKILLS_DIR (fail-closed; no invented ~/.grokbot).
368
+ # ADR: docs/architecture/adr-grokbot-provider-target.md · epic #196.
369
+ # Optional natives (routines/CreateAgent/connectors) deferred #209 — does not block stable.
370
+ # #210: stable via Linux PUW + security + migration + maintainer waiver (no macOS/Windows gate).
371
+ daemon_tier: unsupported
372
+ daemon_pty_adapter: false
373
+ artifact_paths:
374
+ agents: "Indexed: aiwg discover / aiwg show agent" # native CreateAgent teammates are Grok-owned (#209)
375
+ commands: "Indexed: aiwg discover / aiwg show command"
376
+ skills: "AIWG_GROKBOT_SKILLS_DIR when configured (fail-closed)"
377
+ skills_cross_agent: "AIWG_GROKBOT_SKILLS_DIR/.aiwg/skills with --copy-all"
378
+ rules: "Indexed: aiwg show rule + AGENTS.md discover-first bridge"
379
+ behaviors: "Unsupported as automatic AIWG artifact; map manually to Grok routines (#209)"
380
+ native_features:
381
+ cron: true # Grok routines — capability present; AIWG does not own the clock
382
+ agent_teams: true # CreateAgent/teammates — Grok-owned orchestration
383
+ tasks: false # no verified separate task contract
384
+ mcp: true # connectors/dynamic tools — capability; AIWG MCP install deferred #209
385
+ behaviors: false
386
+ mission_control: false
387
+ daemon: false
388
+ emulation:
389
+ cron: null
390
+ agent_teams: null
391
+ tasks: aiwg-mc
392
+ mcp: null
393
+ behaviors: aiwg-mc
394
+ mission_control: aiwg-mc
395
+ daemon: null
396
+ hook_wiring:
397
+ at_link_support: false
398
+ hook_file: null
399
+ fallback: full-inject
400
+ context_file: AGENTS.md
401
+ deploy_target: mixed
402
+ aggregated_output: false
403
+
362
404
  hermes:
363
405
  display_name: Hermes
364
406
  status: stable
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Grok Bot skill-root resolution — fail-closed until explicitly configured.
3
+ *
4
+ * Unlike Hermes (HERMES_HOME with a documented default) or Pi
5
+ * (PI_CODING_AGENT_DIR with ~/.pi/agent fallback), Grok Bot's native skill
6
+ * filesystem root is not yet verified in AIWG. This module therefore:
7
+ *
8
+ * 1. Honors AIWG_GROKBOT_SKILLS_DIR when set to an absolute path
9
+ * 2. Rejects relative paths, `~`-only values that would invent a home layout,
10
+ * and path segments that attempt traversal after resolution
11
+ * 3. Returns null when unset — callers MUST fail closed for user-scope writes
12
+ *
13
+ * Never invent ~/.grokbot or ~/.cursor as a fallback.
14
+ *
15
+ * @see docs/architecture/adr-grokbot-provider-target.md
16
+ * @issue #205 #207
17
+ */
18
+ import { homedir } from 'node:os';
19
+ import * as path from 'node:path';
20
+ export const GROKBOT_SKILLS_DIR_ENV = 'AIWG_GROKBOT_SKILLS_DIR';
21
+ /**
22
+ * Expand a leading `~/` against the operator home directory.
23
+ * Bare `~` is rejected — it would invent a home skill root.
24
+ */
25
+ function expandHomePrefix(raw, userHome = homedir()) {
26
+ if (raw === '~')
27
+ return raw;
28
+ if (raw.startsWith('~/'))
29
+ return path.join(userHome, raw.slice(2));
30
+ return raw;
31
+ }
32
+ /**
33
+ * Validate and resolve the configured Grok Bot skills directory.
34
+ * Returns a structured result so CLI/doctor can print actionable remediation.
35
+ */
36
+ export function resolveGrokbotSkillsDirResult(env = process.env, userHome = homedir()) {
37
+ const raw = (env[GROKBOT_SKILLS_DIR_ENV] || '').trim();
38
+ if (!raw) {
39
+ return {
40
+ ok: false,
41
+ reason: 'unset',
42
+ message: `Grok Bot user-scope skill root is not configured. Set ${GROKBOT_SKILLS_DIR_ENV} to the absolute path of the Grok Bot skills/workflows directory before using --scope user or --global. AIWG does not invent ~/.grokbot.`,
43
+ };
44
+ }
45
+ const expanded = expandHomePrefix(raw, userHome);
46
+ if (expanded === '~' || expanded.startsWith('~')) {
47
+ return {
48
+ ok: false,
49
+ reason: 'not-absolute',
50
+ message: `${GROKBOT_SKILLS_DIR_ENV} must be an absolute path (got '${raw}'). Bare '~' is rejected so AIWG never invents a Grok home layout.`,
51
+ };
52
+ }
53
+ if (!path.isAbsolute(expanded)) {
54
+ return {
55
+ ok: false,
56
+ reason: 'not-absolute',
57
+ message: `${GROKBOT_SKILLS_DIR_ENV} must be an absolute path (got '${raw}'). Relative values are rejected.`,
58
+ };
59
+ }
60
+ const resolved = path.resolve(expanded);
61
+ // After resolve(), reject any attempt to escape via .. that still looks suspicious
62
+ // relative to a normalized absolute root — path.resolve already collapses '..',
63
+ // so the main remaining check is that we did not start relative.
64
+ if (raw.includes('\0') || resolved.includes('\0')) {
65
+ return {
66
+ ok: false,
67
+ reason: 'traversal',
68
+ message: `${GROKBOT_SKILLS_DIR_ENV} contains an invalid path character.`,
69
+ };
70
+ }
71
+ // Defensive: if the pre-resolve value contained '..' segments that would
72
+ // escape a declared parent, surface traversal. Absolute resolve is fine;
73
+ // we still refuse paths that are only '..' noise without a real root.
74
+ const normalizedInput = path.normalize(expanded);
75
+ if (normalizedInput === path.sep || normalizedInput === '') {
76
+ return {
77
+ ok: false,
78
+ reason: 'empty',
79
+ message: `${GROKBOT_SKILLS_DIR_ENV} resolves to an empty or root-only path; refuse to deploy there.`,
80
+ };
81
+ }
82
+ return { ok: true, path: resolved, source: 'env' };
83
+ }
84
+ /** Absolute skills dir when configured; otherwise null (fail closed). */
85
+ export function resolveGrokbotSkillsDir(env = process.env, userHome = homedir()) {
86
+ const result = resolveGrokbotSkillsDirResult(env, userHome);
87
+ return result.ok ? result.path : null;
88
+ }
89
+ /** True when user-scope skill writes are allowed. */
90
+ export function isGrokbotUserScopeConfigured(env = process.env, userHome = homedir()) {
91
+ return resolveGrokbotSkillsDir(env, userHome) !== null;
92
+ }
93
+ /**
94
+ * User-facing remediation for missing/invalid Grok Bot skill root.
95
+ * Shared by `aiwg use`, doctor, and the provider writer.
96
+ */
97
+ export function grokbotMissingRootRemediation(env = process.env, userHome = homedir()) {
98
+ const result = resolveGrokbotSkillsDirResult(env, userHome);
99
+ if (result.ok)
100
+ return '';
101
+ return result.message;
102
+ }
103
+ //# sourceMappingURL=grokbot-paths.js.map