@opengsd/gsd-core 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +12 -0
- package/agents/gsd-executor.md +63 -35
- package/agents/gsd-plan-checker.md +76 -57
- package/agents/gsd-planner.md +14 -0
- package/agents/gsd-ui-checker.md +19 -3
- package/agents/gsd-ui-researcher.md +29 -0
- package/agents/gsd-verifier.md +23 -1
- package/bin/install.js +239 -67
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/ns-workflow.md +2 -1
- package/commands/gsd/phase.md +1 -1
- package/commands/gsd/quick-batch.md +105 -0
- package/commands/gsd/surface.md +18 -8
- package/gsd-core/bin/gsd-tools.cjs +195 -50
- package/gsd-core/bin/lib/capability-activation.cjs +27 -0
- package/gsd-core/bin/lib/capability-registry.cjs +514 -114
- package/gsd-core/bin/lib/capability-state.cjs +7 -1
- package/gsd-core/bin/lib/capability-validator.cjs +120 -4
- package/gsd-core/bin/lib/capability-writer.cjs +14 -4
- package/gsd-core/bin/lib/check-command-router.cjs +85 -2
- package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/command-aliases.cjs +16 -0
- package/gsd-core/bin/lib/commands.cjs +337 -13
- package/gsd-core/bin/lib/config-loader.cjs +3 -0
- package/gsd-core/bin/lib/core-utils.cjs +34 -7
- package/gsd-core/bin/lib/decisions.cjs +213 -1
- package/gsd-core/bin/lib/edge-probe.cjs +14 -1
- package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +137 -23
- package/gsd-core/bin/lib/gap-checker.cjs +22 -13
- package/gsd-core/bin/lib/git-base-branch.cjs +10 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +54 -11
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
- package/gsd-core/bin/lib/host-integration.cjs +57 -5
- package/gsd-core/bin/lib/init-command-router.cjs +14 -0
- package/gsd-core/bin/lib/init.cjs +132 -15
- package/gsd-core/bin/lib/install-engine.cjs +184 -12
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +45 -0
- package/gsd-core/bin/lib/install-profiles.cjs +22 -14
- package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
- package/gsd-core/bin/lib/io.cjs +35 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
- package/gsd-core/bin/lib/markdown-table.cjs +123 -0
- package/gsd-core/bin/lib/milestone.cjs +22 -2
- package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
- package/gsd-core/bin/lib/phase-id.cjs +251 -9
- package/gsd-core/bin/lib/phase.cjs +774 -35
- package/gsd-core/bin/lib/plan-document.cjs +10 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +147 -20
- package/gsd-core/bin/lib/planning-workspace.cjs +103 -28
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
- package/gsd-core/bin/lib/quick-batch.cjs +840 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +53 -5
- package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
- package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
- package/gsd-core/bin/lib/roadmap-parser.cjs +499 -26
- package/gsd-core/bin/lib/roadmap.cjs +187 -58
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +233 -33
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +286 -108
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +215 -43
- package/gsd-core/bin/lib/shell-command-projection.cjs +4 -0
- package/gsd-core/bin/lib/smart-entry.cjs +7 -9
- package/gsd-core/bin/lib/state-document.cjs +30 -5
- package/gsd-core/bin/lib/state-md-schema.cjs +23 -13
- package/gsd-core/bin/lib/state-transition.cjs +333 -44
- package/gsd-core/bin/lib/state.cjs +684 -125
- package/gsd-core/bin/lib/surface.cjs +23 -8
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
- package/gsd-core/bin/lib/uat.cjs +1419 -515
- package/gsd-core/bin/lib/update-context.cjs +6 -2
- package/gsd-core/bin/lib/validate.cjs +230 -12
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +273 -12
- package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
- package/gsd-core/bin/lib/verify.cjs +346 -16
- package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +8 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +8 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
- package/gsd-core/references/agent-contracts.md +3 -3
- package/gsd-core/references/edge-probe.md +17 -13
- package/gsd-core/references/execute-mvp-tdd.md +18 -16
- package/gsd-core/references/execute-phase-response-language.md +6 -0
- package/gsd-core/references/executor-examples.md +42 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
- package/gsd-core/references/mvp-concepts.md +2 -2
- package/gsd-core/references/plan-checker-examples.md +41 -0
- package/gsd-core/references/planner-antipatterns.md +25 -0
- package/gsd-core/references/planner-chunked.md +5 -1
- package/gsd-core/references/planner-coupling.md +42 -0
- package/gsd-core/references/planner-quick-batch.md +71 -0
- package/gsd-core/references/planner-reviews.md +47 -0
- package/gsd-core/references/planner-revision.md +75 -2
- package/gsd-core/references/planning-config.md +2 -1
- package/gsd-core/references/response-language-directive.md +9 -0
- package/gsd-core/references/revision-loop.md +118 -11
- package/gsd-core/references/tdd.md +14 -9
- package/gsd-core/references/verifier-evidence-gate.md +160 -0
- package/gsd-core/templates/phase-prompt.md +4 -0
- package/gsd-core/templates/verification-report.md +5 -0
- package/gsd-core/workflows/add-backlog.md +2 -0
- package/gsd-core/workflows/add-phase.md +2 -0
- package/gsd-core/workflows/add-tests.md +1 -1
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +1 -1
- package/gsd-core/workflows/analyze-dependencies.md +2 -0
- package/gsd-core/workflows/audit-fix.md +2 -0
- package/gsd-core/workflows/audit-milestone.md +2 -0
- package/gsd-core/workflows/audit-uat.md +2 -0
- package/gsd-core/workflows/autonomous.md +2 -0
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +15 -13
- package/gsd-core/workflows/code-review-fix.md +2 -0
- package/gsd-core/workflows/code-review.md +73 -31
- package/gsd-core/workflows/complete-milestone.md +13 -4
- package/gsd-core/workflows/debug.md +1 -1
- package/gsd-core/workflows/diagnose-issues.md +5 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/text.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase-power.md +2 -0
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +43 -13
- package/gsd-core/workflows/docs-update.md +1 -1
- package/gsd-core/workflows/edit-phase.md +2 -0
- package/gsd-core/workflows/eval-review.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +17 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +8 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
- package/gsd-core/workflows/execute-phase.md +32 -14
- package/gsd-core/workflows/execute-plan.md +8 -8
- package/gsd-core/workflows/explore.md +2 -0
- package/gsd-core/workflows/extract-learnings.md +2 -0
- package/gsd-core/workflows/fast.md +6 -0
- package/gsd-core/workflows/forensics.md +2 -0
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +1 -1
- package/gsd-core/workflows/help/modes/brief.md +2 -0
- package/gsd-core/workflows/help/modes/default.md +2 -0
- package/gsd-core/workflows/help/modes/full.md +12 -0
- package/gsd-core/workflows/help/modes/topic.md +2 -0
- package/gsd-core/workflows/help.md +2 -0
- package/gsd-core/workflows/import.md +3 -3
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +2 -0
- package/gsd-core/workflows/list-phase-assumptions.md +2 -0
- package/gsd-core/workflows/list-seeds.md +2 -0
- package/gsd-core/workflows/list-workspaces.md +2 -0
- package/gsd-core/workflows/manager.md +3 -3
- package/gsd-core/workflows/map-codebase.md +2 -0
- package/gsd-core/workflows/milestone-summary.md +2 -0
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +1 -1
- package/gsd-core/workflows/new-project.md +5 -3
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -0
- package/gsd-core/workflows/node-repair.md +2 -0
- package/gsd-core/workflows/note.md +2 -0
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +19 -4
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -0
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +9 -0
- package/gsd-core/workflows/plan-phase.md +130 -12
- package/gsd-core/workflows/plan-review-convergence.md +102 -10
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +11 -3
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
- package/gsd-core/workflows/progress.md +25 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +37 -2
- package/gsd-core/workflows/quick/steps/research-phase.md +3 -3
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
- package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
- package/gsd-core/workflows/quick-batch.md +203 -0
- package/gsd-core/workflows/quick.md +13 -3
- package/gsd-core/workflows/reapply-patches.md +2 -0
- package/gsd-core/workflows/remove-phase.md +2 -0
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +6 -2
- package/gsd-core/workflows/review.md +215 -10
- package/gsd-core/workflows/scan.md +2 -0
- package/gsd-core/workflows/section-manifest.json +12 -0
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/session-report.md +2 -0
- package/gsd-core/workflows/settings-advanced.md +2 -0
- package/gsd-core/workflows/settings-integrations.md +9 -8
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +10 -10
- package/gsd-core/workflows/sketch-wrap-up.md +2 -0
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/spec-phase.md +24 -19
- package/gsd-core/workflows/spike-wrap-up.md +2 -0
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +2 -0
- package/gsd-core/workflows/sync-skills.md +12 -4
- package/gsd-core/workflows/thread.md +2 -0
- package/gsd-core/workflows/transition.md +2 -0
- package/gsd-core/workflows/ui-phase.md +26 -5
- package/gsd-core/workflows/ui-review.md +1 -1
- package/gsd-core/workflows/ultraplan-phase.md +2 -0
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/update.md +41 -38
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-work.md +49 -3
- package/hooks/dist/gsd-check-update-worker.js +19 -2
- package/hooks/dist/gsd-context-monitor.js +283 -12
- package/hooks/dist/gsd-node-runner.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +30 -5
- package/hooks/dist/gsd-read-guard.js +2 -0
- package/hooks/dist/gsd-read-injection-scanner.js +5 -5
- package/hooks/dist/gsd-secret-read-guard.js +1079 -0
- package/hooks/dist/gsd-statusline.js +7 -3
- package/hooks/dist/gsd-validate-commit.sh +444 -7
- package/hooks/dist/gsd-workflow-guard.js +2 -1
- package/hooks/dist/lib/git-cmd.js +210 -1
- package/hooks/dist/lib/injection-patterns.js +36 -6
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-check-update-worker.js +19 -2
- package/hooks/gsd-context-monitor.js +283 -12
- package/hooks/gsd-node-runner.sh +1 -0
- package/hooks/gsd-prompt-guard.js +30 -5
- package/hooks/gsd-read-guard.js +2 -0
- package/hooks/gsd-read-injection-scanner.js +5 -5
- package/hooks/gsd-secret-read-guard.js +1079 -0
- package/hooks/gsd-statusline.js +7 -3
- package/hooks/gsd-validate-commit.sh +444 -7
- package/hooks/gsd-workflow-guard.js +2 -1
- package/hooks/hooks.json +6 -0
- package/hooks/lib/git-cmd.js +210 -1
- package/hooks/lib/injection-patterns.js +36 -6
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +5 -5
- package/scripts/build-hooks.js +11 -4
- package/scripts/ci-test-scope.cjs +7 -0
- package/scripts/docs-guard-registry.cjs +10 -0
- package/scripts/gen-loop-host-contract.cjs +67 -15
- package/scripts/lib/shellcheck-fetch.cjs +247 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +5 -0
- package/scripts/lint-phase-enumeration-drift.cjs +24 -6
- package/scripts/lint-phase-id-drift.cjs +133 -8
- package/scripts/lint-portable-grep.cjs +176 -0
- package/scripts/lint-response-language-coverage.cjs +524 -0
- package/scripts/lint-test-file-count.allowlist.json +3 -1
- package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
- package/scripts/lint-workflow-shellcheck.cjs +614 -0
- package/scripts/npm-audit-baseline.cjs +376 -0
- package/scripts/prompt-injection-scan.sh +8 -0
- package/scripts/require-issue-link-policy.cjs +16 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -1
- package/skills/gsd-ns-workflow/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +105 -0
- package/skills/gsd-surface/SKILL.md +18 -8
- package/vscode/package.json +1 -1
|
@@ -276,8 +276,22 @@ const kiloAgentPermissionOrder = [
|
|
|
276
276
|
'codesearch',
|
|
277
277
|
'lsp',
|
|
278
278
|
];
|
|
279
|
+
const kiloMcpPermissionPattern = /^mcp__([A-Za-z0-9_-]+)__((?:[A-Za-z0-9_-]+)|\*)$/;
|
|
280
|
+
/**
|
|
281
|
+
* Derive Kilo's native `{server}_{tool}` MCP permission key (kilo.ai/docs —
|
|
282
|
+
* external, fixed format we don't control). Not injective: both capture
|
|
283
|
+
* groups allow `_`, so e.g. `mcp__a_b__c` and `mcp__a__b_c` derive the same
|
|
284
|
+
* key. `buildKiloAgentPermissionBlock`'s `Set` resolves any such collision
|
|
285
|
+
* deterministically to first-seen-wins — see its regression test. Changing
|
|
286
|
+
* the derivation to avoid the collision isn't an option: Kilo's own runtime
|
|
287
|
+
* only recognizes this exact key shape.
|
|
288
|
+
*/
|
|
279
289
|
function convertClaudeToKiloPermissionTool(claudeTool) {
|
|
280
|
-
|
|
290
|
+
const builtinPermission = claudeToKiloAgentPermissions[claudeTool];
|
|
291
|
+
if (builtinPermission)
|
|
292
|
+
return builtinPermission;
|
|
293
|
+
const mcpPermission = kiloMcpPermissionPattern.exec(claudeTool);
|
|
294
|
+
return mcpPermission ? `${mcpPermission[1]}_${mcpPermission[2]}` : null;
|
|
281
295
|
}
|
|
282
296
|
function buildKiloAgentPermissionBlock(claudeTools) {
|
|
283
297
|
const allowedPermissions = new Set();
|
|
@@ -291,6 +305,11 @@ function buildKiloAgentPermissionBlock(claudeTools) {
|
|
|
291
305
|
for (const permission of kiloAgentPermissionOrder) {
|
|
292
306
|
lines.push(` ${permission}: ${allowedPermissions.has(permission) ? 'allow' : 'deny'}`);
|
|
293
307
|
}
|
|
308
|
+
for (const permission of allowedPermissions) {
|
|
309
|
+
if (kiloAgentPermissionOrder.includes(permission))
|
|
310
|
+
continue;
|
|
311
|
+
lines.push(` ${permission}: allow`);
|
|
312
|
+
}
|
|
294
313
|
return lines;
|
|
295
314
|
}
|
|
296
315
|
function replaceRelativePathReference(content, fromPath, toPath) {
|
|
@@ -645,6 +664,137 @@ function convertClaudeCommandToKimiCodeSkill(content, skillName, _runtime = null
|
|
|
645
664
|
return convertClaudeCommandToKimiSkill(content, skillName, _runtime, cmdNames);
|
|
646
665
|
}
|
|
647
666
|
const KIMI_CANONICAL_GSD_AGENT_RE = /^gsd-[a-z0-9-]+$/;
|
|
667
|
+
/** Split a `tools:` comma list without tearing a quoted scalar that contains a literal comma. */
|
|
668
|
+
function splitToolScalars(text) {
|
|
669
|
+
const parts = [];
|
|
670
|
+
let current = '';
|
|
671
|
+
let quote = null;
|
|
672
|
+
for (const ch of text) {
|
|
673
|
+
if (quote) {
|
|
674
|
+
current += ch;
|
|
675
|
+
if (ch === quote)
|
|
676
|
+
quote = null;
|
|
677
|
+
}
|
|
678
|
+
else if (ch === '"' || ch === "'") {
|
|
679
|
+
quote = ch;
|
|
680
|
+
current += ch;
|
|
681
|
+
}
|
|
682
|
+
else if (ch === ',') {
|
|
683
|
+
parts.push(current);
|
|
684
|
+
current = '';
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
current += ch;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
parts.push(current);
|
|
691
|
+
return parts;
|
|
692
|
+
}
|
|
693
|
+
/** Normalize one complete frontmatter tool scalar through the shared YAML parser. */
|
|
694
|
+
function decodeToolScalar(raw) {
|
|
695
|
+
if (typeof raw !== 'string')
|
|
696
|
+
return null;
|
|
697
|
+
const value = raw.trim();
|
|
698
|
+
if (!value)
|
|
699
|
+
return null;
|
|
700
|
+
if (value.startsWith('"') || value.startsWith("'")) {
|
|
701
|
+
try {
|
|
702
|
+
const decoded = frontmatterModule.parseFrontmatter('---\ntool: ' + value + '\n---\n').tool;
|
|
703
|
+
return typeof decoded === 'string' && decoded.trim() ? decoded.trim() : null;
|
|
704
|
+
}
|
|
705
|
+
catch {
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
// A bare (unquoted) scalar may carry a trailing ` # comment` (YAML requires
|
|
710
|
+
// whitespace before `#` to start a comment) — every caller here passes a
|
|
711
|
+
// single already-comma-split token, never the whole `tools:` line, so this
|
|
712
|
+
// is safe to strip unconditionally rather than pushing the concern onto
|
|
713
|
+
// each call site. Strip BEFORE the malformed-quote check below: a comment
|
|
714
|
+
// may itself contain a `"`/`'` (e.g. `Bash # note: "internal"`), which is
|
|
715
|
+
// not a real YAML quote delimiter and must not cause a false rejection.
|
|
716
|
+
const commentIndex = value.search(/[ \t]#/);
|
|
717
|
+
const stripped = commentIndex === -1 ? value : value.slice(0, commentIndex).trimEnd();
|
|
718
|
+
if (!stripped)
|
|
719
|
+
return null;
|
|
720
|
+
if (stripped.endsWith('"') || stripped.endsWith("'"))
|
|
721
|
+
return null;
|
|
722
|
+
return stripped;
|
|
723
|
+
}
|
|
724
|
+
/** Append validated canonical grants without reserializing unrelated frontmatter. */
|
|
725
|
+
function appendAgentTools(content, grants) {
|
|
726
|
+
if (grants.length === 0)
|
|
727
|
+
return content;
|
|
728
|
+
const eol = content.includes('\r\n') ? '\r\n' : '\n';
|
|
729
|
+
const lines = content.split(eol);
|
|
730
|
+
if (lines[0] !== '---')
|
|
731
|
+
return content;
|
|
732
|
+
const frontmatterEnd = lines.indexOf('---', 1);
|
|
733
|
+
if (frontmatterEnd === -1)
|
|
734
|
+
return content;
|
|
735
|
+
const toolsIndex = lines.findIndex((line, index) => index < frontmatterEnd && /^tools:[ \t]*(.*)$/.test(line));
|
|
736
|
+
if (toolsIndex === -1)
|
|
737
|
+
return content;
|
|
738
|
+
const toolsMatch = /^tools:[ \t]*(.*)$/.exec(lines[toolsIndex]);
|
|
739
|
+
if (!toolsMatch)
|
|
740
|
+
return content;
|
|
741
|
+
// Plain (non-leading-quote) YAML scalars have no internal quoting — a `#`
|
|
742
|
+
// after whitespace is a real comment start regardless of nearby quote
|
|
743
|
+
// characters (verified: real YAML truncates `Read, "x #1"` at the space
|
|
744
|
+
// before `#` too), so this scan does not need to be quote-aware. The one
|
|
745
|
+
// case that DOES need protection — a value that IS a leading quoted scalar
|
|
746
|
+
// — is refused outright below rather than parsed past.
|
|
747
|
+
const commentIndex = toolsMatch[1].search(/[ \t]#/);
|
|
748
|
+
let inlineValue = commentIndex === -1 ? toolsMatch[1] : toolsMatch[1].slice(0, commentIndex);
|
|
749
|
+
let inlineComment = commentIndex === -1 ? '' : toolsMatch[1].slice(commentIndex);
|
|
750
|
+
// A header that is ONLY a comment (`tools: # note`) has no leading space in
|
|
751
|
+
// the captured group — the outer regex's `[ \t]*` already consumed it — so
|
|
752
|
+
// the `[ \t]#` scan above never fires. Reclassify as no inline value so the
|
|
753
|
+
// block-list scan below runs instead of swallowing the comment as content.
|
|
754
|
+
if (inlineValue.trim().startsWith('#')) {
|
|
755
|
+
inlineComment = toolsMatch[1];
|
|
756
|
+
inlineValue = '';
|
|
757
|
+
}
|
|
758
|
+
// A value that STARTS with a quote is a YAML quoted scalar occupying the
|
|
759
|
+
// whole node — nothing may follow it on the same line except a comment
|
|
760
|
+
// (`tools: "Bash"` is valid; `tools: "Bash", Read` is not, even before this
|
|
761
|
+
// function touches it). Appending in place would corrupt otherwise-valid
|
|
762
|
+
// frontmatter, so refuse rather than emit invalid YAML. A value that STARTS
|
|
763
|
+
// with `[` is a YAML flow sequence (`tools: [Bash, Read]`) — its own commas
|
|
764
|
+
// are node-internal, not scalar separators, and content cannot follow its
|
|
765
|
+
// closing `]` on the same line either, so the same refusal applies.
|
|
766
|
+
if (/^["'[]/.test(inlineValue.trim()))
|
|
767
|
+
return content;
|
|
768
|
+
const existing = [];
|
|
769
|
+
let insertAt = toolsIndex + 1;
|
|
770
|
+
if (inlineValue.trim()) {
|
|
771
|
+
existing.push(...splitToolScalars(inlineValue).map(decodeToolScalar).filter((value) => value !== null));
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
while (insertAt < frontmatterEnd) {
|
|
775
|
+
const item = /^([ \t]+)-[ \t]*(\S.*)$/.exec(lines[insertAt]);
|
|
776
|
+
if (!item)
|
|
777
|
+
break;
|
|
778
|
+
const decoded = decodeToolScalar(item[2]);
|
|
779
|
+
if (decoded !== null)
|
|
780
|
+
existing.push(decoded);
|
|
781
|
+
insertAt += 1;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
const present = new Set(existing);
|
|
785
|
+
const additions = grants.filter((grant) => !present.has(grant) && (present.add(grant), true));
|
|
786
|
+
if (additions.length === 0)
|
|
787
|
+
return content;
|
|
788
|
+
if (inlineValue.trim()) {
|
|
789
|
+
lines[toolsIndex] = `tools: ${inlineValue.trimEnd()}, ${additions.join(', ')}${inlineComment}`;
|
|
790
|
+
}
|
|
791
|
+
else {
|
|
792
|
+
const firstItem = /^([ \t]+)-/.exec(lines[toolsIndex + 1]);
|
|
793
|
+
const indent = firstItem ? firstItem[1] : ' ';
|
|
794
|
+
lines.splice(insertAt, 0, ...additions.map((grant) => `${indent}- ${JSON.stringify(grant)}`));
|
|
795
|
+
}
|
|
796
|
+
return lines.join(eol);
|
|
797
|
+
}
|
|
648
798
|
function parseKimiAgentSource(source) {
|
|
649
799
|
if (typeof source === 'string') {
|
|
650
800
|
return {
|
|
@@ -672,7 +822,9 @@ function parseFrontmatterTools(frontmatter) {
|
|
|
672
822
|
continue;
|
|
673
823
|
if (collecting) {
|
|
674
824
|
if (trimmed.startsWith('- ')) {
|
|
675
|
-
|
|
825
|
+
const tool = decodeToolScalar(trimmed.slice(2));
|
|
826
|
+
if (tool !== null)
|
|
827
|
+
tools.push(tool);
|
|
676
828
|
continue;
|
|
677
829
|
}
|
|
678
830
|
collecting = false;
|
|
@@ -683,10 +835,13 @@ function parseFrontmatterTools(frontmatter) {
|
|
|
683
835
|
}
|
|
684
836
|
if (trimmed.startsWith('tools:') || trimmed.startsWith('allowed-tools:')) {
|
|
685
837
|
const value = trimmed.slice(trimmed.indexOf(':') + 1).trim();
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
838
|
+
// A comment-only value (`tools: # note`) has no real inline content —
|
|
839
|
+
// fall through to the block-list scan below instead of decoding the
|
|
840
|
+
// comment text as a bogus tool name and silently dropping the list.
|
|
841
|
+
if (value && !value.startsWith('#')) {
|
|
842
|
+
for (const tool of splitToolScalars(value)) {
|
|
843
|
+
const name = decodeToolScalar(tool);
|
|
844
|
+
if (name !== null)
|
|
690
845
|
tools.push(name);
|
|
691
846
|
}
|
|
692
847
|
}
|
|
@@ -1623,26 +1778,37 @@ Execute mode fallback:
|
|
|
1623
1778
|
## C. Task() → spawn_agent Mapping
|
|
1624
1779
|
GSD workflows use \`Task(...)\` (Claude Code syntax). Translate to Codex collaboration tools:
|
|
1625
1780
|
|
|
1626
|
-
**Schema detection (required first step):**
|
|
1627
|
-
|
|
1628
|
-
|
|
1781
|
+
**Schema detection (required first step):** Before spawning, inspect the \`spawn_agent\`
|
|
1782
|
+
tool's visible parameter schema (via \`tool_search\` or the tool list). Use the presence
|
|
1783
|
+
of \`agent_type\` only to choose typed dispatch versus the generic-agent workaround.
|
|
1784
|
+
Detect optional fields independently: \`model\`, \`reasoning_effort\`, \`task_name\`,
|
|
1785
|
+
\`fork_turns\`, and \`fork_context\` may be added or removed without \`agent_type\` changing.
|
|
1786
|
+
Never infer one field from a schema/version label or from the presence of another field.
|
|
1629
1787
|
|
|
1630
|
-
|
|
1788
|
+
- **agent_type-capable schema:** \`spawn_agent\` advertises \`agent_type\` — typed GSD agent dispatch is available.
|
|
1789
|
+
- **Generic schema:** \`spawn_agent\` does not advertise \`agent_type\` — typed GSD agent dispatch is unavailable in this session, even if other optional fields are present.
|
|
1631
1790
|
|
|
1632
1791
|
Typed mapping (agent_type-capable schema only):
|
|
1633
1792
|
- \`Task(subagent_type="X", prompt="Y")\` → \`spawn_agent(agent_type="X", message="Y")\`
|
|
1634
1793
|
- \`Agent(subagent_type="X", prompt="Y")\` → \`spawn_agent(agent_type="X", message="Y")\`
|
|
1635
|
-
- \`Task(model="
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1794
|
+
- \`Task(model="{resolved_model}")\` → pass \`model="{resolved_model}"\` when the
|
|
1795
|
+
visible \`spawn_agent\` schema advertises \`model\` and the resolved value is explicit.
|
|
1796
|
+
This is how \`model_profile\` tier routing, including \`adaptive\`, reaches the child agent.
|
|
1797
|
+
Omit \`model\` only when the schema does not advertise \`model\`, or when the value is
|
|
1798
|
+
missing, empty, or \`"inherit"\`; omission deliberately inherits the session/static agent
|
|
1799
|
+
configuration. Explicit \`model_overrides\` may also be embedded in agent \`.toml\` files,
|
|
1800
|
+
but ordinary profile-resolved models are not, so a TOML file is not a reason to discard
|
|
1801
|
+
an available inline value.
|
|
1802
|
+
- Before each typed spawn, obtain the paired effort for its role with
|
|
1803
|
+
\`gsd_run query resolve-model <subagent_type> --pick effort\` when the workflow has not
|
|
1804
|
+
already exposed it. The resolver's unified \`effort\` field maps to the Codex spawn argument
|
|
1805
|
+
\`reasoning_effort\`; do not look for a resolver field named \`reasoning_effort\`.
|
|
1806
|
+
Pass it when the visible \`spawn_agent\` schema advertises \`reasoning_effort\`. Omit the
|
|
1807
|
+
field when it is not advertised, or when the value is missing, empty, \`"inherit"\`, or
|
|
1808
|
+
unsupported; do not invent one-off effort literals in workflow prose.
|
|
1643
1809
|
- \`fork_context: false\` by default — GSD agents load their own context via \`<required_reading>\` blocks
|
|
1644
|
-
- \`task_name\` —
|
|
1645
|
-
- \`fork_turns\` —
|
|
1810
|
+
- \`task_name\` — when advertised, provide a descriptive name for each spawned task
|
|
1811
|
+
- \`fork_turns\` — when advertised, controls turn-forking depth; coexists with \`fork_context\` (not a replacement)
|
|
1646
1812
|
- \`Task(isolation="worktree")\` / \`Agent(isolation="worktree")\` → no direct \`spawn_agent\` mapping,
|
|
1647
1813
|
but Codex declares \`dispatch.isolation: orchestrator-worktree\` (#2584). Codex
|
|
1648
1814
|
\`spawn_agent\` still does not create or bind a git worktree; instead GSD itself
|
|
@@ -1948,7 +2114,9 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
|
|
|
1948
2114
|
}
|
|
1949
2115
|
if (isAgent && inAgentTools) {
|
|
1950
2116
|
if (trimmed.startsWith('- ')) {
|
|
1951
|
-
|
|
2117
|
+
const tool = decodeToolScalar(trimmed.substring(2));
|
|
2118
|
+
if (tool !== null)
|
|
2119
|
+
agentTools.push(tool);
|
|
1952
2120
|
continue;
|
|
1953
2121
|
}
|
|
1954
2122
|
if (trimmed && !trimmed.startsWith('-')) {
|
|
@@ -1959,8 +2127,11 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
|
|
|
1959
2127
|
if (trimmed.startsWith('tools:')) {
|
|
1960
2128
|
if (isAgent) {
|
|
1961
2129
|
const toolsValue = trimmed.substring(6).trim();
|
|
1962
|
-
|
|
1963
|
-
|
|
2130
|
+
// A comment-only value (`tools: # note`) is not real inline content —
|
|
2131
|
+
// fall through to the block-list scan (`inAgentTools`) instead of
|
|
2132
|
+
// decoding the comment as a bogus tool name and dropping the list.
|
|
2133
|
+
if (toolsValue && !toolsValue.startsWith('#')) {
|
|
2134
|
+
const tools = splitToolScalars(toolsValue).map(decodeToolScalar).filter((tool) => tool !== null);
|
|
1964
2135
|
agentTools.push(...tools);
|
|
1965
2136
|
}
|
|
1966
2137
|
else {
|
|
@@ -2022,7 +2193,9 @@ function convertClaudeToKiloFrontmatter(content, { isAgent = false, modelOverrid
|
|
|
2022
2193
|
if (trimmed.startsWith('- ')) {
|
|
2023
2194
|
const tool = trimmed.substring(2).trim();
|
|
2024
2195
|
if (isAgent) {
|
|
2025
|
-
|
|
2196
|
+
const decoded = decodeToolScalar(tool);
|
|
2197
|
+
if (decoded !== null)
|
|
2198
|
+
agentTools.push(decoded);
|
|
2026
2199
|
}
|
|
2027
2200
|
else {
|
|
2028
2201
|
allowedTools.push(tool);
|
|
@@ -2355,11 +2528,16 @@ function convertClaudeAgentToQwenAgent(content) {
|
|
|
2355
2528
|
* Byte-identical for an agent with no `mcp__*` grants (the common case) and
|
|
2356
2529
|
* for an agent with no frontmatter at all.
|
|
2357
2530
|
*/
|
|
2531
|
+
/** Fail-closed: an undecodable scalar is dropped, never kept (ZCode's contract is "never emit mcp__*"). */
|
|
2532
|
+
function zcodeKeepsGrant(rawTool) {
|
|
2533
|
+
const decoded = decodeToolScalar(rawTool);
|
|
2534
|
+
return decoded !== null && !decoded.startsWith('mcp__');
|
|
2535
|
+
}
|
|
2358
2536
|
function convertClaudeAgentToZcodeAgent(content) {
|
|
2359
|
-
//
|
|
2360
|
-
//
|
|
2361
|
-
//
|
|
2362
|
-
if (!content.includes('mcp__'))
|
|
2537
|
+
// A double-quoted YAML scalar may encode the leading "m" in mcp__ as an
|
|
2538
|
+
// escape, so only skip the shared scalar-decoder scan when neither form is
|
|
2539
|
+
// present. The unchanged scan below still preserves byte-identical content.
|
|
2540
|
+
if (!content.includes('mcp__') && !content.includes('\\'))
|
|
2363
2541
|
return content;
|
|
2364
2542
|
const lines = content.split('\n');
|
|
2365
2543
|
if (lines[0] !== '---')
|
|
@@ -2379,9 +2557,14 @@ function convertClaudeAgentToZcodeAgent(content) {
|
|
|
2379
2557
|
while (i < fmEnd) {
|
|
2380
2558
|
const line = lines[i];
|
|
2381
2559
|
const inlineTools = /^tools:[ \t]*(.+)$/.exec(line);
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2560
|
+
// A header that is ONLY a comment (`tools: # note`) is not real inline
|
|
2561
|
+
// content — fall through to the block-list scan below instead of
|
|
2562
|
+
// matching here, or a following block list's mcp__* items never get
|
|
2563
|
+
// scanned and leak through unstripped.
|
|
2564
|
+
const commentOnlyHeader = inlineTools !== null && inlineTools[1].trim().startsWith('#');
|
|
2565
|
+
if (inlineTools && !commentOnlyHeader) {
|
|
2566
|
+
const grants = splitToolScalars(inlineTools[1]).map((tool) => tool.trim()).filter((tool) => tool !== '');
|
|
2567
|
+
const kept = grants.filter((tool) => zcodeKeepsGrant(tool));
|
|
2385
2568
|
if (kept.length === grants.length) {
|
|
2386
2569
|
out.push(line); // no mcp__* grants — keep the line byte-identical
|
|
2387
2570
|
}
|
|
@@ -2395,7 +2578,7 @@ function convertClaudeAgentToZcodeAgent(content) {
|
|
|
2395
2578
|
i++;
|
|
2396
2579
|
continue;
|
|
2397
2580
|
}
|
|
2398
|
-
if (/^tools:[ \t]*$/.test(line)) {
|
|
2581
|
+
if (/^tools:[ \t]*$/.test(line) || commentOnlyHeader) {
|
|
2399
2582
|
// Block-list form: collect the following `- item` lines.
|
|
2400
2583
|
const items = [];
|
|
2401
2584
|
let j = i + 1;
|
|
@@ -2405,7 +2588,7 @@ function convertClaudeAgentToZcodeAgent(content) {
|
|
|
2405
2588
|
}
|
|
2406
2589
|
const kept = items.filter((item) => {
|
|
2407
2590
|
const name = /^([ \t]*)-[ \t]*(\S.*)$/.exec(item)[2].trim();
|
|
2408
|
-
return
|
|
2591
|
+
return zcodeKeepsGrant(name);
|
|
2409
2592
|
});
|
|
2410
2593
|
if (kept.length !== items.length) {
|
|
2411
2594
|
changed = true;
|
|
@@ -2940,6 +3123,20 @@ function _applyRuntimeRewrites(content, runtime, pathPrefix, isGlobal = false, a
|
|
|
2940
3123
|
content = content.replace(/\.\/\.claude\b/g, `./${dirName}`);
|
|
2941
3124
|
content = processAttribution(content, attribution);
|
|
2942
3125
|
break;
|
|
3126
|
+
case 'zcode':
|
|
3127
|
+
// #4002: ZCode is a Claude-Code-shaped host (dot-home `.zcode`, `@~`-ref
|
|
3128
|
+
// expansion, `~/.zcode/...` documented paths) whose commands install with
|
|
3129
|
+
// `converter: null` — this pass is their only chance to receive
|
|
3130
|
+
// runtime-correct paths. Same shape as `claude`, including the tilde
|
|
3131
|
+
// restore: the tilde form is what ZCode expands and what its docs use.
|
|
3132
|
+
// `${_GSD_RUNTIME_ROOT}/.claude/…` matches none of these regexes and
|
|
3133
|
+
// survives as the project-local fallback, exactly as on every sibling.
|
|
3134
|
+
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
3135
|
+
content = content.replace(/\$HOME\/\.claude\//g, pathPrefix);
|
|
3136
|
+
content = content.replace(/\.\/\.claude\//g, `./${dirName}/`);
|
|
3137
|
+
content = restoreClaudeGlobalAtRefTilde(content, pathPrefix);
|
|
3138
|
+
content = processAttribution(content, attribution);
|
|
3139
|
+
break;
|
|
2943
3140
|
default:
|
|
2944
3141
|
// Unknown runtime — no rewrites (OpenCode/Kilo handled by their own install path).
|
|
2945
3142
|
break;
|
|
@@ -3364,6 +3561,7 @@ function processAttribution(content, attribution) {
|
|
|
3364
3561
|
}
|
|
3365
3562
|
module.exports = {
|
|
3366
3563
|
processAttribution,
|
|
3564
|
+
appendAgentTools,
|
|
3367
3565
|
// #2103: public accessor for hostBehaviors.agentFileExtension, exported so
|
|
3368
3566
|
// surface.cts's _syncGsdDir can derive the .agent.md rename from the SAME
|
|
3369
3567
|
// descriptor read as install-engine.cts (folds a duplicated hardcoded
|
|
@@ -3420,6 +3618,8 @@ module.exports = {
|
|
|
3420
3618
|
// opencode/kilo command install through the engine instead of the bespoke path).
|
|
3421
3619
|
convertClaudeToOpencodeFrontmatter,
|
|
3422
3620
|
convertClaudeToKiloFrontmatter,
|
|
3621
|
+
_decodeToolScalar: decodeToolScalar,
|
|
3622
|
+
_splitToolScalars: splitToolScalars,
|
|
3423
3623
|
readGsdCommandNames,
|
|
3424
3624
|
transformContentToHyphen,
|
|
3425
3625
|
// #1383: version resolver (exported for regression test of the Codex
|
|
@@ -51,7 +51,7 @@ function addCleanupDir(cleanupDirs, stagedDir, rewrittenDir) {
|
|
|
51
51
|
return sourceDir;
|
|
52
52
|
}
|
|
53
53
|
function createRuntimeArtifactInstallPlan(args) {
|
|
54
|
-
const { layout, resolvedProfile, homedir, platform, resolveAttribution, deps = {}, } = args;
|
|
54
|
+
const { layout, resolvedProfile, homedir, platform, resolveAttribution, projectDir, deps = {}, } = args;
|
|
55
55
|
const conversionExports = _require('./runtime-artifact-conversion.cjs');
|
|
56
56
|
const rewriteStagedSkillBodies = deps.rewriteStagedSkillBodies ?? conversionExports.rewriteStagedSkillBodies;
|
|
57
57
|
const rewriteStagedCommandBodies = deps.rewriteStagedCommandBodies ?? conversionExports.rewriteStagedCommandBodies;
|
|
@@ -66,11 +66,10 @@ function createRuntimeArtifactInstallPlan(args) {
|
|
|
66
66
|
platform,
|
|
67
67
|
resolveAttribution,
|
|
68
68
|
};
|
|
69
|
-
// ADR-1235 §1: build
|
|
70
|
-
// the CORRECT pre-converter cross-cutting (path rewrites → attribution →
|
|
71
|
-
// → normalize). This
|
|
72
|
-
//
|
|
73
|
-
// to kind.stage() for agents kind entries with a converter (convertedAgentsKind).
|
|
69
|
+
// ADR-1235 §1: build the staging context once per plan. Agent kinds apply
|
|
70
|
+
// the CORRECT pre-converter cross-cutting (path rewrites → attribution →
|
|
71
|
+
// converter → normalize). This
|
|
72
|
+
// mirrors the exact per-file order in the former inline agent loop.
|
|
74
73
|
// NO _stampNonClaudeRuntimeDefaults — agents are NOT stamped in the inline loop.
|
|
75
74
|
const os = _require('node:os');
|
|
76
75
|
const { posixNormalize } = _require('./shell-command-projection.cjs');
|
|
@@ -88,19 +87,19 @@ function createRuntimeArtifactInstallPlan(args) {
|
|
|
88
87
|
const attribution = resolveAttribution ? resolveAttribution(layout.runtime) : undefined;
|
|
89
88
|
// #2875 Part 2 (row I1): layout.configDir IS the install root the inline
|
|
90
89
|
// agent loop called `targetDir` — same value, same resolution.
|
|
91
|
-
const agentCtx = {
|
|
90
|
+
const agentCtx = {
|
|
91
|
+
runtime: layout.runtime,
|
|
92
|
+
pathPrefix,
|
|
93
|
+
attribution,
|
|
94
|
+
targetDir: layout.configDir,
|
|
95
|
+
projectDir: projectDir ?? layout.configDir,
|
|
96
|
+
};
|
|
92
97
|
for (const kind of layout.kinds) {
|
|
93
98
|
let stagedDir;
|
|
94
99
|
try {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// The cross-cutting is now PRE-converter (inside staging), not POST.
|
|
99
|
-
stagedDir = kind.stage(resolvedProfile, agentCtx);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
stagedDir = kind.stage(resolvedProfile);
|
|
103
|
-
}
|
|
100
|
+
// Agent kinds use the context for their pre-converter cross-cutting
|
|
101
|
+
// sequence; other kinds ignore it.
|
|
102
|
+
stagedDir = kind.stage(resolvedProfile, agentCtx);
|
|
104
103
|
}
|
|
105
104
|
catch (err) {
|
|
106
105
|
return { ok: false, kind: 'stage_failed', message: errorMessage(err), cleanupDirs, failedKind: kind.kind };
|
|
@@ -115,7 +114,7 @@ function createRuntimeArtifactInstallPlan(args) {
|
|
|
115
114
|
const rewrittenDir = rewriteStagedSkillBodies(stagedDir, rewriteOpts);
|
|
116
115
|
sourceDir = addCleanupDir(cleanupDirs, stagedDir, rewrittenDir);
|
|
117
116
|
}
|
|
118
|
-
//
|
|
117
|
+
// Agent kinds: cross-cutting already applied INSIDE kind.stage() via agentCtx.
|
|
119
118
|
// No POST-step needed. sourceDir stays as stagedDir.
|
|
120
119
|
}
|
|
121
120
|
catch (err) {
|