@aiwg/cli 2026.10.11 → 2026.10.12

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 (132) hide show
  1. package/agentic/code/providers/model-catalog.v1.json +62 -12
  2. package/dist/src/artifacts/binding-target-identity.js +51 -0
  3. package/dist/src/artifacts/checksum-manifest.js +12 -0
  4. package/dist/src/artifacts/index-builder.js +11 -13
  5. package/dist/src/artifacts/query-engine.js +5 -11
  6. package/dist/src/cli/handlers/doctor-help.js +32 -0
  7. package/dist/src/cli/handlers/gates.js +19 -18
  8. package/dist/src/cli/handlers/models-help.js +7 -1
  9. package/dist/src/cli/handlers/models.js +3 -3
  10. package/dist/src/cli/handlers/script-runner.js +8 -5
  11. package/dist/src/cli/handlers/sessions-intake.js +104 -0
  12. package/dist/src/cli/handlers/sessions-tail.js +172 -0
  13. package/dist/src/cli/handlers/sessions.js +90 -17
  14. package/dist/src/cli/handlers/skill-lint.js +10 -3
  15. package/dist/src/cli/handlers/steward-format.js +100 -0
  16. package/dist/src/cli/handlers/steward-models.js +167 -0
  17. package/dist/src/cli/handlers/steward.js +14 -248
  18. package/dist/src/cli/handlers/use-bundle-counts.js +61 -0
  19. package/dist/src/cli/handlers/use.js +6 -24
  20. package/dist/src/cli/handlers/utilities.js +1 -24
  21. package/dist/src/config/aiwg-config.js +7 -0
  22. package/dist/src/config/authorization-cli.js +89 -0
  23. package/dist/src/config/cli-help.js +1 -0
  24. package/dist/src/config/cli.js +10 -1
  25. package/dist/src/decision/context-pruning.js +3 -2
  26. package/dist/src/decision/ensemble/contract.js +15 -4
  27. package/dist/src/decision/ensemble-study/artifacts.js +5 -0
  28. package/dist/src/decision/ensemble-study/score.js +4 -3
  29. package/dist/src/decision/feature-export.js +3 -9
  30. package/dist/src/decision/heldout/collector.js +2 -2
  31. package/dist/src/decision/issue-triage/runtime.js +3 -9
  32. package/dist/src/decision/qualification/gates.js +2 -1
  33. package/dist/src/decision/qualification/release.js +2 -3
  34. package/dist/src/decision/routing/report.js +2 -0
  35. package/dist/src/decision/sdlc-screening.js +3 -5
  36. package/dist/src/decision/sensitivity/comparative.js +5 -3
  37. package/dist/src/gates/driver.js +6 -77
  38. package/dist/src/gates/evaluate.js +4 -11
  39. package/dist/src/gates/floors.js +4 -4
  40. package/dist/src/gates/index.js +3 -3
  41. package/dist/src/gates/lattice.js +26 -0
  42. package/dist/src/gates/registry.js +2 -1
  43. package/dist/src/gates/report.js +19 -7
  44. package/dist/src/issues/audit-cli.js +120 -0
  45. package/dist/src/issues/audit-contract.js +64 -0
  46. package/dist/src/issues/audit-local.js +82 -0
  47. package/dist/src/issues/audit.js +220 -0
  48. package/dist/src/lint/rule-activation.js +15 -1
  49. package/dist/src/mission-protocol/canonical-codecs.js +270 -0
  50. package/dist/src/mission-protocol/codecs.js +22 -550
  51. package/dist/src/mission-protocol/health-trace-codecs.js +281 -0
  52. package/dist/src/mission-protocol/health-trace-types.js +43 -0
  53. package/dist/src/mission-protocol/types.js +2 -42
  54. package/dist/src/mission-protocol/worker-contract-json.js +10 -0
  55. package/dist/src/mission-protocol/worker-review-gate.js +100 -0
  56. package/dist/src/mission-protocol/worker-review-types.js +2 -0
  57. package/dist/src/models/catalog-policy.js +280 -0
  58. package/dist/src/models/index.js +1 -1
  59. package/dist/src/models/model-catalog.v1.json +62 -12
  60. package/dist/src/models/policy-resources.js +28 -0
  61. package/dist/src/models/provider-policy.js +10 -546
  62. package/dist/src/models/resolver.js +26 -8
  63. package/dist/src/models/router.js +15 -2
  64. package/dist/src/models/tiers.js +13 -0
  65. package/dist/src/models/types.js +0 -6
  66. package/dist/src/models/worker-ceilings.js +59 -0
  67. package/dist/src/models/worker-invocation-policy.js +243 -0
  68. package/dist/src/models/worker-plan.js +16 -20
  69. package/dist/src/models/worker-review-lineage.js +55 -0
  70. package/dist/src/models/worker-selection-policy.js +1 -1
  71. package/dist/src/models/wrapper-route.js +6 -3
  72. package/dist/src/policy/authorization.js +1 -0
  73. package/dist/src/policy/hitl-config.js +63 -0
  74. package/dist/src/policy/hitl-receipt.js +57 -0
  75. package/dist/src/policy/hitl-types.js +4 -0
  76. package/dist/src/policy/hitl-validation.js +39 -0
  77. package/dist/src/policy/hitl.js +117 -0
  78. package/dist/src/rules/activation.d.mts +1 -1
  79. package/dist/src/rules/activation.mjs +0 -2
  80. package/dist/src/rules/gate-coverage.js +51 -0
  81. package/dist/src/rules/gate-references.js +16 -0
  82. package/dist/src/rules/rule-frontmatter.schema.json +7 -1
  83. package/dist/src/serve/worker-command-request.js +21 -4
  84. package/dist/src/serve/worker-invocation-preparation.js +3 -1
  85. package/dist/src/serve/worker-invocation.js +21 -10
  86. package/dist/src/sessions/adapters/deepseek-harness.js +1 -0
  87. package/dist/src/sessions/adapters/grok-build-native.js +269 -0
  88. package/dist/src/sessions/adapters/grok-build.js +57 -15
  89. package/dist/src/sessions/adapters/hermes-state-db.js +252 -0
  90. package/dist/src/sessions/adapters/hermes.js +42 -3
  91. package/dist/src/sessions/adapters/warp.js +1 -1
  92. package/dist/src/sessions/batch-import.js +10 -0
  93. package/dist/src/sessions/contracts.js +1 -1
  94. package/dist/src/sessions/discovery-capability.js +38 -0
  95. package/dist/src/sessions/importer.js +8 -251
  96. package/dist/src/sessions/index.js +4 -0
  97. package/dist/src/sessions/intake-dir.js +71 -0
  98. package/dist/src/sessions/normalization.js +251 -0
  99. package/dist/src/sessions/tail.js +91 -0
  100. package/dist/src/sessions/workspace-discovery.js +83 -7
  101. package/dist/src/skills/agent-skill-sidecar.js +28 -0
  102. package/dist/src/skills/agent-skills.js +4 -23
  103. package/dist/src/skills/claude-surface-projection.js +25 -0
  104. package/dist/src/skills/deployer.js +8 -288
  105. package/dist/src/skills/deployment-policy.js +114 -0
  106. package/dist/src/skills/deployment-projection.js +152 -0
  107. package/dist/src/skills/deployment-types.js +20 -0
  108. package/dist/src/skills/exporter.js +8 -31
  109. package/dist/src/skills/provider-extensions.js +41 -0
  110. package/dist/src/skills/run.js +6 -0
  111. package/dist/src/skills/types.js +0 -8
  112. package/dist/src/skills/validator-resources.js +68 -0
  113. package/dist/src/skills/validator.js +6 -55
  114. package/dist/src/storage/cli-migrate-options.js +125 -0
  115. package/dist/src/storage/cli-migrate.js +111 -0
  116. package/dist/src/storage/cli.js +4 -279
  117. package/dist/src/storage/migration-adapter.js +79 -0
  118. package/dist/src/storage/migration-copy.js +108 -0
  119. package/dist/src/storage/migration-protocol.js +14 -197
  120. package/dist/src/storage/migration-records.js +186 -0
  121. package/dist/src/storage/migration-types.js +12 -0
  122. package/dist/src/tracker/forge-http.js +2 -1
  123. package/dist/src/tracker/issue-pages.js +110 -0
  124. package/package.json +1 -1
  125. package/schemas/mission-v1.schema.json +335 -0
  126. package/schemas/models/model-catalog.v1.schema.json +19 -1
  127. package/schemas/models/model-config-compatibility.v1.schema.json +3 -2
  128. package/schemas/models/model-policy.v1.schema.json +1 -1
  129. package/tools/agents/providers/provider-paths-staging.mjs +35 -0
  130. package/tools/agents/providers/rule-binding-targets.mjs +146 -0
  131. package/tools/agents/providers/rule-delivery.mjs +7 -126
  132. package/vscode-extension/schemas/aiwg.config.v1.json +177 -0
