@aiwg/cli 2026.10.10 → 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 (156) hide show
  1. package/agentic/code/providers/model-capabilities.v1.json +78 -14
  2. package/agentic/code/providers/model-catalog.v1.json +62 -12
  3. package/dist/src/artifacts/binding-target-identity.js +51 -0
  4. package/dist/src/artifacts/checksum-manifest.js +12 -0
  5. package/dist/src/artifacts/index-builder.js +11 -13
  6. package/dist/src/artifacts/query-engine.js +5 -11
  7. package/dist/src/cli/handlers/doctor-help.js +32 -0
  8. package/dist/src/cli/handlers/gates.js +19 -18
  9. package/dist/src/cli/handlers/models-help.js +7 -1
  10. package/dist/src/cli/handlers/models.js +3 -3
  11. package/dist/src/cli/handlers/script-runner.js +8 -5
  12. package/dist/src/cli/handlers/sessions-intake.js +104 -0
  13. package/dist/src/cli/handlers/sessions-tail.js +172 -0
  14. package/dist/src/cli/handlers/sessions.js +287 -31
  15. package/dist/src/cli/handlers/skill-lint.js +10 -3
  16. package/dist/src/cli/handlers/steward-format.js +100 -0
  17. package/dist/src/cli/handlers/steward-models.js +167 -0
  18. package/dist/src/cli/handlers/steward.js +14 -248
  19. package/dist/src/cli/handlers/use-bundle-counts.js +61 -0
  20. package/dist/src/cli/handlers/use.js +18 -28
  21. package/dist/src/cli/handlers/utilities.js +1 -24
  22. package/dist/src/config/aiwg-config.js +7 -0
  23. package/dist/src/config/authorization-cli.js +89 -0
  24. package/dist/src/config/cli-help.js +1 -0
  25. package/dist/src/config/cli.js +10 -1
  26. package/dist/src/config/worker-context.js +337 -0
  27. package/dist/src/decision/context-pruning.js +3 -2
  28. package/dist/src/decision/ensemble/contract.js +15 -4
  29. package/dist/src/decision/ensemble-study/artifacts.js +5 -0
  30. package/dist/src/decision/ensemble-study/score.js +4 -3
  31. package/dist/src/decision/feature-export.js +3 -9
  32. package/dist/src/decision/heldout/collector.js +2 -2
  33. package/dist/src/decision/issue-triage/runtime.js +3 -9
  34. package/dist/src/decision/qualification/gates.js +2 -1
  35. package/dist/src/decision/qualification/release.js +2 -3
  36. package/dist/src/decision/routing/report.js +2 -0
  37. package/dist/src/decision/sdlc-screening.js +3 -5
  38. package/dist/src/decision/sensitivity/comparative.js +5 -3
  39. package/dist/src/gates/driver.js +6 -77
  40. package/dist/src/gates/evaluate.js +4 -11
  41. package/dist/src/gates/floors.js +4 -4
  42. package/dist/src/gates/index.js +3 -3
  43. package/dist/src/gates/lattice.js +26 -0
  44. package/dist/src/gates/registry.js +2 -1
  45. package/dist/src/gates/report.js +19 -7
  46. package/dist/src/issues/audit-cli.js +120 -0
  47. package/dist/src/issues/audit-contract.js +64 -0
  48. package/dist/src/issues/audit-local.js +82 -0
  49. package/dist/src/issues/audit.js +220 -0
  50. package/dist/src/lint/rule-activation.js +15 -1
  51. package/dist/src/mcp/tools/worker-invoke.mjs +108 -10
  52. package/dist/src/mission-protocol/canonical-codecs.js +270 -0
  53. package/dist/src/mission-protocol/codecs.js +22 -550
  54. package/dist/src/mission-protocol/health-trace-codecs.js +281 -0
  55. package/dist/src/mission-protocol/health-trace-types.js +43 -0
  56. package/dist/src/mission-protocol/types.js +2 -42
  57. package/dist/src/mission-protocol/worker-contract-json.js +10 -0
  58. package/dist/src/mission-protocol/worker-review-gate.js +100 -0
  59. package/dist/src/mission-protocol/worker-review-types.js +2 -0
  60. package/dist/src/models/catalog-policy.js +280 -0
  61. package/dist/src/models/index.js +1 -1
  62. package/dist/src/models/model-capabilities.v1.json +78 -14
  63. package/dist/src/models/model-catalog.v1.json +62 -12
  64. package/dist/src/models/policy-resources.js +28 -0
  65. package/dist/src/models/provider-policy.js +10 -539
  66. package/dist/src/models/resolver.js +26 -8
  67. package/dist/src/models/router.js +15 -2
  68. package/dist/src/models/tiers.js +13 -0
  69. package/dist/src/models/types.js +0 -6
  70. package/dist/src/models/worker-ceilings.js +59 -0
  71. package/dist/src/models/worker-invocation-policy.js +243 -0
  72. package/dist/src/models/worker-plan.js +16 -20
  73. package/dist/src/models/worker-review-lineage.js +55 -0
  74. package/dist/src/models/worker-selection-policy.js +1 -1
  75. package/dist/src/models/wrapper-route.js +6 -3
  76. package/dist/src/policy/authorization.js +30 -1
  77. package/dist/src/policy/hitl-config.js +63 -0
  78. package/dist/src/policy/hitl-receipt.js +57 -0
  79. package/dist/src/policy/hitl-types.js +4 -0
  80. package/dist/src/policy/hitl-validation.js +39 -0
  81. package/dist/src/policy/hitl.js +117 -0
  82. package/dist/src/process/aiwg-probe-command.d.mts +15 -0
  83. package/dist/src/process/aiwg-probe-command.mjs +37 -0
  84. package/dist/src/rules/activation.d.mts +1 -1
  85. package/dist/src/rules/activation.mjs +0 -2
  86. package/dist/src/rules/gate-coverage.js +51 -0
  87. package/dist/src/rules/gate-references.js +16 -0
  88. package/dist/src/rules/rule-frontmatter.schema.json +7 -1
  89. package/dist/src/serve/worker-command-request.js +21 -4
  90. package/dist/src/serve/worker-invocation-preparation.js +3 -1
  91. package/dist/src/serve/worker-invocation.js +21 -10
  92. package/dist/src/sessions/adapters/deepseek-harness.js +1 -0
  93. package/dist/src/sessions/adapters/grok-build-native.js +269 -0
  94. package/dist/src/sessions/adapters/grok-build.js +57 -15
  95. package/dist/src/sessions/adapters/grokbot.js +7 -0
  96. package/dist/src/sessions/adapters/hermes-state-db.js +252 -0
  97. package/dist/src/sessions/adapters/hermes.js +42 -3
  98. package/dist/src/sessions/adapters/warp.js +1 -1
  99. package/dist/src/sessions/batch-import.js +44 -6
  100. package/dist/src/sessions/contracts.js +20 -1
  101. package/dist/src/sessions/coverage-preflight.js +7 -1
  102. package/dist/src/sessions/discovery-capability.js +38 -0
  103. package/dist/src/sessions/fortemi-export-mapping.js +33 -3
  104. package/dist/src/sessions/host-catalog.js +157 -0
  105. package/dist/src/sessions/image-blobs.js +141 -0
  106. package/dist/src/sessions/importer.js +9 -232
  107. package/dist/src/sessions/index.js +6 -0
  108. package/dist/src/sessions/intake-dir.js +71 -0
  109. package/dist/src/sessions/normalization.js +251 -0
  110. package/dist/src/sessions/refresh.js +25 -2
  111. package/dist/src/sessions/repository.js +164 -22
  112. package/dist/src/sessions/tail.js +91 -0
  113. package/dist/src/sessions/workspace-discovery.js +88 -9
  114. package/dist/src/skills/agent-skill-sidecar.js +28 -0
  115. package/dist/src/skills/agent-skills.js +4 -23
  116. package/dist/src/skills/claude-surface-projection.js +25 -0
  117. package/dist/src/skills/deployer.js +8 -288
  118. package/dist/src/skills/deployment-policy.js +114 -0
  119. package/dist/src/skills/deployment-projection.js +152 -0
  120. package/dist/src/skills/deployment-types.js +20 -0
  121. package/dist/src/skills/exporter.js +8 -31
  122. package/dist/src/skills/provider-extensions.js +41 -0
  123. package/dist/src/skills/run.js +6 -0
  124. package/dist/src/skills/types.js +0 -8
  125. package/dist/src/skills/validator-resources.js +68 -0
  126. package/dist/src/skills/validator.js +6 -55
  127. package/dist/src/storage/cli-migrate-options.js +125 -0
  128. package/dist/src/storage/cli-migrate.js +111 -0
  129. package/dist/src/storage/cli.js +4 -279
  130. package/dist/src/storage/migration-adapter.js +79 -0
  131. package/dist/src/storage/migration-copy.js +108 -0
  132. package/dist/src/storage/migration-protocol.js +14 -197
  133. package/dist/src/storage/migration-records.js +186 -0
  134. package/dist/src/storage/migration-types.js +12 -0
  135. package/dist/src/tracker/forge-http.js +2 -1
  136. package/dist/src/tracker/issue-pages.js +110 -0
  137. package/package.json +7 -1
  138. package/schemas/mission-v1.schema.json +335 -0
  139. package/schemas/models/model-catalog.v1.schema.json +19 -1
  140. package/schemas/models/model-config-compatibility.v1.schema.json +3 -2
  141. package/schemas/models/model-policy.v1.schema.json +1 -1
  142. package/tools/agents/providers/provider-paths-staging.mjs +35 -0
  143. package/tools/agents/providers/rule-binding-targets.mjs +146 -0
  144. package/tools/agents/providers/rule-delivery.mjs +7 -126
  145. package/tools/ralph-external/lib/muse-adapter.mjs +10 -0
  146. package/tools/ralph-external/lib/worker-context.mjs +237 -0
  147. package/tools/ralph-external/lib/worker-invocation-ancestry.mjs +132 -0
  148. package/tools/ralph-external/lib/worker-invocation-processes.mjs +123 -0
  149. package/tools/ralph-external/lib/worker-isolation-status.mjs +48 -0
  150. package/tools/ralph-external/lib/worker-isolation.mjs +17 -29
  151. package/tools/ralph-external/lib/worker-launch-cli.mjs +3 -1
  152. package/tools/ralph-external/lib/worker-overflow.mjs +48 -13
  153. package/tools/ralph-external/lib/worker-retry-evidence.mjs +103 -0
  154. package/tools/ralph-external/lib/worker-termination.mjs +82 -0
  155. package/tools/ralph-external/session-launcher.mjs +51 -96
  156. package/vscode-extension/schemas/aiwg.config.v1.json +177 -0
