* refactor(#1099): extract runtime artifact conversion module * docs(#1099): update runtime conversion inventory * docs(#1099): reconcile runtime conversion inventory count --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -130,6 +130,8 @@ build/
|
||||
/gsd-core/bin/lib/worktree-base-ref.cjs
|
||||
/gsd-core/bin/lib/worktree-safety.cjs
|
||||
/gsd-core/bin/lib/planning-workspace.cjs
|
||||
/gsd-core/bin/lib/command-roster.cjs
|
||||
/gsd-core/bin/lib/runtime-artifact-conversion.cjs
|
||||
/gsd-core/bin/lib/runtime-artifact-layout.cjs
|
||||
/gsd-core/bin/lib/runtime-config-adapter-registry.cjs
|
||||
/gsd-core/bin/lib/runtime-hooks-surface.cjs
|
||||
|
||||
@@ -139,6 +139,12 @@ Module owning which skills and agents are written to runtime config directories
|
||||
### Runtime Artifact Layout Module
|
||||
Module owning the per-runtime mapping from artifact kind to filesystem placement. ADR-3660 defines the typed `kinds` per runtime (`commands`, `agents`, `skills`) with destination subpath, prefix, and stage adapter (with per-runtime converters in `bin/install.js`: `convertClaudeCommandToClaudeSkill`, `…CodexSkill`, `…CopilotSkill`, `…AntigravitySkill`). Owns the per-runtime `nested` skill-bundle decision (#69): a `skillsKind` flag in `src/runtime-artifact-layout.cts` drives whether a runtime receives the nested router layout (6 `gsd-ns-*` routers + concrete skills under `<router>/skills/<name>/`) or the flat `skills/gsd-<stem>/` layout; the evidence/doc-link matrix is recorded in a comment above `resolveRuntimeArtifactLayout`. Phase 1 applies this seam to the Runtime Surface Module (`surface.cjs:applySurface`); as of #813, `applySurface` applies the same per-runtime skill-body path rewrites as `installRuntimeArtifacts` for `skills` kinds — re-surfacing no longer overwrites installed SKILL.md bodies with converter-default `~/.claude` paths. The shared accessor `getInstallExports` (exported from `runtime-artifact-layout.cjs`) is the single-source seam through which `surface.cjs` reaches `computePathPrefix` and `applyRuntimeContentRewritesInPlace`; the resolved `scope` (`'local'`|`'global'`) is now carried on the `Layout` object returned by `resolveRuntimeArtifactLayout` so `applySurface` derives the same `pathPrefix` (global `$HOME` form vs. absolute) as a fresh install. Phase 2 is planned to migrate install/uninstall in `bin/install.js` so all lifecycle sites iterate one shared layout table instead of re-encoding runtime layout logic. This design is intended to remove the #3659 class of omissions. Migrations remain under the Installer Migration Module (ADR-0008). See ADR-3660.
|
||||
|
||||
### Runtime Artifact Conversion Module
|
||||
Sibling Module to Runtime Artifact Layout Module. Owns projection from canonical Claude-authored command/agent/skill markdown into runtime-specific artifact bodies, including converter selection, frontmatter/body normalization, runtime path rewrites, and staged artifact generation. Runtime Artifact Layout remains responsible for filesystem placement (`kind`, destination subpath, prefix, nesting); Runtime Artifact Conversion owns the content Implementation behind that placement seam so install, uninstall/surface parity, and future plugin/package projections stop reaching back through `bin/install.js` for converter functions or `GSD_TEST_MODE`-guarded installer exports. Chosen direction: sibling Module, not an expanded Layout Module, to preserve ADR-3660's narrow placement responsibility while deepening artifact content locality. First slice: relocate only the layout-reached conversion family (`convertClaudeCommandTo*Skill`, converted command-file emitters, `buildKimiAgentArtifacts`) plus the minimal helper closure they need; do not leave helper dependencies in `bin/install.js` because that would preserve the same shallow seam under a new filename. Installer integration decision: `bin/install.js` imports the conversion Module at top level and re-exports the moved names for compatibility; the conversion Module must not import `bin/install.js` or Runtime Artifact Layout, so the dependency direction becomes installer/layout Adapters -> conversion Module, never conversion -> installer. First-slice Interface decision: export the existing compatibility names only; do not introduce a grouped `convertRuntimeArtifact` Interface until after relocation proves byte-for-byte behavior.
|
||||
|
||||
### Command Roster Module
|
||||
Tiny read-only helper Module owning discovery of canonical `commands/gsd/*.md` command stems for artifact conversion and runtime projection. It is a sibling dependency of Runtime Artifact Conversion Module, not part of conversion itself: conversion consumes a roster to safely rewrite `gsd:` / `/gsd-` references, while roster discovery owns filesystem/catalog knowledge. First slice: extract existing `readGsdCommandNames` behavior behind this Module instead of moving it into Runtime Artifact Conversion Module or keeping it as installer-owned state.
|
||||
|
||||
### Runtime Install Policy Module
|
||||
Projects a pure, typed install plan for a given runtime by composing artifact placements (Runtime Artifact Layout Module), command text (Shell Command Projection Module), and per-runtime config intentions — with no filesystem IO or format-specific serialization. Runtime-specific adapters consume the plan and execute concrete file mutations and config rendering. See ADR-58.
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ const {
|
||||
// fs.readdirSync + RegExp work for every skill.
|
||||
const {
|
||||
transformContentToHyphen,
|
||||
readCmdNames: readGsdCommandNames,
|
||||
} = require(path.join(__dirname, '..', 'scripts', 'fix-slash-commands.cjs'));
|
||||
readGsdCommandNames,
|
||||
} = require('../gsd-core/bin/lib/command-roster.cjs');
|
||||
const {
|
||||
resolveAntigravityGlobalDir,
|
||||
getGlobalConfigDir,
|
||||
@@ -38,6 +38,7 @@ const {
|
||||
readBaseRefFromSettings,
|
||||
} = require('../gsd-core/bin/lib/worktree-base-ref.cjs');
|
||||
const { resolveInstallPlan } = require('../gsd-core/bin/lib/runtime-config-adapter-registry.cjs');
|
||||
const runtimeArtifactConversion = require('../gsd-core/bin/lib/runtime-artifact-conversion.cjs');
|
||||
// Canonical set of hook files shipped to users. Imported here so writeManifest()
|
||||
// records exactly the same set that build-hooks.js copies to hooks/dist/, making
|
||||
// the manifest and the installed hooks/ dir structurally identical. Avoids the
|
||||
@@ -12281,6 +12282,7 @@ module.exports = {
|
||||
parseConfigDirFromArgs,
|
||||
cleanupLegacyGsdCc,
|
||||
_applyRuntimeRewrites,
|
||||
...runtimeArtifactConversion,
|
||||
};
|
||||
|
||||
// Main logic — only run when not loaded as a module for testing
|
||||
|
||||
@@ -284,6 +284,7 @@
|
||||
"code-review-flags.cjs",
|
||||
"command-aliases.cjs",
|
||||
"command-arg-projection.cjs",
|
||||
"command-roster.cjs",
|
||||
"command-routing-hub.cjs",
|
||||
"commands.cjs",
|
||||
"config-loader.cjs",
|
||||
@@ -344,6 +345,7 @@
|
||||
"roadmap-parser.cjs",
|
||||
"roadmap-upgrade.cjs",
|
||||
"roadmap.cjs",
|
||||
"runtime-artifact-conversion.cjs",
|
||||
"runtime-artifact-layout.cjs",
|
||||
"runtime-config-adapter-registry.cjs",
|
||||
"runtime-homes.cjs",
|
||||
|
||||
@@ -372,7 +372,7 @@ The `gsd-planner` agent is decomposed into a core agent plus reference modules t
|
||||
|
||||
---
|
||||
|
||||
## CLI Modules (110 shipped)
|
||||
## CLI Modules (112 shipped)
|
||||
|
||||
Full listing: `gsd-core/bin/lib/*.cjs`.
|
||||
|
||||
@@ -395,6 +395,7 @@ Full listing: `gsd-core/bin/lib/*.cjs`.
|
||||
| `code-review-flags.cjs` | Typed flag parser for `/gsd:code-review`; exports `parseCodeReviewFlags(argv)` (→ `{ fix, all, auto, depth, files }`) and `resolveCodeReviewWorkflow(flags)` (→ `'code-review.md' \| 'code-review-fix.md'`); canonical dispatch seam for `--fix`/`--all`/`--auto` routing |
|
||||
| `command-aliases.cjs` | Alias/subcommand metadata for manifest-backed family routers |
|
||||
| `command-arg-projection.cjs` | Typed flag and positional argument projection helpers shared across command-family routers |
|
||||
| `command-roster.cjs` | Read-only discovery of canonical `commands/gsd/*.md` command stems for runtime artifact conversion and namespace rewrites |
|
||||
| `command-routing-hub.cjs` | Pure-result dispatch hub that centralizes mode decision (SDK vs CJS), error taxonomy, and no-throw contract for all command-family routers (#3788) |
|
||||
| `commands.cjs` | Misc CLI commands (slug, timestamp, todos, scaffolding, stats) |
|
||||
| `config-loader.cjs` | Project config loading — defaults merge, legacy-key migration, workstream overlay, unknown-key/profile-override validation (extracted from `core.cjs`, ADR-857) |
|
||||
@@ -455,6 +456,7 @@ Full listing: `gsd-core/bin/lib/*.cjs`.
|
||||
| `roadmap-parser.cjs` | ROADMAP.md parsing — milestone slicing, current-milestone extraction, phase/milestone lookups, milestone-phase filter (extracted from `core.cjs`, ADR-857) |
|
||||
| `roadmap-upgrade.cjs` | Migration tool for converting legacy `Phase N` entries to milestone-prefixed `Phase M-NN` convention; `computeMigrationPlan` + `applyMigration` with dry-run default and atomic rollback |
|
||||
| `roadmap.cjs` | ROADMAP.md parsing, phase extraction, plan progress |
|
||||
| `runtime-artifact-conversion.cjs` | Runtime artifact conversion module — projects Claude-authored commands, agents, and skills into runtime-specific artifact bodies while preserving installer compatibility exports |
|
||||
| `runtime-artifact-layout.cjs` | Runtime artifact layout module — resolves the artifact directory shapes (commands, agents, skills) for each supported runtime; single source of truth for per-runtime artifact placement (#3663) |
|
||||
| `runtime-config-adapter-registry.cjs` | Explicit runtime config adapter registry — resolves per-runtime config-mutation install intent (install surface, shared-settings gate, finish-phase permission writer); see ADR-58. |
|
||||
| `runtime-hooks-surface.cjs` | Runtime hooks surface module — standalone hook-surface writer functions extracted from bin/install.js (ADR-857 phase 5f-1); owns Cline/Cursor/Copilot/Codex hook artifact generation and reconciliation. |
|
||||
|
||||
@@ -96,6 +96,8 @@ export default tseslint.config(
|
||||
'gsd-core/bin/lib/worktree-safety.cjs',
|
||||
'gsd-core/bin/lib/worktree-base-ref.cjs',
|
||||
'gsd-core/bin/lib/planning-workspace.cjs',
|
||||
'gsd-core/bin/lib/command-roster.cjs',
|
||||
'gsd-core/bin/lib/runtime-artifact-conversion.cjs',
|
||||
'gsd-core/bin/lib/runtime-artifact-layout.cjs',
|
||||
'gsd-core/bin/lib/runtime-config-adapter-registry.cjs',
|
||||
'gsd-core/bin/lib/runtime-hooks-surface.cjs',
|
||||
|
||||
29
src/command-roster.cts
Normal file
29
src/command-roster.cts
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Command Roster Module
|
||||
*
|
||||
* Read-only helper for discovering canonical commands/gsd command stems and
|
||||
* applying the shared GSD slash-command namespace transform.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const slashCommandTransformer = require('../../../scripts/fix-slash-commands.cjs') as {
|
||||
readCmdNames: () => string[];
|
||||
transformContentToHyphen: (src: string, cmdNames: string[]) => string;
|
||||
transformContent: (src: string, cmdNames: string[]) => string;
|
||||
buildPattern: (cmdNames: string[]) => RegExp | null;
|
||||
buildColonPattern: (cmdNames: string[]) => RegExp | null;
|
||||
};
|
||||
|
||||
function readGsdCommandNames(): string[] {
|
||||
return slashCommandTransformer.readCmdNames();
|
||||
}
|
||||
|
||||
export = {
|
||||
readGsdCommandNames,
|
||||
transformContentToHyphen: slashCommandTransformer.transformContentToHyphen,
|
||||
transformContent: slashCommandTransformer.transformContent,
|
||||
buildPattern: slashCommandTransformer.buildPattern,
|
||||
buildColonPattern: slashCommandTransformer.buildColonPattern,
|
||||
};
|
||||
2160
src/runtime-artifact-conversion.cts
Normal file
2160
src/runtime-artifact-conversion.cts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,11 @@ const {
|
||||
stageSkillsForRuntimeAsSkills,
|
||||
stageCommandsForRuntimeFlat,
|
||||
} = installProfiles;
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import runtimeArtifactConversion = require('./runtime-artifact-conversion.cjs');
|
||||
const conversionExports = runtimeArtifactConversion as Record<string, unknown> & {
|
||||
readGsdCommandNames?: () => string[];
|
||||
};
|
||||
|
||||
// In .cts (CommonJS output) files, `require` is available as a global.
|
||||
const _require: NodeRequire = require;
|
||||
@@ -33,7 +38,6 @@ const _require: NodeRequire = require;
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
interface InstallExports {
|
||||
readGsdCommandNames: () => string[];
|
||||
computePathPrefix: (opts: { isGlobal: boolean; isOpencode: boolean; isWindowsHost: boolean; resolvedTarget: string; homeDir: string }) => string;
|
||||
applyRuntimeContentRewritesInPlace: (stagedDir: string, runtime: string, pathPrefix: string) => void;
|
||||
[converterName: string]: unknown;
|
||||
@@ -194,8 +198,7 @@ function kimiAgentsKind(destSubpath: string, prefix: string, configDir: string):
|
||||
destSubpath,
|
||||
prefix,
|
||||
stage: (resolved) => {
|
||||
const installExports = getInstallExports();
|
||||
const buildKimiAgentArtifacts = installExports['buildKimiAgentArtifacts'] as (opts: {
|
||||
const buildKimiAgentArtifacts = conversionExports['buildKimiAgentArtifacts'] as (opts: {
|
||||
rootAgent?: string;
|
||||
subagents?: Array<{ path: string; content: string }>;
|
||||
}) => {
|
||||
@@ -237,7 +240,7 @@ function kimiAgentsKind(destSubpath: string, prefix: string, configDir: string):
|
||||
*
|
||||
* @param destSubpath
|
||||
* @param prefix
|
||||
* @param converterName name of converter function in bin/install.js exports
|
||||
* @param converterName name of converter function in Runtime Artifact Conversion exports
|
||||
* @param runtime canonical runtime ID (gates Hermes/Qwen branding in converter)
|
||||
* @param configDir runtime config dir (for .gsd-source marker resolution)
|
||||
* @param nested if true, nest concrete skills under their ns-* routers (#69)
|
||||
@@ -260,15 +263,16 @@ function skillsKind(
|
||||
destSubpath,
|
||||
prefix,
|
||||
stage: (resolved) => {
|
||||
const installExports = getInstallExports();
|
||||
const realConverter = installExports[converterName] as (content: string, skillName: string, runtime: string, cmdNames: string[], isGlobal: boolean) => string;
|
||||
const realConverter = conversionExports[converterName] as (content: string, skillName: string, runtime: string, cmdNames: string[], isGlobal: boolean) => string;
|
||||
// Compute cmdNames once per stage call for performance (#3583).
|
||||
// Extra trailing args are ignored by converters that don't need them. The
|
||||
// isGlobal flag is the 5th positional (NOT the 3rd): the 3rd positional is
|
||||
// `runtime` for the claude/kimi/cline converters, so the scope-aware
|
||||
// converters (antigravity, copilot) read isGlobal from position 5 to avoid
|
||||
// colliding with `runtime` and always taking the global branch.
|
||||
const cmdNames = installExports.readGsdCommandNames();
|
||||
const cmdNames = conversionExports.readGsdCommandNames
|
||||
? conversionExports.readGsdCommandNames()
|
||||
: [];
|
||||
const isGlobal = scope === 'global';
|
||||
const wrappedConverter = (content: string, skillName: string): string =>
|
||||
realConverter(content, skillName, runtime, cmdNames, isGlobal);
|
||||
@@ -282,7 +286,7 @@ function skillsKind(
|
||||
* commands directory with per-file conversion (e.g. Cursor 1.6 slash commands).
|
||||
*
|
||||
* Unlike `commandsKind` (which passes raw source files through), this kind
|
||||
* applies `converterName` from bin/install.js exports to each file during
|
||||
* applies `converterName` from Runtime Artifact Conversion exports to each file during
|
||||
* staging, writing flat `${prefix}${stem}.md` files to the staged directory.
|
||||
*
|
||||
* The staged files are then written by `_copyStaged` (commands branch) which
|
||||
@@ -290,7 +294,7 @@ function skillsKind(
|
||||
*
|
||||
* @param destSubpath destination subpath within configDir (e.g. 'commands')
|
||||
* @param prefix filename prefix, e.g. 'gsd-'
|
||||
* @param converterName name of converter function in bin/install.js exports
|
||||
* @param converterName name of converter function in Runtime Artifact Conversion exports
|
||||
* @param configDir runtime config dir (for .gsd-source marker resolution)
|
||||
*/
|
||||
function convertedCommandsKind(
|
||||
@@ -304,8 +308,7 @@ function convertedCommandsKind(
|
||||
destSubpath,
|
||||
prefix,
|
||||
stage: (resolved) => {
|
||||
const installExports = getInstallExports();
|
||||
const converter = installExports[converterName] as (content: string, commandName: string) => string;
|
||||
const converter = conversionExports[converterName] as (content: string, commandName: string) => string;
|
||||
return stageCommandsForRuntimeFlat(findInstallSourceRoot(configDir), resolved, converter, prefix);
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user