@@ -7,296 +7,15 @@
7
7
  * @implements #1879
8
8
  */
9
9
  import fs from 'node:fs';
10
- import os from 'node:os';
11
10
  import path from 'node:path';
12
11
  import { randomUUID } from 'node:crypto';
13
- import { stringify } from 'yaml';
14
- import { getProviderDefinition, normalizeProviderDefinitionId, } from '../providers/provider-definitions.js';
15
- import { AGENT_SKILLS_SIDECAR_SCHEMA, AIWG_SKILL_CONTROL_FIELDS, createAgentSkillSidecar, projectStrictAgentSkill, } from './agent-skills.js';
12
+ import { normalizeProviderDefinitionId } from '../providers/provider-definitions.js';
13
+ import { AGENT_SKILLS_SIDECAR_SCHEMA } from './agent-skills.js';
16
14
  import { getImportedAgentSkill } from './importer.js';
17
- import { validateAgentSkillContent } from './validator.js';
18
- import { resolveHermesHomePath } from '../providers/hermes-home.js';
19
- import { museXdgSkillsDirRemediation, resolveMuseXdgSkillsDir, } from '../providers/muse-paths.js';
20
- import { GROKBOT_SKILLS_DIR_ENV, grokbotMissingRootRemediation, resolveGrokbotSkillsDir, } from '../providers/grokbot-paths.js';
21
- export const AGENT_SKILL_MANAGED_MARKER = '.aiwg-managed';
22
- export const AGENT_SKILL_DEPLOYMENT_SIDECAR = '.aiwg-agent-skill.json';
23
- const MARKER_CONTENT = 'aiwg-agent-skill-v1\n';
24
- const STANDARD_FIELDS = [
25
- 'name',
26
- 'description',
27
- 'license',
28
- 'compatibility',
29
- 'metadata',
30
- 'allowed-tools',
31
- ];
32
- const AIWG_FIELDS = new Set(AIWG_SKILL_CONTROL_FIELDS);
33
- export class AgentSkillDeploymentError extends Error {
34
- code;
35
- constructor(code, message) {
36
- super(message);
37
- this.code = code;
38
- this.name = 'AgentSkillDeploymentError';
39
- }
40
- }
41
- function fail(code, message) {
42
- throw new AgentSkillDeploymentError(code, message);
43
- }
44
- function assertPortableName(name) {
45
- if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name) || name.length > 64) {
46
- fail('AS_DEPLOY_NAME', 'Agent Skill name must be 1-64 lowercase ASCII letters, numbers, or single hyphens');
47
- }
48
- }
49
- function resolvedHome(options) {
50
- return path.resolve(options.homeDir ?? os.homedir());
51
- }
52
- function resolvePolicy(target, options) {
53
- const provider = normalizeProviderDefinitionId(target);
54
- if (!provider) {
55
- fail('AS_DEPLOY_PROVIDER', `unknown Agent Skills target "${target}"`);
56
- }
57
- const definition = getProviderDefinition(provider);
58
- if (!definition) {
59
- fail('AS_DEPLOY_PROVIDER', `provider definition is unavailable for "${provider}"`);
60
- }
61
- const namespace = definition.skillNamespace;
62
- const reasons = [];
63
- const warnings = [];
64
- let root = namespace.pathType === 'home-dir'
65
- ? path.join(resolvedHome(options), namespace.skillsBaseDir)
66
- : path.join(path.resolve(options.projectDir), namespace.skillsBaseDir);
67
- let status = 'native';
68
- let supported = true;
69
- let appendToDescription;
70
- let maxDescriptionLength;
71
- switch (provider) {
72
- case 'codex':
73
- root = path.join(path.resolve(options.projectDir), '.agents', 'skills');
74
- status = 'projected';
75
- maxDescriptionLength = namespace.maxDescriptionLength;
76
- reasons.push('uses the project .agents/skills compatibility surface without the legacy 100/500 truncation transform');
77
- break;
78
- case 'factory':
79
- status = 'projected';
80
- appendToDescription = namespace.appendToDescription;
81
- reasons.push('applies the Factory description guidance before strict validation');
82
- break;
83
- case 'grokbot': {
84
- // Fail closed: never invent ~/grokbot-skills or ~/.grokbot.
85
- const configured = resolveGrokbotSkillsDir(process.env);
86
- if (!configured) {
87
- root = '';
88
- status = 'unsupported';
89
- supported = false;
90
- reasons.push(grokbotMissingRootRemediation(process.env));
91
- warnings.push(`Agent Skills deploy for grokbot requires absolute ${GROKBOT_SKILLS_DIR_ENV}; no filesystem root was invented`);
92
- }
93
- else {
94
- root = configured;
95
- reasons.push(`uses the operator-configured ${GROKBOT_SKILLS_DIR_ENV} skills root with strict managed ownership markers`);
96
- }
97
- break;
98
- }
99
- case 'hermes':
100
- if (options.homeDir === undefined) {
101
- root = resolveHermesHomePath('skills');
102
- }
103
- reasons.push('uses the active HERMES_HOME skills surface with strict managed ownership markers');
104
- break;
105
- case 'muse': {
106
- // ADR scope rule 1: the default projection is the project
107
- // <repo>/.agents/skills surface shared with antigravity, codex, and
108
- // deepseek-harness. Muse reads both that root and its XDG user root,
109
- // so writing the user root by default would list a skill twice.
110
- // #234: an explicit user scope resolves the documented XDG root at
111
- // deploy time — never ~/.muse — and bad XDG metadata fails closed.
112
- if (options.scope === 'user') {
113
- const home = resolvedHome(options);
114
- const configured = resolveMuseXdgSkillsDir(process.env, home);
115
- if (!configured) {
116
- root = '';
117
- status = 'unsupported';
118
- supported = false;
119
- reasons.push(museXdgSkillsDirRemediation(process.env, home));
120
- warnings.push('Agent Skills deploy for muse requires a valid absolute XDG_CONFIG_HOME; no filesystem root was invented');
121
- }
122
- else {
123
- root = configured;
124
- reasons.push('uses the Muse XDG user skills root ($XDG_CONFIG_HOME/muse/skills, default ~/.config/muse/skills) with strict managed ownership markers');
125
- }
126
- }
127
- else {
128
- reasons.push('uses the project .agents/skills surface shared with antigravity, codex, and deepseek-harness');
129
- }
130
- break;
131
- }
132
- case 'openhuman':
133
- status = 'projected';
134
- reasons.push('uses the verified global one-level ~/.openhuman/skills layout');
135
- break;
136
- case 'windsurf':
137
- status = 'projected';
138
- reasons.push('uses one skill bundle directly below the one-level .windsurf/skills surface');
139
- break;
140
- default:
141
- reasons.push('provider exposes a native recursive Agent Skills bundle surface');
142
- }
143
- return {
144
- provider,
145
- root,
146
- status,
147
- supported,
148
- reasons,
149
- warnings,
150
- appendToDescription,
151
- maxDescriptionLength,
152
- };
153
- }
154
- function assertSafeSourceEntry(sourceRoot, absolutePath, relativePath) {
155
- const stat = fs.lstatSync(absolutePath);
156
- if (stat.isSymbolicLink()) {
157
- fail('AS_DEPLOY_SOURCE_SYMLINK', `managed source contains a symlink: ${relativePath}`);
158
- }
159
- if (!stat.isDirectory() && !stat.isFile()) {
160
- fail('AS_DEPLOY_SOURCE_SPECIAL_FILE', `managed source contains a non-regular entry: ${relativePath}`);
161
- }
162
- const real = fs.realpathSync.native(absolutePath);
163
- const relativeReal = path.relative(fs.realpathSync.native(sourceRoot), real);
164
- if (relativeReal.startsWith('..') || path.isAbsolute(relativeReal)) {
165
- fail('AS_DEPLOY_SOURCE_ESCAPE', `managed source entry escapes its root: ${relativePath}`);
166
- }
167
- return stat;
168
- }
169
- function collectSourceEntries(sourceRoot) {
170
- const entries = [];
171
- const walk = (current, prefix) => {
172
- for (const entry of fs.readdirSync(current, { withFileTypes: true })
173
- .sort((left, right) => left.name.localeCompare(right.name))) {
174
- const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
175
- if (relativePath === AGENT_SKILL_MANAGED_MARKER
176
- || relativePath === AGENT_SKILL_DEPLOYMENT_SIDECAR) {
177
- fail('AS_DEPLOY_RESERVED_PATH', `managed source uses reserved deployment path "${relativePath}"`);
178
- }
179
- const absolutePath = path.join(current, entry.name);
180
- const stat = assertSafeSourceEntry(sourceRoot, absolutePath, relativePath);
181
- if (stat.isDirectory()) {
182
- entries.push({ kind: 'directory', relativePath });
183
- walk(absolutePath, relativePath);
184
- }
185
- else {
186
- entries.push({
187
- kind: 'file',
188
- relativePath,
189
- bytes: fs.readFileSync(absolutePath),
190
- });
191
- }
192
- }
193
- };
194
- walk(sourceRoot, '');
195
- return entries;
196
- }
197
- function projectionDocument(record) {
198
- const sourceEntries = collectSourceEntries(record.managedLocation);
199
- const skillFile = sourceEntries.find((entry) => (entry.kind === 'file' && entry.relativePath === 'SKILL.md'));
200
- if (!skillFile) {
201
- fail('AS_DEPLOY_SKILL_MISSING', 'managed source does not contain SKILL.md');
202
- }
203
- const content = new TextDecoder('utf-8', { fatal: true }).decode(skillFile.bytes);
204
- const validation = validateAgentSkillContent(content, {
205
- profile: record.validationProfile,
206
- file: path.join(record.managedLocation, 'SKILL.md'),
207
- directoryName: record.name,
208
- skillRoot: record.managedLocation,
209
- checkResources: true,
210
- });
211
- if (!validation.valid || !validation.frontmatter) {
212
- fail('AS_DEPLOY_SOURCE_INVALID', `managed source for "${record.name}" no longer passes ${record.validationProfile} validation`);
213
- }
214
- const standard = {};
215
- for (const key of STANDARD_FIELDS) {
216
- const value = validation.frontmatter[key];
217
- if (value !== undefined) {
218
- Object.assign(standard, { [key]: structuredClone(value) });
219
- }
220
- }
221
- const aiwg = {};
222
- for (const [key, value] of Object.entries(validation.frontmatter)) {
223
- if (AIWG_FIELDS.has(key)) {
224
- aiwg[key] = structuredClone(value);
225
- }
226
- }
227
- return {
228
- document: {
229
- standard: standard,
230
- body: validation.body,
231
- resources: [],
232
- aiwg,
233
- unknownFields: [],
234
- },
235
- sourceEntries,
236
- };
237
- }
238
- function strictSkillBytes(record, policy, document) {
239
- const metadata = projectStrictAgentSkill(document);
240
- if (policy.appendToDescription) {
241
- const suffix = policy.appendToDescription;
242
- if (!metadata.description.endsWith(suffix)) {
243
- metadata.description = `${metadata.description.trimEnd()} ${suffix}`;
244
- }
245
- }
246
- if (policy.maxDescriptionLength !== undefined
247
- && metadata.description.length > policy.maxDescriptionLength) {
248
- policy.status = 'degraded';
249
- policy.supported = false;
250
- policy.reasons.push(`description length ${metadata.description.length} exceeds the provider limit ${policy.maxDescriptionLength}; no truncation was applied`);
251
- return undefined;
252
- }
253
- const frontmatter = stringify(metadata, {
254
- lineWidth: 0,
255
- sortMapEntries: false,
256
- }).trimEnd();
257
- const content = `---\n${frontmatter}\n---\n${document.body}`;
258
- const validation = validateAgentSkillContent(content, {
259
- profile: 'strict',
260
- file: 'SKILL.md',
261
- directoryName: record.name,
262
- });
263
- if (!validation.valid) {
264
- policy.status = 'degraded';
265
- policy.supported = false;
266
- policy.reasons.push(`provider projection failed strict validation: ${validation.diagnostics
267
- .filter((item) => item.severity === 'error')
268
- .map((item) => item.code)
269
- .join(', ')}`);
270
- return undefined;
271
- }
272
- return Buffer.from(content, 'utf8');
273
- }
274
- function sidecarBytes(record, policy, document) {
275
- const portableSidecar = createAgentSkillSidecar(document, {
276
- sourceKind: record.source.kind,
277
- locator: record.source.locator,
278
- ...(record.source.kind === 'git'
279
- ? {
280
- requestedRevision: record.source.requestedRevision,
281
- resolvedRevision: record.source.resolvedRevision,
282
- }
283
- : {}),
284
- sourceDigest: record.digest,
285
- importedAt: record.importedAt,
286
- aiwgVersion: record.aiwgVersion,
287
- }, record.validationProfile, record.trust);
288
- return Buffer.from(`${JSON.stringify({
289
- schemaVersion: 1,
290
- kind: 'aiwg-managed-agent-skill-projection',
291
- name: record.name,
292
- provider: policy.provider,
293
- projectionStatus: policy.status,
294
- sourceDigest: record.digest,
295
- reasons: policy.reasons,
296
- warnings: policy.warnings,
297
- portable: portableSidecar,
298
- }, null, 2)}\n`, 'utf8');
299
- }
15
+ import { resolvePolicy } from './deployment-policy.js';
16
+ import { projectionDocument, providerSkillBytes, sidecarBytes } from './deployment-projection.js';
17
+ import { AGENT_SKILL_MANAGED_MARKER, AGENT_SKILL_DEPLOYMENT_SIDECAR, MARKER_CONTENT, assertPortableName, fail, } from './deployment-types.js';
18
+ export { AGENT_SKILL_MANAGED_MARKER, AGENT_SKILL_DEPLOYMENT_SIDECAR, AgentSkillDeploymentError, } from './deployment-types.js';
300
19
  function readDeploymentSidecar(targetPath, expectedName, expectedProvider) {
301
20
  try {
302
21
  const sidecarPath = path.join(targetPath, AGENT_SKILL_DEPLOYMENT_SIDECAR);
@@ -356,7 +75,8 @@ function buildProjectionPlan(record, options) {
356
75
  };
357
76
  }
358
77
  const { document, sourceEntries } = projectionDocument(record);
359
- const skillBytes = strictSkillBytes(record, policy, document);
78
+ const original = sourceEntries.find((entry) => (entry.kind === 'file' && entry.relativePath === 'SKILL.md'));
79
+ const skillBytes = providerSkillBytes(record, policy, document, original?.bytes);
360
80
  if (!skillBytes) {
361
81
  return {
362
82
  policy,
@@ -0,0 +1,114 @@
1
+ // Resolve existing provider skill roots and projection limits.
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { getProviderDefinition, normalizeProviderDefinitionId } from '../providers/provider-definitions.js';
5
+ import { resolveHermesHomePath } from '../providers/hermes-home.js';
6
+ import { museXdgSkillsDirRemediation, resolveMuseXdgSkillsDir } from '../providers/muse-paths.js';
7
+ import { GROKBOT_SKILLS_DIR_ENV, grokbotMissingRootRemediation, resolveGrokbotSkillsDir } from '../providers/grokbot-paths.js';
8
+ import { fail } from './deployment-types.js';
9
+ function resolvedHome(options) {
10
+ return path.resolve(options.homeDir ?? os.homedir());
11
+ }
12
+ export function resolvePolicy(target, options) {
13
+ const provider = normalizeProviderDefinitionId(target);
14
+ if (!provider) {
15
+ fail('AS_DEPLOY_PROVIDER', `unknown Agent Skills target "${target}"`);
16
+ }
17
+ const definition = getProviderDefinition(provider);
18
+ if (!definition) {
19
+ fail('AS_DEPLOY_PROVIDER', `provider definition is unavailable for "${provider}"`);
20
+ }
21
+ const namespace = definition.skillNamespace;
22
+ const reasons = [];
23
+ const warnings = [];
24
+ let root = namespace.pathType === 'home-dir'
25
+ ? path.join(resolvedHome(options), namespace.skillsBaseDir)
26
+ : path.join(path.resolve(options.projectDir), namespace.skillsBaseDir);
27
+ let status = 'native';
28
+ let supported = true;
29
+ let appendToDescription;
30
+ let maxDescriptionLength;
31
+ switch (provider) {
32
+ case 'codex':
33
+ root = path.join(path.resolve(options.projectDir), '.agents', 'skills');
34
+ status = 'projected';
35
+ maxDescriptionLength = namespace.maxDescriptionLength;
36
+ reasons.push('uses the project .agents/skills compatibility surface without the legacy 100/500 truncation transform');
37
+ break;
38
+ case 'factory':
39
+ status = 'projected';
40
+ appendToDescription = namespace.appendToDescription;
41
+ reasons.push('applies the Factory description guidance before strict validation');
42
+ break;
43
+ case 'grokbot': {
44
+ // Fail closed: never invent ~/grokbot-skills or ~/.grokbot.
45
+ const configured = resolveGrokbotSkillsDir(process.env);
46
+ if (!configured) {
47
+ root = '';
48
+ status = 'unsupported';
49
+ supported = false;
50
+ reasons.push(grokbotMissingRootRemediation(process.env));
51
+ warnings.push(`Agent Skills deploy for grokbot requires absolute ${GROKBOT_SKILLS_DIR_ENV}; no filesystem root was invented`);
52
+ }
53
+ else {
54
+ root = configured;
55
+ reasons.push(`uses the operator-configured ${GROKBOT_SKILLS_DIR_ENV} skills root with strict managed ownership markers`);
56
+ }
57
+ break;
58
+ }
59
+ case 'hermes':
60
+ if (options.homeDir === undefined) {
61
+ root = resolveHermesHomePath('skills');
62
+ }
63
+ reasons.push('uses the active HERMES_HOME skills surface with strict managed ownership markers');
64
+ break;
65
+ case 'muse': {
66
+ // ADR scope rule 1: the default projection is the project
67
+ // <repo>/.agents/skills surface shared with antigravity, codex, and
68
+ // deepseek-harness. Muse reads both that root and its XDG user root,
69
+ // so writing the user root by default would list a skill twice.
70
+ // #234: an explicit user scope resolves the documented XDG root at
71
+ // deploy time — never ~/.muse — and bad XDG metadata fails closed.
72
+ if (options.scope === 'user') {
73
+ const home = resolvedHome(options);
74
+ const configured = resolveMuseXdgSkillsDir(process.env, home);
75
+ if (!configured) {
76
+ root = '';
77
+ status = 'unsupported';
78
+ supported = false;
79
+ reasons.push(museXdgSkillsDirRemediation(process.env, home));
80
+ warnings.push('Agent Skills deploy for muse requires a valid absolute XDG_CONFIG_HOME; no filesystem root was invented');
81
+ }
82
+ else {
83
+ root = configured;
84
+ reasons.push('uses the Muse XDG user skills root ($XDG_CONFIG_HOME/muse/skills, default ~/.config/muse/skills) with strict managed ownership markers');
85
+ }
86
+ }
87
+ else {
88
+ reasons.push('uses the project .agents/skills surface shared with antigravity, codex, and deepseek-harness');
89
+ }
90
+ break;
91
+ }
92
+ case 'openhuman':
93
+ status = 'projected';
94
+ reasons.push('uses the verified global one-level ~/.openhuman/skills layout');
95
+ break;
96
+ case 'windsurf':
97
+ status = 'projected';
98
+ reasons.push('uses one skill bundle directly below the one-level .windsurf/skills surface');
99
+ break;
100
+ default:
101
+ reasons.push('provider exposes a native recursive Agent Skills bundle surface');
102
+ }
103
+ return {
104
+ provider,
105
+ root,
106
+ status,
107
+ supported,
108
+ reasons,
109
+ warnings,
110
+ appendToDescription,
111
+ maxDescriptionLength,
112
+ };
113
+ }
114
+ //# sourceMappingURL=deployment-policy.js.map
@@ -0,0 +1,152 @@
1
+ // Project immutable managed sources into provider frontmatter and sidecars.
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { stringify } from 'yaml';
5
+ import { createAgentSkillSidecar, projectStrictAgentSkill } from './agent-skills.js';
6
+ import { agentSkillDocument, claudeSkillExtensions } from './provider-extensions.js';
7
+ import { validateAgentSkillContent } from './validator.js';
8
+ import { AGENT_SKILL_MANAGED_MARKER, AGENT_SKILL_DEPLOYMENT_SIDECAR, fail, } from './deployment-types.js';
9
+ function assertSafeSourceEntry(sourceRoot, absolutePath, relativePath) {
10
+ const stat = fs.lstatSync(absolutePath);
11
+ if (stat.isSymbolicLink()) {
12
+ fail('AS_DEPLOY_SOURCE_SYMLINK', `managed source contains a symlink: ${relativePath}`);
13
+ }
14
+ if (!stat.isDirectory() && !stat.isFile()) {
15
+ fail('AS_DEPLOY_SOURCE_SPECIAL_FILE', `managed source contains a non-regular entry: ${relativePath}`);
16
+ }
17
+ const real = fs.realpathSync.native(absolutePath);
18
+ const relativeReal = path.relative(fs.realpathSync.native(sourceRoot), real);
19
+ if (relativeReal.startsWith('..') || path.isAbsolute(relativeReal)) {
20
+ fail('AS_DEPLOY_SOURCE_ESCAPE', `managed source entry escapes its root: ${relativePath}`);
21
+ }
22
+ return stat;
23
+ }
24
+ function collectSourceEntries(sourceRoot) {
25
+ const entries = [];
26
+ const walk = (current, prefix) => {
27
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })
28
+ .sort((left, right) => left.name.localeCompare(right.name))) {
29
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
30
+ if (relativePath === AGENT_SKILL_MANAGED_MARKER
31
+ || relativePath === AGENT_SKILL_DEPLOYMENT_SIDECAR) {
32
+ fail('AS_DEPLOY_RESERVED_PATH', `managed source uses reserved deployment path "${relativePath}"`);
33
+ }
34
+ const absolutePath = path.join(current, entry.name);
35
+ const stat = assertSafeSourceEntry(sourceRoot, absolutePath, relativePath);
36
+ if (stat.isDirectory()) {
37
+ entries.push({ kind: 'directory', relativePath });
38
+ walk(absolutePath, relativePath);
39
+ }
40
+ else {
41
+ entries.push({
42
+ kind: 'file',
43
+ relativePath,
44
+ bytes: fs.readFileSync(absolutePath),
45
+ });
46
+ }
47
+ }
48
+ };
49
+ walk(sourceRoot, '');
50
+ return entries;
51
+ }
52
+ export function projectionDocument(record) {
53
+ const sourceEntries = collectSourceEntries(record.managedLocation);
54
+ const skillFile = sourceEntries.find((entry) => (entry.kind === 'file' && entry.relativePath === 'SKILL.md'));
55
+ if (!skillFile) {
56
+ fail('AS_DEPLOY_SKILL_MISSING', 'managed source does not contain SKILL.md');
57
+ }
58
+ const content = new TextDecoder('utf-8', { fatal: true }).decode(skillFile.bytes);
59
+ const validation = validateAgentSkillContent(content, {
60
+ profile: record.validationProfile,
61
+ file: path.join(record.managedLocation, 'SKILL.md'),
62
+ directoryName: record.name,
63
+ skillRoot: record.managedLocation,
64
+ checkResources: true,
65
+ });
66
+ if (!validation.valid || !validation.frontmatter) {
67
+ fail('AS_DEPLOY_SOURCE_INVALID', `managed source for "${record.name}" no longer passes ${record.validationProfile} validation`);
68
+ }
69
+ return {
70
+ document: agentSkillDocument(validation.frontmatter, validation.body),
71
+ sourceEntries,
72
+ };
73
+ }
74
+ export function providerSkillBytes(record, policy, document, originalBytes) {
75
+ const metadata = { ...projectStrictAgentSkill(document) };
76
+ const extensions = claudeSkillExtensions(document);
77
+ if (policy.provider === 'claude') {
78
+ Object.assign(metadata, extensions);
79
+ }
80
+ else {
81
+ for (const field of Object.keys(extensions).sort()) {
82
+ const warning = `Claude skill field "${field}" is dropped for provider "${policy.provider}"; retained in providers.claude sidecar only`;
83
+ policy.warnings.push(warning);
84
+ policy.reasons.push(warning);
85
+ policy.status = 'degraded';
86
+ }
87
+ }
88
+ if (policy.appendToDescription) {
89
+ const suffix = policy.appendToDescription;
90
+ if (!metadata.description.endsWith(suffix)) {
91
+ metadata.description = `${metadata.description.trimEnd()} ${suffix}`;
92
+ }
93
+ }
94
+ if (policy.maxDescriptionLength !== undefined
95
+ && metadata.description.length > policy.maxDescriptionLength) {
96
+ policy.status = 'degraded';
97
+ policy.supported = false;
98
+ policy.reasons.push(`description length ${metadata.description.length} exceeds the provider limit ${policy.maxDescriptionLength}; no truncation was applied`);
99
+ return undefined;
100
+ }
101
+ const frontmatter = stringify(metadata, {
102
+ lineWidth: 0,
103
+ sortMapEntries: false,
104
+ }).trimEnd();
105
+ const content = `---\n${frontmatter}\n---\n${document.body}`;
106
+ const validation = validateAgentSkillContent(content, {
107
+ profile: policy.provider === 'claude' ? 'compatible' : 'strict',
108
+ file: 'SKILL.md',
109
+ directoryName: record.name,
110
+ });
111
+ if (!validation.valid) {
112
+ policy.status = 'degraded';
113
+ policy.supported = false;
114
+ policy.reasons.push(`provider projection failed validation: ${validation.diagnostics
115
+ .filter((item) => item.severity === 'error')
116
+ .map((item) => item.code)
117
+ .join(', ')}`);
118
+ return undefined;
119
+ }
120
+ if (policy.provider === 'claude' && originalBytes
121
+ && document.unknownFields.length === 0
122
+ && Object.keys(document.aiwg).every((key) => Object.hasOwn(extensions, key)))
123
+ return Buffer.from(originalBytes);
124
+ return Buffer.from(content, 'utf8');
125
+ }
126
+ export function sidecarBytes(record, policy, document) {
127
+ const portableSidecar = createAgentSkillSidecar(document, {
128
+ sourceKind: record.source.kind,
129
+ locator: record.source.locator,
130
+ ...(record.source.kind === 'git'
131
+ ? {
132
+ requestedRevision: record.source.requestedRevision,
133
+ resolvedRevision: record.source.resolvedRevision,
134
+ }
135
+ : {}),
136
+ sourceDigest: record.digest,
137
+ importedAt: record.importedAt,
138
+ aiwgVersion: record.aiwgVersion,
139
+ }, record.validationProfile, record.trust);
140
+ return Buffer.from(`${JSON.stringify({
141
+ schemaVersion: 1,
142
+ kind: 'aiwg-managed-agent-skill-projection',
143
+ name: record.name,
144
+ provider: policy.provider,
145
+ projectionStatus: policy.status,
146
+ sourceDigest: record.digest,
147
+ reasons: policy.reasons,
148
+ warnings: policy.warnings,
149
+ portable: portableSidecar,
150
+ }, null, 2)}\n`, 'utf8');
151
+ }
152
+ //# sourceMappingURL=deployment-projection.js.map
@@ -0,0 +1,20 @@
1
+ export const AGENT_SKILL_MANAGED_MARKER = '.aiwg-managed';
2
+ export const AGENT_SKILL_DEPLOYMENT_SIDECAR = '.aiwg-agent-skill.json';
3
+ export const MARKER_CONTENT = 'aiwg-agent-skill-v1\n';
4
+ export class AgentSkillDeploymentError extends Error {
5
+ code;
6
+ constructor(code, message) {
7
+ super(message);
8
+ this.code = code;
9
+ this.name = 'AgentSkillDeploymentError';
10
+ }
11
+ }
12
+ export function fail(code, message) {
13
+ throw new AgentSkillDeploymentError(code, message);
14
+ }
15
+ export function assertPortableName(name) {
16
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name) || name.length > 64) {
17
+ fail('AS_DEPLOY_NAME', 'Agent Skill name must be 1-64 lowercase ASCII letters, numbers, or single hyphens');
18
+ }
19
+ }
20
+ //# sourceMappingURL=deployment-types.js.map
@@ -13,18 +13,10 @@ import fs from 'node:fs';
13
13
  import path from 'node:path';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { stringify } from 'yaml';