@@ -0,0 +1,25 @@
1
+ /** Inspection only: account-enabled skills are a separate delivery mechanism. */
2
+ export function projectClaudeSkillSurfaces(body) {
3
+ const shell = /!`[^`]+`/.test(body);
4
+ return ['cli', 'desktop-code', 'cowork', 'cloud'].map((surface) => {
5
+ const local = surface === 'cli' || surface === 'desktop-code';
6
+ const shellStatus = local ? 'native' : surface === 'cowork' ? 'degraded' : 'unsupported';
7
+ return {
8
+ provider: 'claude',
9
+ surface,
10
+ status: local ? 'native' : 'unsupported',
11
+ ...(shell ? { shellInterpolation: shellStatus } : {}),
12
+ reasons: [
13
+ local
14
+ ? 'Reads filesystem SKILL.md bundles from .claude/skills.'
15
+ : 'Does not read local .claude/skills; requires skills enabled on the claude.ai account.',
16
+ ...(shell ? [local
17
+ ? '! shell interpolation is native; AIWG does not execute it during validation or deploy.'
18
+ : surface === 'cowork'
19
+ ? '! shell interpolation is degraded to a policy notice for account-enabled Cowork skills.'
20
+ : '! shell interpolation from a local skill is unsupported on cloud.'] : []),
21
+ ],
22
+ };
23
+ });
24
+ }
25
+ //# sourceMappingURL=claude-surface-projection.js.map
@@ -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