sdtk-kit 0.3.2 → 0.3.4
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/README.md +40 -3
- package/assets/manifest/toolkit-bundle.manifest.json +87 -12
- package/assets/manifest/toolkit-bundle.sha256.txt +19 -4
- package/assets/toolkit/toolkit/AGENTS.md +20 -16
- package/assets/toolkit/toolkit/install.ps1 +122 -7
- package/assets/toolkit/toolkit/runtimes/claude/CLAUDE_TEMPLATE.md +32 -10
- package/assets/toolkit/toolkit/scripts/install-claude-skills.ps1 +129 -0
- package/assets/toolkit/toolkit/scripts/install-codex-skills.ps1 +8 -0
- package/assets/toolkit/toolkit/scripts/uninstall-claude-skills.ps1 +139 -0
- package/assets/toolkit/toolkit/skills-claude/api-design-spec/SKILL.md +76 -0
- package/assets/toolkit/toolkit/skills-claude/api-doc/SKILL.md +46 -0
- package/assets/toolkit/toolkit/skills-claude/arch/SKILL.md +70 -0
- package/assets/toolkit/toolkit/skills-claude/ba/SKILL.md +49 -0
- package/assets/toolkit/toolkit/skills-claude/design-layout/SKILL.md +25 -0
- package/assets/toolkit/toolkit/skills-claude/dev/SKILL.md +45 -0
- package/assets/toolkit/toolkit/skills-claude/dev-backend/SKILL.md +20 -0
- package/assets/toolkit/toolkit/skills-claude/dev-frontend/SKILL.md +18 -0
- package/assets/toolkit/toolkit/skills-claude/orchestrator/SKILL.md +63 -0
- package/assets/toolkit/toolkit/skills-claude/pm/SKILL.md +52 -0
- package/assets/toolkit/toolkit/skills-claude/qa/SKILL.md +47 -0
- package/assets/toolkit/toolkit/skills-claude/screen-design-spec/SKILL.md +68 -0
- package/assets/toolkit/toolkit/skills-claude/test-case-spec/SKILL.md +63 -0
- package/package.json +2 -2
- package/src/commands/help.js +30 -4
- package/src/commands/init.js +25 -1
- package/src/commands/runtime.js +217 -0
- package/src/index.js +4 -1
- package/src/lib/scope.js +68 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qa
|
|
3
|
+
description: QA workflow for SDTK. Use when you need to validate an implemented feature against BA/PRD/Backlog, run quality gates, document defects, and produce a QA_RELEASE_REPORT with a release decision.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## SDTK Pipeline Rules (always apply)
|
|
7
|
+
1. Pipeline: PM Initiation → BA Analysis → PM Planning → Architecture Design → Development + Review → QA Validation
|
|
8
|
+
2. After completing phase work: update SHARED_PLANNING.md + QUALITY_CHECKLIST.md
|
|
9
|
+
3. If unclear: log OQ-xx in artifact, escalate to PM (PM asks user if needed)
|
|
10
|
+
4. Traceability: REQ → BR/UC/AC → design → backlog → code/tests → QA
|
|
11
|
+
5. Code review must be COMPLETE before QA phase can start
|
|
12
|
+
6. Do not skip phases. If inputs missing, ask focused questions.
|
|
13
|
+
|
|
14
|
+
## Prerequisites (verify before proceeding)
|
|
15
|
+
Read QUALITY_CHECKLIST.md and verify:
|
|
16
|
+
- Phase 4 DEV gate must show all items [x] Done (including code review completion).
|
|
17
|
+
|
|
18
|
+
If prerequisites NOT met: report which gate is missing, suggest user run `/dev` first to complete code review.
|
|
19
|
+
|
|
20
|
+
## Current Context
|
|
21
|
+
- Config: !`node -e "try{process.stdout.write(require('fs').readFileSync('sdtk.config.json','utf8'))}catch{process.stdout.write('{}')}"`
|
|
22
|
+
- Pipeline: !`node -e "try{process.stdout.write(require('fs').readFileSync('SHARED_PLANNING.md','utf8'))}catch{process.stdout.write('Not initialized')}"`
|
|
23
|
+
- Gates: !`node -e "try{process.stdout.write(require('fs').readFileSync('QUALITY_CHECKLIST.md','utf8'))}catch{process.stdout.write('Not initialized')}"`
|
|
24
|
+
- State: !`node -e "try{process.stdout.write(require('fs').readFileSync('.sdtk/orchestration-state.json','utf8'))}catch{process.stdout.write('{}')}"`
|
|
25
|
+
|
|
26
|
+
## Input
|
|
27
|
+
$ARGUMENTS
|
|
28
|
+
|
|
29
|
+
If no arguments provided, read current feature context from SHARED_PLANNING.md.
|
|
30
|
+
|
|
31
|
+
# SDTK QA (Testing + Release Decision)
|
|
32
|
+
|
|
33
|
+
## Output
|
|
34
|
+
- `docs/qa/QA_RELEASE_REPORT_[FEATURE_KEY].md`
|
|
35
|
+
- Optional (when detailed test design spec is requested):
|
|
36
|
+
- `docs/qa/[FEATURE_KEY]_TEST_CASE.md` via `/test-case-spec`
|
|
37
|
+
|
|
38
|
+
## Process
|
|
39
|
+
1. Validate prerequisites: DEV phase completed + code review PASS.
|
|
40
|
+
2. Create test strategy mapped to UC/AC.
|
|
41
|
+
3. If test-case specification artifact is required, invoke `/test-case-spec` and align counts/coverage with release testing scope.
|
|
42
|
+
4. If acceptance criteria / expected behavior is unclear: record OQ-xx in QA report and escalate to PM (suggest user run `/pm` if still missing info).
|
|
43
|
+
5. Execute/record results (unit/integration/e2e as applicable).
|
|
44
|
+
6. Record defects with severity and status.
|
|
45
|
+
7. Decide: APPROVED vs REJECTED (with reasons).
|
|
46
|
+
8. Update shared state + Phase 5 checklist.
|
|
47
|
+
9. Handoff: suggest user run `/pm` to finalize release status if approved.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: screen-design-spec
|
|
3
|
+
description: Create/update screen flow-action specifications from requirement sources (Excel/Figma/spec docs), including screen flow PlantUML, UI item/action tables, API mapping tables, and screen-to-API traceability.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Required Inputs (read before proceeding)
|
|
7
|
+
Read the following artifacts for the current feature:
|
|
8
|
+
1. `docs/specs/BA_SPEC_*.md` — business rules, use cases
|
|
9
|
+
2. `docs/architecture/ARCH_DESIGN_*.md` — system components
|
|
10
|
+
3. `docs/api/[FEATURE_KEY]_ENDPOINTS.md` — API endpoints (when available)
|
|
11
|
+
|
|
12
|
+
## Input
|
|
13
|
+
$ARGUMENTS
|
|
14
|
+
|
|
15
|
+
# SDTK Screen Flow Action Spec
|
|
16
|
+
|
|
17
|
+
## Outputs
|
|
18
|
+
- `docs/specs/[FEATURE_KEY]_FLOW_ACTION_SPEC.md`
|
|
19
|
+
- Optional supporting docs:
|
|
20
|
+
- `docs/specs/[FEATURE_KEY]_FIGMA_LAYOUT.md`
|
|
21
|
+
- `docs/specs/[FEATURE_KEY]_DESIGN_SPEC_FROM_EXCEL.md`
|
|
22
|
+
- `docs/specs/assets/[feature_snake]/screens/*`
|
|
23
|
+
|
|
24
|
+
## Required Inputs
|
|
25
|
+
- Feature key/name
|
|
26
|
+
- Primary requirement sources (BA spec, architecture, customer design docs)
|
|
27
|
+
- Screen source references (Figma URLs and/or requirement screenshots)
|
|
28
|
+
- API endpoint source (`docs/api/[FEATURE_KEY]_ENDPOINTS.md`) when available
|
|
29
|
+
|
|
30
|
+
## Process
|
|
31
|
+
1. Read requirement sources and identify in-scope screens, dialogs, and transitions.
|
|
32
|
+
2. Read and apply rules from `.claude/skills/references/FLOW_ACTION_SPEC_CREATION_RULES.md`.
|
|
33
|
+
3. Build/update section `Feature overview` and `Screen flow action` (PlantUML).
|
|
34
|
+
4. For each screen/dialog:
|
|
35
|
+
- Add metadata (screen ID, source link)
|
|
36
|
+
- Add screen image reference
|
|
37
|
+
- Add UI item/action table with `No` column
|
|
38
|
+
- Add API mapping table (trigger -> API -> data usage)
|
|
39
|
+
5. Build/update `System processing flow` from use-case and process sources.
|
|
40
|
+
6. Build/update `Open questions` for unresolved behavior/API/data points.
|
|
41
|
+
7. Build/update `Screen - API Mapping` summary section.
|
|
42
|
+
8. Validate:
|
|
43
|
+
- global numbering consistency (no screen-level reset)
|
|
44
|
+
- no broken image paths
|
|
45
|
+
- PlantUML renderability
|
|
46
|
+
- consistency with API endpoints spec
|
|
47
|
+
- EN artifact hygiene (no VI leftovers, no mojibake, no merged heading lines)
|
|
48
|
+
- for legacy specs with per-screen reset numbering: run renumber migration first
|
|
49
|
+
9. Update document history and handoff to ARCH/DEV.
|
|
50
|
+
|
|
51
|
+
## Rule References
|
|
52
|
+
- Core rules: `.claude/skills/references/FLOW_ACTION_SPEC_CREATION_RULES.md`
|
|
53
|
+
- Numbering reference: `.claude/skills/references/numbering-rules.md`
|
|
54
|
+
- Figma reference: `.claude/skills/references/figma-mcp.md`
|
|
55
|
+
- Excel image export reference: `.claude/skills/references/excel-image-export.md`
|
|
56
|
+
|
|
57
|
+
## Validation Script
|
|
58
|
+
- `scripts/validate_flow_action_spec_numbering.py`
|
|
59
|
+
- Checks duplicate/resetted numbering in action tables.
|
|
60
|
+
- Checks encoding/markdown hygiene.
|
|
61
|
+
- For EN artifacts, run with `--en-check`:
|
|
62
|
+
- `python scripts/validate_flow_action_spec_numbering.py --spec "docs/specs/[FEATURE_KEY]_FLOW_ACTION_SPEC.md" --en-check`
|
|
63
|
+
- `scripts/renumber_flow_action_spec_global.py`
|
|
64
|
+
- Auto-migrates action table `No` fields to global numbering.
|
|
65
|
+
- Dry-run:
|
|
66
|
+
- `python scripts/renumber_flow_action_spec_global.py --spec "docs/specs/[FEATURE_KEY]_FLOW_ACTION_SPEC.md"`
|
|
67
|
+
- Apply:
|
|
68
|
+
- `python scripts/renumber_flow_action_spec_global.py --spec "docs/specs/[FEATURE_KEY]_FLOW_ACTION_SPEC.md" --write`
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-case-spec
|
|
3
|
+
description: Generate screen-based QA test-case markdown in Excel-aligned layout (Statistic + per-screen UTC/ITC worksheets). Use when QA needs reusable test design artifacts before or during execution.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Required Inputs (read before proceeding)
|
|
7
|
+
Read the following artifacts for the current feature:
|
|
8
|
+
1. `docs/specs/[FEATURE_KEY]_FLOW_ACTION_SPEC.md` — screen/flow references
|
|
9
|
+
2. `docs/specs/BA_SPEC_[FEATURE_KEY].md` — business rules, use cases
|
|
10
|
+
3. `docs/api/[FEATURE_KEY]_ENDPOINTS.md` — API reference
|
|
11
|
+
4. `docs/specs/Q&A.md` or `docs/en/specs/Q&A.md` — clarification source (when available)
|
|
12
|
+
|
|
13
|
+
## Input
|
|
14
|
+
$ARGUMENTS
|
|
15
|
+
|
|
16
|
+
# SDTK Test Case Spec
|
|
17
|
+
|
|
18
|
+
## Outputs
|
|
19
|
+
- `docs/qa/[FEATURE_KEY]_TEST_CASE.md`
|
|
20
|
+
- Optional project variant:
|
|
21
|
+
- `docs/en/qa/[FEATURE_KEY]_TEST_CASE.md` (only when project uses `docs/en/**`)
|
|
22
|
+
|
|
23
|
+
## Core Rules
|
|
24
|
+
1. Apply `.claude/skills/references/TEST_CASE_CREATION_RULES.md` first.
|
|
25
|
+
2. Keep section order fixed (Statistic -> Abbreviations -> Scope -> References -> Environment -> Coverage -> Screen-based UTC/ITC -> OQ -> STC/UAT note).
|
|
26
|
+
3. Use screen-first layout to mirror worksheet structure:
|
|
27
|
+
- each screen can have `[SCREEN_KEY]_UTC` and `[SCREEN_KEY]_ITC`.
|
|
28
|
+
4. Keep one unified 18-column schema for UTC/ITC rows.
|
|
29
|
+
5. Keep stable case IDs; do not renumber only because of regrouping.
|
|
30
|
+
6. Track unresolved decisions via `OQ-xx`.
|
|
31
|
+
|
|
32
|
+
## Procedure
|
|
33
|
+
1. Resolve output path:
|
|
34
|
+
- default `docs/qa/[FEATURE_KEY]_TEST_CASE.md`
|
|
35
|
+
- use `docs/en/qa/...` only if the repo already follows `docs/en/**`.
|
|
36
|
+
2. Build/refresh `Statistic Summary (Excel-aligned)`:
|
|
37
|
+
- include UT total, IT total, grand total.
|
|
38
|
+
3. Build `Feature Coverage Matrix` from flow/action and API docs.
|
|
39
|
+
4. Split UTC/ITC by screen sections (`screen-first`), not by test type only.
|
|
40
|
+
5. Fill conflict/permission/error-path cases from Q&A decisions and API contracts.
|
|
41
|
+
6. Record unresolved items in section `Open Questions`.
|
|
42
|
+
7. Validate:
|
|
43
|
+
- counts in summary match table rows
|
|
44
|
+
- no placeholder tokens like `??`
|
|
45
|
+
- out-of-scope boundaries are explicit
|
|
46
|
+
|
|
47
|
+
## Role Integration
|
|
48
|
+
- Primary owner: `/qa`.
|
|
49
|
+
- `/qa` uses this skill to design/update reusable test-case specs.
|
|
50
|
+
- `/qa` still owns release decision artifact (`QA_RELEASE_REPORT_*`).
|
|
51
|
+
|
|
52
|
+
## Notes
|
|
53
|
+
- This skill is for test-case specification artifacts, not test execution logs.
|
|
54
|
+
- For release approval and defect triage, continue with `/qa`.
|
|
55
|
+
|
|
56
|
+
## Validator Script
|
|
57
|
+
- `scripts/validate_test_case_spec.py`
|
|
58
|
+
|
|
59
|
+
### Typical command
|
|
60
|
+
```bash
|
|
61
|
+
python scripts/validate_test_case_spec.py \
|
|
62
|
+
--file "docs/qa/[FEATURE_KEY]_TEST_CASE.md"
|
|
63
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sdtk-kit",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "SDTK CLI toolkit for deterministic software documentation workflows",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sdtk": "./bin/sdtk.js"
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"url": "https://github.com/codexsdtk/sdtk-toolkit.git",
|
|
37
37
|
"directory": "distribution/sdtk-cli"
|
|
38
38
|
},
|
|
39
|
-
"homepage": "https://
|
|
39
|
+
"homepage": "https://agenttoolkits.dev",
|
|
40
40
|
"bugs": {
|
|
41
41
|
"url": "https://github.com/codexsdtk/sdtk-toolkit/issues"
|
|
42
42
|
},
|
package/src/commands/help.js
CHANGED
|
@@ -9,15 +9,36 @@ function cmdHelp() {
|
|
|
9
9
|
"",
|
|
10
10
|
"Commands:",
|
|
11
11
|
" init Initialize SDTK workspace (runtime adapter + config)",
|
|
12
|
+
" runtime Manage runtime asset installation (install, uninstall, status)",
|
|
12
13
|
" auth Manage GitHub authentication and entitlement",
|
|
13
14
|
" generate Scaffold feature documentation from templates (17 files)",
|
|
14
15
|
"",
|
|
15
16
|
"Init options:",
|
|
16
|
-
" --runtime <codex|claude>
|
|
17
|
+
" --runtime <codex|claude> Runtime adapter (default: codex)",
|
|
18
|
+
" --runtime-scope <project|user> Install scope (default: project for claude, user for codex)",
|
|
19
|
+
" --project-path <path> Target project directory (default: cwd)",
|
|
20
|
+
" --force Overwrite existing files",
|
|
21
|
+
" --skip-runtime-assets Skip runtime asset installation",
|
|
22
|
+
" --skip-skills (deprecated, use --skip-runtime-assets)",
|
|
23
|
+
" --verbose Show detailed PowerShell script output",
|
|
24
|
+
"",
|
|
25
|
+
"Runtime subcommands:",
|
|
26
|
+
" sdtk runtime install --runtime <codex|claude> [--scope <project|user>]",
|
|
27
|
+
" sdtk runtime uninstall --runtime <codex|claude> [--scope <project|user>] [--all]",
|
|
28
|
+
" sdtk runtime status --runtime <codex|claude>",
|
|
29
|
+
"",
|
|
30
|
+
"Runtime options:",
|
|
31
|
+
" --runtime <codex|claude> Target runtime (required)",
|
|
32
|
+
" --scope <project|user> Install scope (default: project for claude, user for codex)",
|
|
17
33
|
" --project-path <path> Target project directory (default: cwd)",
|
|
18
|
-
" --force Overwrite existing
|
|
19
|
-
" --
|
|
20
|
-
" --verbose Show detailed
|
|
34
|
+
" --force Overwrite existing skills",
|
|
35
|
+
" --all Uninstall all managed skills",
|
|
36
|
+
" --verbose Show detailed script output",
|
|
37
|
+
"",
|
|
38
|
+
"Scope behavior:",
|
|
39
|
+
" project Skills are installed inside the repo (Claude only: .claude/skills/)",
|
|
40
|
+
" user Skills are installed in the runtime home (~/.claude/skills/ or ~/.codex/skills/)",
|
|
41
|
+
" Note: Codex supports user scope only. Project scope is not available for Codex.",
|
|
21
42
|
"",
|
|
22
43
|
"Auth options:",
|
|
23
44
|
" --token <value> Store GitHub PAT",
|
|
@@ -60,6 +81,11 @@ function cmdHelp() {
|
|
|
60
81
|
" sdtk auth --verify",
|
|
61
82
|
' sdtk generate --feature-key USER_PROFILE --feature-name "User Profile"',
|
|
62
83
|
" sdtk generate --feature-key ORDER_MGMT --feature-name \"Order Management\" --validate-only",
|
|
84
|
+
" sdtk init --runtime claude --runtime-scope user",
|
|
85
|
+
" sdtk runtime install --runtime claude --scope project",
|
|
86
|
+
" sdtk runtime install --runtime codex --scope user",
|
|
87
|
+
" sdtk runtime status --runtime claude",
|
|
88
|
+
" sdtk runtime uninstall --runtime claude --scope project --all",
|
|
63
89
|
"",
|
|
64
90
|
" # Override entitlement repo (bash/zsh):",
|
|
65
91
|
" export SDTK_ENTITLEMENT_REPO=owner/repo",
|
package/src/commands/init.js
CHANGED
|
@@ -5,12 +5,15 @@ const { parseFlags, validateChoice } = require("../lib/args");
|
|
|
5
5
|
const { verify, resolvePayloadFile } = require("../lib/toolkit-payload");
|
|
6
6
|
const { runScript } = require("../lib/powershell");
|
|
7
7
|
const { ValidationError } = require("../lib/errors");
|
|
8
|
+
const { VALID_SCOPES, defaultScope, isProjectScopeSupported } = require("../lib/scope");
|
|
8
9
|
|
|
9
10
|
const FLAG_DEFS = {
|
|
10
11
|
runtime: { type: "string" },
|
|
11
12
|
"project-path": { type: "string" },
|
|
13
|
+
"runtime-scope": { type: "string" },
|
|
12
14
|
force: { type: "boolean" },
|
|
13
15
|
"skip-skills": { type: "boolean" },
|
|
16
|
+
"skip-runtime-assets": { type: "boolean" },
|
|
14
17
|
verbose: { type: "boolean" },
|
|
15
18
|
};
|
|
16
19
|
|
|
@@ -23,6 +26,25 @@ async function cmdInit(args) {
|
|
|
23
26
|
const runtime = flags.runtime || "codex";
|
|
24
27
|
validateChoice(runtime, VALID_RUNTIMES, "runtime");
|
|
25
28
|
|
|
29
|
+
// Resolve scope
|
|
30
|
+
const scope = flags["runtime-scope"] || defaultScope(runtime);
|
|
31
|
+
validateChoice(scope, VALID_SCOPES, "runtime-scope");
|
|
32
|
+
|
|
33
|
+
// Gate C0: Codex does not support project-local skills
|
|
34
|
+
if (scope === "project" && !isProjectScopeSupported(runtime)) {
|
|
35
|
+
throw new ValidationError(
|
|
36
|
+
"Codex does not support project-local skills. Use --runtime-scope user instead."
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Handle deprecated --skip-skills
|
|
41
|
+
const skipAssets = flags["skip-runtime-assets"] || flags["skip-skills"];
|
|
42
|
+
if (flags["skip-skills"] && !flags["skip-runtime-assets"]) {
|
|
43
|
+
console.warn(
|
|
44
|
+
"Warning: --skip-skills is deprecated. Use --skip-runtime-assets instead."
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
26
48
|
// Resolve project path
|
|
27
49
|
const projectPath = flags["project-path"]
|
|
28
50
|
? path.resolve(flags["project-path"])
|
|
@@ -38,13 +60,15 @@ async function cmdInit(args) {
|
|
|
38
60
|
const params = {
|
|
39
61
|
ProjectPath: projectPath,
|
|
40
62
|
Runtime: runtime,
|
|
63
|
+
Scope: scope,
|
|
41
64
|
};
|
|
42
65
|
if (flags.force) params.Force = true;
|
|
43
|
-
if (
|
|
66
|
+
if (skipAssets) params.SkipRuntimeAssets = true;
|
|
44
67
|
if (!flags.verbose) params.Quiet = true;
|
|
45
68
|
|
|
46
69
|
console.log(`Initializing SDTK workspace...`);
|
|
47
70
|
console.log(` Runtime: ${runtime}`);
|
|
71
|
+
console.log(` Scope: ${scope}`);
|
|
48
72
|
console.log(` Project: ${projectPath}`);
|
|
49
73
|
console.log("");
|
|
50
74
|
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const { parseFlags, requireFlag, validateChoice } = require("../lib/args");
|
|
6
|
+
const { verify, resolvePayloadFile } = require("../lib/toolkit-payload");
|
|
7
|
+
const { runScript } = require("../lib/powershell");
|
|
8
|
+
const { ValidationError } = require("../lib/errors");
|
|
9
|
+
const {
|
|
10
|
+
VALID_SCOPES,
|
|
11
|
+
defaultScope,
|
|
12
|
+
isProjectScopeSupported,
|
|
13
|
+
resolveSkillsDir,
|
|
14
|
+
managedSkillNames,
|
|
15
|
+
} = require("../lib/scope");
|
|
16
|
+
|
|
17
|
+
const FLAG_DEFS = {
|
|
18
|
+
runtime: { type: "string" },
|
|
19
|
+
scope: { type: "string" },
|
|
20
|
+
"project-path": { type: "string" },
|
|
21
|
+
force: { type: "boolean" },
|
|
22
|
+
all: { type: "boolean" },
|
|
23
|
+
verbose: { type: "boolean" },
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const VALID_RUNTIMES = ["codex", "claude"];
|
|
27
|
+
const SUBCOMMANDS = ["install", "uninstall", "status"];
|
|
28
|
+
|
|
29
|
+
function validateScopeForRuntime(runtime, scope) {
|
|
30
|
+
if (scope === "project" && !isProjectScopeSupported(runtime)) {
|
|
31
|
+
throw new ValidationError(
|
|
32
|
+
`Codex does not support project-local skills. Use --scope user instead.`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function cmdRuntimeInstall(flags) {
|
|
38
|
+
const runtime = requireFlag(flags, "runtime", "runtime");
|
|
39
|
+
validateChoice(runtime, VALID_RUNTIMES, "runtime");
|
|
40
|
+
|
|
41
|
+
const scope = flags.scope || defaultScope(runtime);
|
|
42
|
+
validateChoice(scope, VALID_SCOPES, "scope");
|
|
43
|
+
validateScopeForRuntime(runtime, scope);
|
|
44
|
+
|
|
45
|
+
const projectPath = flags["project-path"]
|
|
46
|
+
? path.resolve(flags["project-path"])
|
|
47
|
+
: process.cwd();
|
|
48
|
+
|
|
49
|
+
verify();
|
|
50
|
+
|
|
51
|
+
const scriptName =
|
|
52
|
+
runtime === "claude"
|
|
53
|
+
? "toolkit/scripts/install-claude-skills.ps1"
|
|
54
|
+
: "toolkit/scripts/install-codex-skills.ps1";
|
|
55
|
+
const script = resolvePayloadFile(scriptName);
|
|
56
|
+
|
|
57
|
+
const params = { Scope: scope };
|
|
58
|
+
if (runtime === "claude") {
|
|
59
|
+
params.ProjectPath = projectPath;
|
|
60
|
+
}
|
|
61
|
+
if (flags.force) params.Force = true;
|
|
62
|
+
|
|
63
|
+
console.log(`Installing ${runtime} runtime assets...`);
|
|
64
|
+
console.log(` Runtime: ${runtime}`);
|
|
65
|
+
console.log(` Scope: ${scope}`);
|
|
66
|
+
if (scope === "project") {
|
|
67
|
+
console.log(` Project: ${projectPath}`);
|
|
68
|
+
}
|
|
69
|
+
console.log("");
|
|
70
|
+
|
|
71
|
+
const result = await runScript(script, params, {
|
|
72
|
+
silent: !flags.verbose,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (result.exitCode !== 0) {
|
|
76
|
+
if (result.stderr) console.error(result.stderr);
|
|
77
|
+
throw new ValidationError(
|
|
78
|
+
`Runtime install failed (exit code ${result.exitCode}).`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log("");
|
|
83
|
+
console.log(`${runtime} runtime assets installed successfully.`);
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function cmdRuntimeUninstall(flags) {
|
|
88
|
+
const runtime = requireFlag(flags, "runtime", "runtime");
|
|
89
|
+
validateChoice(runtime, VALID_RUNTIMES, "runtime");
|
|
90
|
+
|
|
91
|
+
const scope = flags.scope || defaultScope(runtime);
|
|
92
|
+
validateChoice(scope, VALID_SCOPES, "scope");
|
|
93
|
+
validateScopeForRuntime(runtime, scope);
|
|
94
|
+
|
|
95
|
+
const projectPath = flags["project-path"]
|
|
96
|
+
? path.resolve(flags["project-path"])
|
|
97
|
+
: process.cwd();
|
|
98
|
+
|
|
99
|
+
verify();
|
|
100
|
+
|
|
101
|
+
const scriptName =
|
|
102
|
+
runtime === "claude"
|
|
103
|
+
? "toolkit/scripts/uninstall-claude-skills.ps1"
|
|
104
|
+
: "toolkit/scripts/uninstall-codex-skills.ps1";
|
|
105
|
+
const script = resolvePayloadFile(scriptName);
|
|
106
|
+
|
|
107
|
+
const params = {};
|
|
108
|
+
if (runtime === "claude") {
|
|
109
|
+
params.Scope = scope;
|
|
110
|
+
params.ProjectPath = projectPath;
|
|
111
|
+
}
|
|
112
|
+
if (flags.all) params.All = true;
|
|
113
|
+
|
|
114
|
+
console.log(`Uninstalling ${runtime} runtime assets...`);
|
|
115
|
+
console.log(` Runtime: ${runtime}`);
|
|
116
|
+
console.log(` Scope: ${scope}`);
|
|
117
|
+
console.log("");
|
|
118
|
+
|
|
119
|
+
const result = await runScript(script, params, {
|
|
120
|
+
silent: !flags.verbose,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (result.exitCode !== 0) {
|
|
124
|
+
if (result.stderr) console.error(result.stderr);
|
|
125
|
+
throw new ValidationError(
|
|
126
|
+
`Runtime uninstall failed (exit code ${result.exitCode}).`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.log("");
|
|
131
|
+
console.log(`${runtime} runtime assets uninstalled successfully.`);
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function cmdRuntimeStatus(flags) {
|
|
136
|
+
const runtime = requireFlag(flags, "runtime", "runtime");
|
|
137
|
+
validateChoice(runtime, VALID_RUNTIMES, "runtime");
|
|
138
|
+
|
|
139
|
+
const projectPath = flags["project-path"]
|
|
140
|
+
? path.resolve(flags["project-path"])
|
|
141
|
+
: process.cwd();
|
|
142
|
+
|
|
143
|
+
console.log(`Runtime: ${runtime}`);
|
|
144
|
+
console.log("");
|
|
145
|
+
|
|
146
|
+
// Check both scopes
|
|
147
|
+
const scopes = runtime === "claude" ? ["project", "user"] : ["user"];
|
|
148
|
+
|
|
149
|
+
for (const scope of scopes) {
|
|
150
|
+
const skillsDir = resolveSkillsDir(runtime, scope, projectPath);
|
|
151
|
+
const exists = fs.existsSync(skillsDir);
|
|
152
|
+
let skillCount = 0;
|
|
153
|
+
|
|
154
|
+
const managed = managedSkillNames(runtime);
|
|
155
|
+
let installedNames = [];
|
|
156
|
+
|
|
157
|
+
if (exists) {
|
|
158
|
+
try {
|
|
159
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
160
|
+
installedNames = entries
|
|
161
|
+
.filter((e) => e.isDirectory() && managed.includes(e.name))
|
|
162
|
+
.map((e) => e.name);
|
|
163
|
+
skillCount = installedNames.length;
|
|
164
|
+
} catch {
|
|
165
|
+
// Directory not readable
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const allInstalled = skillCount === managed.length;
|
|
170
|
+
|
|
171
|
+
console.log(` Scope: ${scope}`);
|
|
172
|
+
console.log(` Path: ${skillsDir}`);
|
|
173
|
+
const statusLabel = !exists
|
|
174
|
+
? "not installed"
|
|
175
|
+
: allInstalled
|
|
176
|
+
? `installed (${skillCount}/${managed.length} SDTK skills)`
|
|
177
|
+
: `partial (${skillCount}/${managed.length} SDTK skills)`;
|
|
178
|
+
console.log(` Status: ${statusLabel}`);
|
|
179
|
+
if (exists && skillCount < managed.length) {
|
|
180
|
+
const missing = managed.filter((n) => !installedNames.includes(n));
|
|
181
|
+
console.log(` Missing: ${missing.join(", ")}`);
|
|
182
|
+
}
|
|
183
|
+
console.log("");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function cmdRuntime(args) {
|
|
190
|
+
const { flags, positional } = parseFlags(args, FLAG_DEFS);
|
|
191
|
+
|
|
192
|
+
const subcommand = positional[0];
|
|
193
|
+
if (!subcommand) {
|
|
194
|
+
throw new ValidationError(
|
|
195
|
+
`Missing subcommand. Usage: sdtk runtime <${SUBCOMMANDS.join("|")}> [options]`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (!SUBCOMMANDS.includes(subcommand)) {
|
|
200
|
+
throw new ValidationError(
|
|
201
|
+
`Unknown subcommand: "${subcommand}". Must be one of: ${SUBCOMMANDS.join(", ")}`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
switch (subcommand) {
|
|
206
|
+
case "install":
|
|
207
|
+
return cmdRuntimeInstall(flags);
|
|
208
|
+
case "uninstall":
|
|
209
|
+
return cmdRuntimeUninstall(flags);
|
|
210
|
+
case "status":
|
|
211
|
+
return cmdRuntimeStatus(flags);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
module.exports = {
|
|
216
|
+
cmdRuntime,
|
|
217
|
+
};
|
package/src/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const { cmdHelp } = require("./commands/help");
|
|
|
4
4
|
const { cmdInit } = require("./commands/init");
|
|
5
5
|
const { cmdAuth } = require("./commands/auth");
|
|
6
6
|
const { cmdGenerate } = require("./commands/generate");
|
|
7
|
+
const { cmdRuntime } = require("./commands/runtime");
|
|
7
8
|
const { ValidationError, CliError } = require("./lib/errors");
|
|
8
9
|
|
|
9
10
|
function getVersion() {
|
|
@@ -25,7 +26,7 @@ function parseCommand(argv) {
|
|
|
25
26
|
return { command: first, args: rest };
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
const COMMANDS = new Set(["help", "version", "init", "auth", "generate"]);
|
|
29
|
+
const COMMANDS = new Set(["help", "version", "init", "auth", "generate", "runtime"]);
|
|
29
30
|
|
|
30
31
|
async function run(argv) {
|
|
31
32
|
const { command, args } = parseCommand(argv);
|
|
@@ -48,6 +49,8 @@ async function run(argv) {
|
|
|
48
49
|
return cmdAuth(args);
|
|
49
50
|
case "generate":
|
|
50
51
|
return cmdGenerate(args);
|
|
52
|
+
case "runtime":
|
|
53
|
+
return cmdRuntime(args);
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
|
package/src/lib/scope.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
|
|
6
|
+
const VALID_SCOPES = ["project", "user"];
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns the default scope for a given runtime.
|
|
10
|
+
* Claude defaults to project-local, Codex defaults to user/global.
|
|
11
|
+
*/
|
|
12
|
+
function defaultScope(runtime) {
|
|
13
|
+
return runtime === "claude" ? "project" : "user";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns true if the given runtime supports project-local scope.
|
|
18
|
+
* Gate C0: Codex does not support project-local skills.
|
|
19
|
+
*/
|
|
20
|
+
function isProjectScopeSupported(runtime) {
|
|
21
|
+
return runtime === "claude";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Resolves the skills directory for a given runtime, scope, and project path.
|
|
26
|
+
*/
|
|
27
|
+
function resolveSkillsDir(runtime, scope, projectPath) {
|
|
28
|
+
if (runtime === "claude") {
|
|
29
|
+
if (scope === "user") {
|
|
30
|
+
return path.join(os.homedir(), ".claude", "skills");
|
|
31
|
+
}
|
|
32
|
+
return path.join(projectPath || process.cwd(), ".claude", "skills");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Codex: always user/global scope
|
|
36
|
+
const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
|
|
37
|
+
return path.join(codexHome, "skills");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* SDTK-managed skill directory names per runtime.
|
|
42
|
+
* Used by runtime status to distinguish SDTK skills from unrelated user skills.
|
|
43
|
+
*/
|
|
44
|
+
const MANAGED_CODEX_SKILLS = [
|
|
45
|
+
"sdtk-api-design-spec", "sdtk-api-doc", "sdtk-arch", "sdtk-ba",
|
|
46
|
+
"sdtk-design-layout", "sdtk-dev", "sdtk-dev-backend", "sdtk-dev-frontend",
|
|
47
|
+
"sdtk-orchestrator", "sdtk-pm", "sdtk-qa", "sdtk-screen-design-spec",
|
|
48
|
+
"sdtk-test-case-spec",
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const MANAGED_CLAUDE_SKILLS = [
|
|
52
|
+
"api-design-spec", "api-doc", "arch", "ba",
|
|
53
|
+
"design-layout", "dev", "dev-backend", "dev-frontend",
|
|
54
|
+
"orchestrator", "pm", "qa", "screen-design-spec",
|
|
55
|
+
"test-case-spec",
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
function managedSkillNames(runtime) {
|
|
59
|
+
return runtime === "claude" ? MANAGED_CLAUDE_SKILLS : MANAGED_CODEX_SKILLS;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
VALID_SCOPES,
|
|
64
|
+
defaultScope,
|
|
65
|
+
isProjectScopeSupported,
|
|
66
|
+
resolveSkillsDir,
|
|
67
|
+
managedSkillNames,
|
|
68
|
+
};
|