16
- import { AGENT_SKILLS_BASELINE, AIWG_SKILL_CONTROL_FIELDS, projectStrictAgentSkill, } from './agent-skills.js';
16
+ import { AGENT_SKILLS_BASELINE, projectStrictAgentSkill, } from './agent-skills.js';
17
17
  import { validateAgentSkillContent } from './validator.js';
18
+ import { agentSkillDocument } from './provider-extensions.js';
18
19
  export const AGENT_SKILL_EXPORT_SIDECAR = '.aiwg-agent-skill-export.json';
19
- const STANDARD_FIELDS = [
20
- 'name',
21
- 'description',
22
- 'license',
23
- 'compatibility',
24
- 'metadata',
25
- 'allowed-tools',
26
- ];
27
- const AIWG_FIELDS = new Set(AIWG_SKILL_CONTROL_FIELDS);
28
20
  export class AgentSkillExportError extends Error {
29
21
  code;
30
22
  constructor(code, message) {
@@ -160,28 +152,11 @@ function parseDocument(sourceRoot, entries) {
160
152
  .map((item) => item.code)
161
153
  .join(', ')}`);
162
154
  }
163
- const standard = {};
164
- for (const key of STANDARD_FIELDS) {
165
- const value = validation.frontmatter[key];
166
- if (value !== undefined)
167
- Object.assign(standard, { [key]: structuredClone(value) });
168
- }
169
- const aiwg = {};
170
- for (const [key, value] of Object.entries(validation.frontmatter)) {
171
- if (AIWG_FIELDS.has(key)) {
172
- aiwg[key] = structuredClone(value);
173
- }
174
- }
155
+ const document = agentSkillDocument(validation.frontmatter, validation.body);
175
156
  return {
176
- document: {
177
- standard: standard,
178
- body: validation.body,
179
- resources: [],
180
- aiwg,
181
- unknownFields: [],
182
- },
183
- description: validation.frontmatter.description,
184
- omittedAiwgFields: Object.keys(aiwg).sort(),
157
+ document,
158
+ description: document.standard.description,
159
+ omittedAiwgFields: Object.keys(document.aiwg).sort(),
185
160
  };
186
161
  }
187
162
  function strictSkillEntry(sourceRoot, document) {
@@ -332,6 +307,7 @@ export function exportAgentSkillDirectory(sourceDir, options) {
332
307
  sourceDigest,
333
308
  exportDigest: '',
334
309
  omittedAiwgFields,
310
+ ...(document.providers ? { providers: document.providers } : {}),
335
311
  fileCount: 0,
336
312
  totalBytes: 0,
337
313
  exportedAt,
@@ -360,6 +336,7 @@ export function exportAgentSkillDirectory(sourceDir, options) {
360
336
  sourceDigest,
361
337
  exportDigest,
362
338
  omittedAiwgFields,
339
+ ...(document.providers ? { providers: document.providers } : {}),
363
340
  fileCount,
364
341
  totalBytes,
365
342
  exportedAt,