@haposoft/cafekit 0.16.0-rc.8 → 0.16.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/README.md +116 -27
- package/bin/__tests__/codex-hooks-ownership.test.js +239 -0
- package/bin/__tests__/codex-hooks.test.js +50 -0
- package/bin/__tests__/codex-native.test.js +1882 -70
- package/bin/__tests__/develop-contract.test.js +400 -23
- package/bin/__tests__/installer-safety.test.js +3 -3
- package/bin/__tests__/optional-skill-inventory.test.js +249 -0
- package/bin/__tests__/output-styles.test.js +214 -0
- package/bin/__tests__/package-inventory.test.js +1735 -98
- package/bin/__tests__/runtime-schema.test.js +111 -0
- package/bin/__tests__/secret-output-guardrail.test.js +122 -0
- package/bin/__tests__/skill-routing-source.test.js +172 -0
- package/bin/__tests__/specs-v2-execution-closeout.test.js +1 -1
- package/bin/install.js +10 -0
- package/bin/lib/codex-install.js +170 -5
- package/bin/lib/context.js +14 -0
- package/bin/lib/i18n.js +12 -6
- package/bin/lib/skill-deps.js +5 -5
- package/bin/phases/claude-runtime.js +23 -0
- package/bin/phases/claude-settings.js +8 -0
- package/bin/phases/codex-hooks.js +156 -0
- package/bin/phases/codex-runtime.js +29 -38
- package/bin/phases/copy-payload.js +8 -2
- package/bin/phases/select-skill-bundles.js +96 -0
- package/bin/phases/skill-inventory.js +71 -0
- package/bin/phases/skills-setup.js +9 -2
- package/bin/phases/write-metadata.js +8 -5
- package/package.json +8 -2
- package/src/claude/CLAUDE.md +3 -3
- package/src/claude/agents/brainstormer.md +52 -69
- package/src/claude/agents/code-auditor.md +32 -14
- package/src/claude/agents/debugger.md +35 -20
- package/src/claude/agents/deployer.md +12 -5
- package/src/claude/agents/docs-keeper.md +11 -1
- package/src/claude/agents/implementer.md +25 -13
- package/src/claude/agents/inspector.md +6 -3
- package/src/claude/agents/project-manager.md +1 -1
- package/src/claude/agents/researcher.md +26 -55
- package/src/claude/agents/spec-maker.md +12 -7
- package/src/claude/agents/strategist.md +52 -0
- package/src/claude/agents/test-runner.md +117 -132
- package/src/claude/agents/ui-ux-designer.md +1 -1
- package/src/claude/hooks/__tests__/fixtures/statusline-default.golden +1 -0
- package/src/claude/hooks/__tests__/precompact.test.js +158 -0
- package/src/claude/hooks/__tests__/spec-gate.test.js +10 -3
- package/src/claude/hooks/__tests__/state.test.js +5 -0
- package/src/claude/hooks/__tests__/statusline.test.js +196 -0
- package/src/claude/hooks/agent.cjs +1 -1
- package/src/claude/hooks/docs-sync.cjs +12 -10
- package/src/claude/hooks/inspect-block.cjs +1 -1
- package/src/claude/hooks/lib/config.cjs +3 -0
- package/src/claude/hooks/lib/hook-state-dir.cjs +39 -0
- package/src/claude/hooks/lib/secret-keywords.cjs +42 -0
- package/src/claude/hooks/precompact.cjs +105 -0
- package/src/claude/hooks/rules.cjs +1 -1
- package/src/claude/hooks/secret-output-guardrail.cjs +43 -0
- package/src/claude/hooks/session.cjs +27 -1
- package/src/claude/hooks/spec-gate.cjs +3 -3
- package/src/claude/hooks/spec-state.cjs +2 -2
- package/src/claude/hooks/state.cjs +1 -1
- package/src/claude/hooks/task-scaffold-guard.cjs +1 -1
- package/src/claude/hooks/usage.cjs +1 -1
- package/src/claude/migration-manifest.json +29 -15
- package/src/claude/output-styles/coding-level-0-eli5.md +103 -0
- package/src/claude/output-styles/coding-level-1-junior.md +124 -0
- package/src/claude/output-styles/coding-level-2-mid.md +146 -0
- package/src/claude/output-styles/coding-level-3-senior.md +148 -0
- package/src/claude/output-styles/coding-level-4-lead.md +159 -0
- package/src/claude/output-styles/coding-level-5-god.md +91 -0
- package/src/claude/references/debugger/core-philosophy.md +5 -3
- package/src/claude/references/debugger/frontend-verification.md +2 -2
- package/src/claude/references/debugger/log-ci-analysis.md +13 -1
- package/src/claude/references/debugger/parallel-agent-hydration.md +19 -34
- package/src/claude/references/debugger/performance-diagnostics.md +2 -2
- package/src/claude/references/debugger/root-cause-tracing.md +37 -6
- package/src/claude/references/debugger/side-effect-gate.md +3 -1
- package/src/claude/references/debugger/verification-protocol.md +13 -12
- package/src/claude/rules/orchestrator.md +7 -1
- package/src/claude/rules/process-management.md +39 -0
- package/src/claude/rules/review-audit-self-decision.md +48 -0
- package/src/claude/rules/skill-domain-routing.md +26 -24
- package/src/claude/rules/skill-workflow-routing.md +22 -14
- package/src/claude/rules/workflow.md +3 -3
- package/src/claude/runtime.json +1 -0
- package/src/claude/runtime.schema.json +205 -0
- package/src/claude/scripts/generate-skill-catalog.cjs +156 -122
- package/src/claude/scripts/provenance.cjs +18 -5
- package/src/claude/scripts/workflow-policy.cjs +1 -1
- package/src/claude/settings/settings.json +16 -0
- package/src/claude/skills/agent-browser/SKILL.md +1 -1
- package/src/claude/skills/ai-multimodal/SKILL.md +1 -1
- package/src/claude/skills/brainstorm/SKILL.md +193 -172
- package/src/claude/skills/brainstorm/references/question-framework.md +105 -167
- package/src/claude/skills/chrome-devtools/SKILL.md +1 -1
- package/src/claude/skills/code-review/SKILL.md +43 -25
- package/src/claude/skills/code-review/references/spec-compliance-review.md +3 -4
- package/src/claude/skills/code-review/references/verification-gate.md +1 -1
- package/src/claude/skills/debug/SKILL.md +48 -19
- package/src/claude/skills/delegate/SKILL.md +1 -1
- package/src/claude/skills/develop/SKILL.md +92 -65
- package/src/claude/skills/develop/references/parallel-waves.md +36 -63
- package/src/claude/skills/develop/references/quality-gate.md +31 -4
- package/src/claude/skills/develop/references/subagent-patterns.md +21 -7
- package/src/claude/skills/docs/SKILL.md +42 -23
- package/src/claude/skills/docs/references/init-workflow.md +4 -4
- package/src/claude/skills/docs/references/reconstruct-workflow.md +6 -6
- package/src/claude/skills/docs/references/standard-docs-workflow.md +6 -2
- package/src/claude/skills/docs/references/summarize-workflow.md +2 -2
- package/src/claude/skills/docs/references/update-workflow.md +9 -7
- package/src/claude/skills/docs/templates/requirements-as-is.md +1 -1
- package/src/claude/skills/docx/SKILL.md +1 -1
- package/src/claude/skills/git/SKILL.md +1 -1
- package/src/claude/skills/git/references/commit-protocols.md +1 -1
- package/src/claude/skills/git/references/finish-branch.md +1 -1
- package/src/claude/skills/hotfix/SKILL.md +159 -170
- package/src/claude/skills/hotfix/references/diagnosis-protocol.md +14 -9
- package/src/claude/skills/hotfix/references/parallel-patterns.md +27 -13
- package/src/claude/skills/hotfix/references/prevention-gate.md +5 -0
- package/src/claude/skills/hotfix/references/review-cycle.md +21 -15
- package/src/claude/skills/hotfix/references/workflow-specialized.md +53 -21
- package/src/claude/skills/inspect/SKILL.md +55 -46
- package/src/claude/skills/inspect/references/internal-inspection.md +21 -5
- package/src/claude/skills/loop/SKILL.md +114 -0
- package/src/claude/skills/loop/references/bounded-loop-protocol.md +104 -0
- package/src/claude/skills/loop/references/metric-and-guard-contract.md +76 -0
- package/src/claude/skills/pdf/SKILL.md +1 -1
- package/src/claude/skills/pptx/SKILL.md +1 -1
- package/src/claude/skills/question/SKILL.md +16 -13
- package/src/claude/skills/research/SKILL.md +70 -43
- package/src/claude/skills/route/SKILL.md +94 -0
- package/src/claude/skills/route/references/agent-timing.md +46 -0
- package/src/claude/skills/route/references/chaining-patterns.md +53 -0
- package/src/claude/skills/route/references/task-taxonomy.md +48 -0
- package/src/claude/skills/specs/SKILL.md +41 -60
- package/src/claude/skills/specs/references/review.md +11 -8
- package/src/claude/skills/specs/references/templates.md +34 -18
- package/src/claude/skills/specs/templates/requirements-init.md +1 -1
- package/src/claude/skills/specs/templates/research.md +2 -2
- package/src/claude/skills/sync/SKILL.md +6 -6
- package/src/claude/skills/sync/references/sync-protocols.md +1 -1
- package/src/claude/skills/test/SKILL.md +120 -120
- package/src/claude/skills/test/references/execution-strategy.md +208 -361
- package/src/claude/skills/test/references/failure-triage.md +55 -121
- package/src/claude/skills/test/references/test-memory.md +20 -34
- package/src/claude/skills/ui-ux-pro-max/SKILL.md +1 -1
- package/src/claude/skills/web-testing/SKILL.md +1 -1
- package/src/claude/skills/xlsx/SKILL.md +1 -1
- package/src/claude/status.cjs +135 -33
- package/src/codex/AGENTS.md +14 -4
- package/src/codex/hooks/docs-sync.cjs +8 -3
- package/src/codex/hooks/lib/hook-context.cjs +18 -4
- package/src/codex/hooks/rules.cjs +29 -1
- package/src/codex/hooks/secret-output-guardrail.cjs +30 -0
- package/src/codex/hooks/spec-gate.cjs +3 -8
- package/src/codex/hooks/spec-state.cjs +2 -1
- package/src/codex/hooks.json +5 -0
- package/src/codex/runtime.json +2 -0
- package/src/common/.env.example +1 -1
- package/src/claude/skills/backend-development/SKILL.md +0 -101
- package/src/claude/skills/backend-development/references/backend-api-design.md +0 -495
- package/src/claude/skills/backend-development/references/backend-architecture.md +0 -454
- package/src/claude/skills/backend-development/references/backend-authentication.md +0 -338
- package/src/claude/skills/backend-development/references/backend-code-quality.md +0 -659
- package/src/claude/skills/backend-development/references/backend-debugging.md +0 -904
- package/src/claude/skills/backend-development/references/backend-devops.md +0 -491
- package/src/claude/skills/backend-development/references/backend-mindset.md +0 -387
- package/src/claude/skills/backend-development/references/backend-performance.md +0 -397
- package/src/claude/skills/backend-development/references/backend-security.md +0 -342
- package/src/claude/skills/backend-development/references/backend-technologies.md +0 -256
- package/src/claude/skills/backend-development/references/backend-testing.md +0 -429
- package/src/claude/skills/devops/.env.example +0 -76
- package/src/claude/skills/devops/SKILL.md +0 -102
- package/src/claude/skills/devops/references/browser-rendering.md +0 -305
- package/src/claude/skills/devops/references/cloudflare-d1-kv.md +0 -123
- package/src/claude/skills/devops/references/cloudflare-platform.md +0 -271
- package/src/claude/skills/devops/references/cloudflare-r2-storage.md +0 -280
- package/src/claude/skills/devops/references/cloudflare-workers-advanced.md +0 -312
- package/src/claude/skills/devops/references/cloudflare-workers-apis.md +0 -309
- package/src/claude/skills/devops/references/cloudflare-workers-basics.md +0 -418
- package/src/claude/skills/devops/references/docker-basics.md +0 -297
- package/src/claude/skills/devops/references/docker-compose.md +0 -292
- package/src/claude/skills/devops/references/gcloud-platform.md +0 -297
- package/src/claude/skills/devops/references/gcloud-services.md +0 -304
- package/src/claude/skills/devops/references/kubernetes-basics.md +0 -95
- package/src/claude/skills/devops/references/kubernetes-helm-advanced.md +0 -70
- package/src/claude/skills/devops/references/kubernetes-helm.md +0 -81
- package/src/claude/skills/devops/references/kubernetes-kubectl.md +0 -74
- package/src/claude/skills/devops/references/kubernetes-security-advanced.md +0 -94
- package/src/claude/skills/devops/references/kubernetes-security.md +0 -89
- package/src/claude/skills/devops/references/kubernetes-troubleshooting-advanced.md +0 -74
- package/src/claude/skills/devops/references/kubernetes-troubleshooting.md +0 -49
- package/src/claude/skills/devops/references/kubernetes-workflows-advanced.md +0 -75
- package/src/claude/skills/devops/references/kubernetes-workflows.md +0 -76
- package/src/claude/skills/devops/scripts/cloudflare_deploy.py +0 -269
- package/src/claude/skills/devops/scripts/docker_optimize.py +0 -332
- package/src/claude/skills/devops/scripts/requirements.txt +0 -20
- package/src/claude/skills/devops/scripts/tests/requirements.txt +0 -3
- package/src/claude/skills/devops/scripts/tests/test_cloudflare_deploy.py +0 -285
- package/src/claude/skills/devops/scripts/tests/test_docker_optimize.py +0 -436
- package/src/claude/skills/frontend-design/SKILL.md +0 -135
- package/src/claude/skills/frontend-design/references/ai-multimodal-overview.md +0 -165
- package/src/claude/skills/frontend-design/references/analysis-best-practices.md +0 -80
- package/src/claude/skills/frontend-design/references/analysis-prompts.md +0 -141
- package/src/claude/skills/frontend-design/references/analysis-techniques.md +0 -118
- package/src/claude/skills/frontend-design/references/animejs.md +0 -396
- package/src/claude/skills/frontend-design/references/anti-slop-rules.md +0 -103
- package/src/claude/skills/frontend-design/references/asset-generation.md +0 -337
- package/src/claude/skills/frontend-design/references/bento-motion-engine.md +0 -142
- package/src/claude/skills/frontend-design/references/design-extraction-overview.md +0 -71
- package/src/claude/skills/frontend-design/references/extraction-best-practices.md +0 -141
- package/src/claude/skills/frontend-design/references/extraction-output-templates.md +0 -162
- package/src/claude/skills/frontend-design/references/extraction-prompts.md +0 -127
- package/src/claude/skills/frontend-design/references/magicui-components.md +0 -129
- package/src/claude/skills/frontend-design/references/performance-guardrails.md +0 -169
- package/src/claude/skills/frontend-design/references/premium-design-patterns.md +0 -93
- package/src/claude/skills/frontend-design/references/redesign-audit-checklist.md +0 -114
- package/src/claude/skills/frontend-design/references/technical-accessibility.md +0 -119
- package/src/claude/skills/frontend-design/references/technical-best-practices.md +0 -97
- package/src/claude/skills/frontend-design/references/technical-optimization.md +0 -44
- package/src/claude/skills/frontend-design/references/technical-overview.md +0 -90
- package/src/claude/skills/frontend-design/references/technical-workflows.md +0 -150
- package/src/claude/skills/frontend-design/references/visual-analysis-overview.md +0 -95
- package/src/claude/skills/frontend-design/references/workflow-3d.md +0 -102
- package/src/claude/skills/frontend-design/references/workflow-describe.md +0 -87
- package/src/claude/skills/frontend-design/references/workflow-immersive.md +0 -87
- package/src/claude/skills/frontend-design/references/workflow-quick.md +0 -57
- package/src/claude/skills/frontend-design/references/workflow-screenshot.md +0 -63
- package/src/claude/skills/frontend-design/references/workflow-video.md +0 -74
- package/src/claude/skills/frontend-development/SKILL.md +0 -406
- package/src/claude/skills/frontend-development/resources/common-patterns.md +0 -331
- package/src/claude/skills/frontend-development/resources/complete-examples.md +0 -872
- package/src/claude/skills/frontend-development/resources/component-patterns.md +0 -502
- package/src/claude/skills/frontend-development/resources/data-fetching.md +0 -767
- package/src/claude/skills/frontend-development/resources/file-organization.md +0 -502
- package/src/claude/skills/frontend-development/resources/loading-and-error-states.md +0 -501
- package/src/claude/skills/frontend-development/resources/performance.md +0 -406
- package/src/claude/skills/frontend-development/resources/routing-guide.md +0 -364
- package/src/claude/skills/frontend-development/resources/styling-guide.md +0 -428
- package/src/claude/skills/frontend-development/resources/typescript-standards.md +0 -418
- package/src/claude/skills/mobile-development/SKILL.md +0 -218
- package/src/claude/skills/mobile-development/references/mobile-android.md +0 -604
- package/src/claude/skills/mobile-development/references/mobile-best-practices.md +0 -544
- package/src/claude/skills/mobile-development/references/mobile-debugging.md +0 -1089
- package/src/claude/skills/mobile-development/references/mobile-frameworks.md +0 -465
- package/src/claude/skills/mobile-development/references/mobile-ios.md +0 -496
- package/src/claude/skills/mobile-development/references/mobile-mindset.md +0 -542
- package/src/claude/skills/react-best-practices/AGENTS.md +0 -2249
- package/src/claude/skills/react-best-practices/README.md +0 -123
- package/src/claude/skills/react-best-practices/SKILL.md +0 -128
- package/src/claude/skills/react-best-practices/metadata.json +0 -15
- package/src/claude/skills/react-best-practices/rules/_sections.md +0 -46
- package/src/claude/skills/react-best-practices/rules/_template.md +0 -28
- package/src/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +0 -55
- package/src/claude/skills/react-best-practices/rules/advanced-use-latest.md +0 -49
- package/src/claude/skills/react-best-practices/rules/async-api-routes.md +0 -38
- package/src/claude/skills/react-best-practices/rules/async-defer-await.md +0 -80
- package/src/claude/skills/react-best-practices/rules/async-dependencies.md +0 -36
- package/src/claude/skills/react-best-practices/rules/async-parallel.md +0 -28
- package/src/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +0 -99
- package/src/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +0 -59
- package/src/claude/skills/react-best-practices/rules/bundle-conditional.md +0 -31
- package/src/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +0 -49
- package/src/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +0 -35
- package/src/claude/skills/react-best-practices/rules/bundle-preload.md +0 -50
- package/src/claude/skills/react-best-practices/rules/client-event-listeners.md +0 -74
- package/src/claude/skills/react-best-practices/rules/client-swr-dedup.md +0 -56
- package/src/claude/skills/react-best-practices/rules/js-batch-dom-css.md +0 -82
- package/src/claude/skills/react-best-practices/rules/js-cache-function-results.md +0 -80
- package/src/claude/skills/react-best-practices/rules/js-cache-property-access.md +0 -28
- package/src/claude/skills/react-best-practices/rules/js-cache-storage.md +0 -70
- package/src/claude/skills/react-best-practices/rules/js-combine-iterations.md +0 -32
- package/src/claude/skills/react-best-practices/rules/js-early-exit.md +0 -50
- package/src/claude/skills/react-best-practices/rules/js-hoist-regexp.md +0 -45
- package/src/claude/skills/react-best-practices/rules/js-index-maps.md +0 -37
- package/src/claude/skills/react-best-practices/rules/js-length-check-first.md +0 -49
- package/src/claude/skills/react-best-practices/rules/js-min-max-loop.md +0 -82
- package/src/claude/skills/react-best-practices/rules/js-set-map-lookups.md +0 -24
- package/src/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +0 -57
- package/src/claude/skills/react-best-practices/rules/rendering-activity.md +0 -26
- package/src/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
- package/src/claude/skills/react-best-practices/rules/rendering-conditional-render.md +0 -40
- package/src/claude/skills/react-best-practices/rules/rendering-content-visibility.md +0 -38
- package/src/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +0 -46
- package/src/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
- package/src/claude/skills/react-best-practices/rules/rendering-svg-precision.md +0 -28
- package/src/claude/skills/react-best-practices/rules/rerender-defer-reads.md +0 -39
- package/src/claude/skills/react-best-practices/rules/rerender-dependencies.md +0 -45
- package/src/claude/skills/react-best-practices/rules/rerender-derived-state.md +0 -29
- package/src/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +0 -74
- package/src/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +0 -58
- package/src/claude/skills/react-best-practices/rules/rerender-memo.md +0 -44
- package/src/claude/skills/react-best-practices/rules/rerender-transitions.md +0 -40
- package/src/claude/skills/react-best-practices/rules/server-after-nonblocking.md +0 -73
- package/src/claude/skills/react-best-practices/rules/server-cache-lru.md +0 -41
- package/src/claude/skills/react-best-practices/rules/server-cache-react.md +0 -26
- package/src/claude/skills/react-best-practices/rules/server-parallel-fetching.md +0 -79
- package/src/claude/skills/react-best-practices/rules/server-serialization.md +0 -38
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://haposoft.github.io/cafekit/runtime.schema.json",
|
|
4
|
+
"title": "CafeKit runtime configuration",
|
|
5
|
+
"description": "Project-scoped CafeKit settings, installed as .claude/runtime.json and .codex/runtime.json. Every key is optional; an absent key keeps the built-in default. Editors that honour $schema use this file for completion and inline documentation. Secrets do not belong here: this file is meant to be committed.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Path or URL of this schema. Present so editors can validate the file; CafeKit itself ignores it."
|
|
12
|
+
},
|
|
13
|
+
"privacyBlock": {
|
|
14
|
+
"type": "boolean",
|
|
15
|
+
"default": true,
|
|
16
|
+
"description": "Block reads of files that usually hold secrets (.env, credentials, keys). Set false to disable the privacy hook for this project."
|
|
17
|
+
},
|
|
18
|
+
"inspect": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"description": "The guard that steers broad codebase searches toward the discovery workflow.",
|
|
22
|
+
"properties": {
|
|
23
|
+
"enabled": {
|
|
24
|
+
"type": "boolean",
|
|
25
|
+
"default": true,
|
|
26
|
+
"description": "Set false to stop the inspect guard from blocking broad search commands."
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"docs": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"description": "Documentation conventions surfaced to the agent.",
|
|
34
|
+
"properties": {
|
|
35
|
+
"maxLoc": {
|
|
36
|
+
"type": "integer",
|
|
37
|
+
"minimum": 1,
|
|
38
|
+
"default": 800,
|
|
39
|
+
"description": "Lines allowed in one documentation file before the agent is reminded to split it."
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"paths": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"additionalProperties": false,
|
|
46
|
+
"description": "Where this project keeps its documentation, specifications, and plans, relative to the repository root.",
|
|
47
|
+
"properties": {
|
|
48
|
+
"docs": { "type": "string", "default": "docs", "description": "Documentation root the docs workflow reads and writes." },
|
|
49
|
+
"specs": { "type": "string", "default": "specs", "description": "Specification packet root: one direct child per feature." },
|
|
50
|
+
"plans": { "type": "string", "default": "plans", "description": "Directory holding plan files, one directory per plan." }
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"spec": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"additionalProperties": false,
|
|
56
|
+
"description": "Specification workflow guards. These are convenience switches for local work, not authorizations.",
|
|
57
|
+
"properties": {
|
|
58
|
+
"scaffold_guard": {
|
|
59
|
+
"type": "boolean",
|
|
60
|
+
"default": true,
|
|
61
|
+
"description": "Require task files to be generated by the scaffold script. Set false to write them by hand."
|
|
62
|
+
},
|
|
63
|
+
"tollgate": {
|
|
64
|
+
"type": "boolean",
|
|
65
|
+
"default": true,
|
|
66
|
+
"description": "Report specification state on each prompt. Set false to silence it."
|
|
67
|
+
},
|
|
68
|
+
"completion_gate": {
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"default": true,
|
|
71
|
+
"description": "Not a switch. The completion gate treats this flag as a bypass attempt and blocks while it is present, whatever its value, because a worker-writable file cannot authorize completion. Remove the key and satisfy the gate instead."
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"usage": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"additionalProperties": false,
|
|
78
|
+
"description": "Usage and quota reporting.",
|
|
79
|
+
"properties": {
|
|
80
|
+
"enabled": {
|
|
81
|
+
"type": "boolean",
|
|
82
|
+
"default": true,
|
|
83
|
+
"description": "Set false to stop fetching quota data for the statusline."
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"locale": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"additionalProperties": false,
|
|
90
|
+
"description": "Languages the agent should use. null means English, or match the user.",
|
|
91
|
+
"properties": {
|
|
92
|
+
"thinkingLanguage": { "type": ["string", "null"], "default": null, "description": "Language for reasoning." },
|
|
93
|
+
"responseLanguage": { "type": ["string", "null"], "default": null, "description": "Language for user-facing output." }
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"codingLevel": {
|
|
97
|
+
"type": ["integer", "null"],
|
|
98
|
+
"minimum": 0,
|
|
99
|
+
"maximum": 5,
|
|
100
|
+
"default": 1,
|
|
101
|
+
"description": "Codex only. How much explanation answers carry: 0 ELI5, 1 junior, 2 mid-level, 3 senior, 4 lead, 5 expert. Codex CLI has no output-style feature, so the rules hook injects the matching file from .codex/output-styles/ once per session. Claude Code loads the same styles natively and reads outputStyle from settings.json instead, so this key is ignored there. null or an out-of-range value injects nothing."
|
|
102
|
+
},
|
|
103
|
+
"statusline": {
|
|
104
|
+
"enum": ["full", "compact", "minimal", "none"],
|
|
105
|
+
"default": "full",
|
|
106
|
+
"description": "How much the statusline renders. 'none' prints an empty line."
|
|
107
|
+
},
|
|
108
|
+
"statuslineColors": {
|
|
109
|
+
"type": "boolean",
|
|
110
|
+
"default": true,
|
|
111
|
+
"description": "Set false for a statusline without ANSI colour."
|
|
112
|
+
},
|
|
113
|
+
"statuslineLayout": {
|
|
114
|
+
"type": "object",
|
|
115
|
+
"additionalProperties": false,
|
|
116
|
+
"required": ["lines"],
|
|
117
|
+
"description": "Explicit statusline composition. A valid layout replaces the default renderers; an invalid or empty one falls back to them. The 'statusline' mode still limits how many lines are drawn.",
|
|
118
|
+
"properties": {
|
|
119
|
+
"lines": {
|
|
120
|
+
"type": "array",
|
|
121
|
+
"description": "One entry per rendered line, each listing section ids in display order.",
|
|
122
|
+
"items": {
|
|
123
|
+
"type": "array",
|
|
124
|
+
"items": { "enum": ["model", "context", "quota", "directory", "git", "plan", "cost", "changes"] }
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"assertions": {
|
|
130
|
+
"type": "array",
|
|
131
|
+
"description": "Rules injected for files matching a glob.",
|
|
132
|
+
"items": {
|
|
133
|
+
"type": "object",
|
|
134
|
+
"additionalProperties": false,
|
|
135
|
+
"required": ["pattern", "rule"],
|
|
136
|
+
"properties": {
|
|
137
|
+
"pattern": { "type": "string", "description": "Glob the rule applies to, for example \"**/*.go\"." },
|
|
138
|
+
"rule": { "type": "string", "description": "The rule text shown to the agent." }
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"trust": {
|
|
143
|
+
"type": "object",
|
|
144
|
+
"additionalProperties": false,
|
|
145
|
+
"description": "Local trust prompt. Keep the passphrase in your own user configuration, never in this committed file.",
|
|
146
|
+
"properties": {
|
|
147
|
+
"enabled": { "type": "boolean", "default": false, "description": "Whether a trust passphrase is required." },
|
|
148
|
+
"passphrase": { "type": ["string", "null"], "default": null, "description": "Do not set this here. This file is committed." }
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"project": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"additionalProperties": false,
|
|
154
|
+
"description": "Detection overrides for a repository the defaults read wrong.",
|
|
155
|
+
"properties": {
|
|
156
|
+
"type": { "type": "string", "default": "auto", "description": "Project type, or \"auto\" to detect." },
|
|
157
|
+
"packageManager": { "type": "string", "default": "auto", "description": "Package manager, or \"auto\" to detect." },
|
|
158
|
+
"framework": { "type": "string", "default": "auto", "description": "Framework, or \"auto\" to detect." }
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"plan": {
|
|
162
|
+
"type": "object",
|
|
163
|
+
"additionalProperties": false,
|
|
164
|
+
"description": "Plan directory naming and resolution.",
|
|
165
|
+
"properties": {
|
|
166
|
+
"namingFormat": { "type": "string", "default": "{date}-{issue}-{slug}", "description": "Directory name pattern. Variables: {date}, {issue}, {slug}." },
|
|
167
|
+
"dateFormat": { "type": "string", "default": "YYMMDD-HHmm", "description": "Date portion of the plan name." },
|
|
168
|
+
"issuePrefix": { "type": ["string", "null"], "default": null, "description": "Prefix for the issue portion, for example \"GH-\"." },
|
|
169
|
+
"reportsDir": { "type": "string", "default": "reports", "description": "Reports directory inside a plan." },
|
|
170
|
+
"resolution": {
|
|
171
|
+
"type": "object",
|
|
172
|
+
"additionalProperties": false,
|
|
173
|
+
"description": "How the active plan is chosen. Only explicit session state makes a plan active; a branch match is a suggestion.",
|
|
174
|
+
"properties": {
|
|
175
|
+
"order": { "type": "array", "items": { "enum": ["session", "branch"] }, "description": "Order the sources are consulted in when resolving the active plan." },
|
|
176
|
+
"branchPattern": { "type": "string", "description": "Regular expression extracting a plan slug from the branch name." }
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"validation": {
|
|
180
|
+
"type": "object",
|
|
181
|
+
"additionalProperties": false,
|
|
182
|
+
"description": "Plan validation questioning.",
|
|
183
|
+
"properties": {
|
|
184
|
+
"mode": { "enum": ["auto", "prompt", "off"], "default": "prompt", "description": "When to run validation questions." },
|
|
185
|
+
"minQuestions": { "type": "integer", "minimum": 0, "default": 3, "description": "Fewest questions to ask." },
|
|
186
|
+
"maxQuestions": { "type": "integer", "minimum": 0, "default": 8, "description": "Most questions to ask." },
|
|
187
|
+
"focusAreas": { "type": "array", "items": { "type": "string" }, "description": "Topics the questions should cover." }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"hooks": {
|
|
193
|
+
"type": "object",
|
|
194
|
+
"deprecated": true,
|
|
195
|
+
"description": "Not honoured. No hook consults this map, so an entry here disables nothing. Disable a hook by removing its entry from the host's hook configuration instead.",
|
|
196
|
+
"additionalProperties": { "type": "boolean" }
|
|
197
|
+
},
|
|
198
|
+
"develop": {
|
|
199
|
+
"type": "object",
|
|
200
|
+
"deprecated": true,
|
|
201
|
+
"description": "Not honoured. Parallel execution is chosen per invocation with the --parallel flag, not from this file.",
|
|
202
|
+
"additionalProperties": true
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -1,184 +1,218 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* This mirrors the Research/.claude approach: expose the installed skill set as
|
|
6
|
-
* a readable catalog so the model can choose skills from rules, not from an
|
|
7
|
-
* automatic prompt-scoring hook.
|
|
8
|
-
*/
|
|
2
|
+
/** Generate a fail-closed catalog from the current runtime's installed skills. */
|
|
3
|
+
|
|
4
|
+
'use strict';
|
|
9
5
|
|
|
10
6
|
const fs = require('fs');
|
|
11
7
|
const path = require('path');
|
|
12
8
|
|
|
9
|
+
// Keep synchronized with migration-manifest.json obsolete.skills. Modified
|
|
10
|
+
// retired directories may remain on disk, but they are never automatic routes.
|
|
11
|
+
const RETIRED_DIRECTORIES = new Set([
|
|
12
|
+
'backend-development',
|
|
13
|
+
'frontend-development',
|
|
14
|
+
'frontend-design',
|
|
15
|
+
'mobile-development',
|
|
16
|
+
'devops',
|
|
17
|
+
'react-best-practices',
|
|
18
|
+
]);
|
|
19
|
+
const PUBLIC_SUFFIX_BY_DIRECTORY = {
|
|
20
|
+
hotfix: 'fix',
|
|
21
|
+
inspect: 'scout',
|
|
22
|
+
question: 'ask',
|
|
23
|
+
};
|
|
24
|
+
|
|
13
25
|
function usage() {
|
|
14
26
|
console.log(`Usage:
|
|
15
|
-
node
|
|
27
|
+
node <runtime>/scripts/generate-skill-catalog.cjs [--skills] [--json] [--root <skills-dir>]
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
node .claude/scripts/generate-skill-catalog.cjs --json --root .claude/skills`);
|
|
29
|
+
The default root is bound to the script runtime: .claude/skills for Claude,
|
|
30
|
+
.agents/skills for Codex, and ../skills for the source tree.`);
|
|
20
31
|
}
|
|
21
32
|
|
|
22
33
|
function parseArgs(argv) {
|
|
23
34
|
const args = { json: false, help: false, root: null };
|
|
24
|
-
for (let
|
|
25
|
-
const arg = argv[
|
|
35
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
36
|
+
const arg = argv[index];
|
|
26
37
|
if (arg === '--help' || arg === '-h') args.help = true;
|
|
27
38
|
else if (arg === '--json') args.json = true;
|
|
28
39
|
else if (arg === '--skills') continue;
|
|
29
40
|
else if (arg === '--root') {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
args.root =
|
|
34
|
-
}
|
|
41
|
+
if (!argv[index + 1] || argv[index + 1].startsWith('--')) {
|
|
42
|
+
throw new Error('--root requires a skills directory');
|
|
43
|
+
}
|
|
44
|
+
args.root = argv[++index];
|
|
45
|
+
} else throw new Error(`unknown option: ${arg}`);
|
|
35
46
|
}
|
|
36
47
|
return args;
|
|
37
48
|
}
|
|
38
49
|
|
|
39
50
|
function defaultSkillsRoot() {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return candidates.find((candidate) => fs.existsSync(candidate)) || candidates[0];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function readText(filePath) {
|
|
50
|
-
return fs.readFileSync(filePath, 'utf8');
|
|
51
|
+
const runtimeRoot = path.dirname(__dirname);
|
|
52
|
+
const runtimeName = path.basename(runtimeRoot);
|
|
53
|
+
if (runtimeName === '.codex') return path.join(path.dirname(runtimeRoot), '.agents', 'skills');
|
|
54
|
+
const claudeRuntimeName = `.${['cla', 'ude'].join('')}`;
|
|
55
|
+
if (runtimeName === claudeRuntimeName) return path.join(runtimeRoot, 'skills');
|
|
56
|
+
return path.resolve(__dirname, '..', 'skills');
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
function extractFrontmatter(content) {
|
|
54
|
-
const match = content.match(/^---\
|
|
55
|
-
if (!match) return
|
|
60
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
61
|
+
if (!match) return null;
|
|
56
62
|
const frontmatter = {};
|
|
57
63
|
const lines = match[1].split(/\r?\n/);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
const seen = new Set();
|
|
65
|
+
let nestedKey = null;
|
|
66
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
67
|
+
const line = lines[index];
|
|
68
|
+
if (line.trim() === '') continue;
|
|
69
|
+
if (/^\s+/.test(line)) {
|
|
70
|
+
const nested = line.match(/^ ([A-Za-z0-9_-]+):\s*(\S.*)$/);
|
|
71
|
+
if (!nestedKey || !nested) return null;
|
|
72
|
+
const identity = `${nestedKey}.${nested[1]}`;
|
|
73
|
+
if (seen.has(identity) || quotedValue(nested[2]) === null) return null;
|
|
74
|
+
seen.add(identity);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
nestedKey = null;
|
|
78
|
+
const parsed = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
79
|
+
if (!parsed || seen.has(parsed[1])) return null;
|
|
80
|
+
seen.add(parsed[1]);
|
|
81
|
+
let value = parsed[2].trim();
|
|
82
|
+
if (['>', '>-', '|', '|-'].includes(value)) {
|
|
65
83
|
const block = [];
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
block.push(lines[i].trim());
|
|
69
|
-
i += 1;
|
|
84
|
+
while (index + 1 < lines.length && /^\s+/.test(lines[index + 1])) {
|
|
85
|
+
block.push(lines[++index].trim());
|
|
70
86
|
}
|
|
71
|
-
|
|
87
|
+
if (block.length === 0) return null;
|
|
72
88
|
value = block.join(' ');
|
|
73
89
|
}
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
value = value.slice(1, -1);
|
|
90
|
+
if (value === '') {
|
|
91
|
+
nestedKey = parsed[1];
|
|
92
|
+
frontmatter[parsed[1]] = '';
|
|
93
|
+
continue;
|
|
79
94
|
}
|
|
80
|
-
|
|
95
|
+
value = quotedValue(value);
|
|
96
|
+
if (value === null) return null;
|
|
97
|
+
frontmatter[parsed[1]] = value;
|
|
81
98
|
}
|
|
82
99
|
return frontmatter;
|
|
83
100
|
}
|
|
84
101
|
|
|
85
|
-
function
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
paragraph.push(line);
|
|
95
|
-
if (paragraph.join(' ').length > 160) break;
|
|
102
|
+
function quotedValue(value) {
|
|
103
|
+
const startsQuote = value.startsWith('"') || value.startsWith("'");
|
|
104
|
+
const endsQuote = value.endsWith('"') || value.endsWith("'");
|
|
105
|
+
const startsFlow = value.startsWith('[') || value.startsWith('{');
|
|
106
|
+
const endsFlow = value.endsWith(']') || value.endsWith('}');
|
|
107
|
+
if (startsFlow || endsFlow) {
|
|
108
|
+
const expected = value.startsWith('[') ? ']' : value.startsWith('{') ? '}' : null;
|
|
109
|
+
if (!expected || !value.endsWith(expected)) return null;
|
|
96
110
|
}
|
|
97
|
-
|
|
111
|
+
if (!startsQuote && !endsQuote) return value;
|
|
112
|
+
if (value.length < 2 || value[0] !== value[value.length - 1]) return null;
|
|
113
|
+
return value.slice(1, -1);
|
|
98
114
|
}
|
|
99
115
|
|
|
100
|
-
function
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (/debug|hotfix|inspect|impact|review|test|agent-browser|chrome/.test(text)) return 'quality';
|
|
104
|
-
if (/frontend|react|ui|ux|mobile/.test(text)) return 'frontend-mobile';
|
|
105
|
-
if (/pdf|docx|pptx|xlsx|multimodal/.test(text)) return 'artifacts-tools';
|
|
106
|
-
if (/backend|devops|api|database|deploy/.test(text)) return 'backend-infra';
|
|
107
|
-
if (/docs|research|graph/.test(text)) return 'knowledge';
|
|
108
|
-
if (/git/.test(text)) return 'git';
|
|
109
|
-
return 'other';
|
|
116
|
+
function parseKeywords(value) {
|
|
117
|
+
if (!value || !/^\[[^\]]*\]$/.test(value)) return [];
|
|
118
|
+
return value.slice(1, -1).split(',').map((item) => item.trim()).filter(Boolean);
|
|
110
119
|
}
|
|
111
120
|
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
121
|
+
function publicIdentity(name) {
|
|
122
|
+
const match = String(name).match(/^cf(?::|-)([a-z0-9]+(?:-[a-z0-9]+)*)$/);
|
|
123
|
+
return match ? `cf:${match[1]}` : null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function expectedIdentity(directory) {
|
|
127
|
+
return `cf:${PUBLIC_SUFFIX_BY_DIRECTORY[directory] || directory}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function diagnostic(code, directory, message) {
|
|
131
|
+
return { code, directory, message };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function scanSkills(requestedRoot) {
|
|
135
|
+
if (!fs.existsSync(requestedRoot)) throw new Error(`skills root not found: ${requestedRoot}`);
|
|
136
|
+
const root = fs.realpathSync(requestedRoot);
|
|
137
|
+
const diagnostics = [];
|
|
138
|
+
const candidates = [];
|
|
139
|
+
const entries = fs.readdirSync(root, { withFileTypes: true })
|
|
140
|
+
.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))
|
|
141
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
142
|
+
|
|
118
143
|
for (const entry of entries) {
|
|
119
|
-
if (!entry.isDirectory() || entry.name.startsWith('.')) continue;
|
|
120
144
|
const skillPath = path.join(root, entry.name, 'SKILL.md');
|
|
121
145
|
if (!fs.existsSync(skillPath)) continue;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
146
|
+
if (RETIRED_DIRECTORIES.has(entry.name)) {
|
|
147
|
+
diagnostics.push(diagnostic('retired_skill', entry.name, 'excluded from automatic routing'));
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const frontmatter = extractFrontmatter(fs.readFileSync(skillPath, 'utf8'));
|
|
151
|
+
if (!frontmatter) {
|
|
152
|
+
diagnostics.push(diagnostic('malformed_frontmatter', entry.name, 'missing frontmatter block'));
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const identity = publicIdentity(frontmatter.name);
|
|
156
|
+
if (!identity || !frontmatter.description || frontmatter.description.trim() === '') {
|
|
157
|
+
diagnostics.push(diagnostic('missing_routing_metadata', entry.name, 'requires valid name and description'));
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (identity !== expectedIdentity(entry.name)) {
|
|
161
|
+
diagnostics.push(diagnostic('folder_name_mismatch', entry.name, `${identity} does not match directory`));
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
candidates.push({
|
|
165
|
+
name: frontmatter.name,
|
|
166
|
+
public_id: identity,
|
|
128
167
|
directory: entry.name,
|
|
129
|
-
description,
|
|
130
|
-
|
|
168
|
+
description: frontmatter.description,
|
|
169
|
+
when_to_use: frontmatter.when_to_use || '',
|
|
170
|
+
category: frontmatter.category || 'other',
|
|
171
|
+
keywords: parseKeywords(frontmatter.keywords),
|
|
172
|
+
user_invocable: frontmatter['user-invocable'] !== 'false',
|
|
131
173
|
has_references: fs.existsSync(path.join(root, entry.name, 'references')),
|
|
132
174
|
has_scripts: fs.existsSync(path.join(root, entry.name, 'scripts')),
|
|
133
175
|
});
|
|
134
176
|
}
|
|
135
|
-
|
|
177
|
+
|
|
178
|
+
const counts = new Map();
|
|
179
|
+
for (const skill of candidates) counts.set(skill.public_id, (counts.get(skill.public_id) || 0) + 1);
|
|
180
|
+
const skills = candidates.filter((skill) => {
|
|
181
|
+
if (counts.get(skill.public_id) === 1) return true;
|
|
182
|
+
diagnostics.push(diagnostic('duplicate_public_name', skill.directory, `${skill.public_id} requires explicit user disambiguation`));
|
|
183
|
+
return false;
|
|
184
|
+
}).sort((left, right) => left.public_id.localeCompare(right.public_id));
|
|
185
|
+
|
|
186
|
+
return { root, skills, diagnostics: diagnostics.sort((left, right) =>
|
|
187
|
+
`${left.directory}:${left.code}`.localeCompare(`${right.directory}:${right.code}`)) };
|
|
136
188
|
}
|
|
137
189
|
|
|
138
|
-
function renderMarkdown(
|
|
139
|
-
const lines = [
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
`
|
|
143
|
-
|
|
144
|
-
'',
|
|
145
|
-
];
|
|
146
|
-
const categories = [...new Set(skills.map((skill) => skill.category))].sort();
|
|
147
|
-
for (const category of categories) {
|
|
148
|
-
lines.push(`## ${category}`, '');
|
|
149
|
-
for (const skill of skills.filter((item) => item.category === category)) {
|
|
150
|
-
const badges = [
|
|
151
|
-
skill.has_references ? 'refs' : null,
|
|
152
|
-
skill.has_scripts ? 'scripts' : null,
|
|
153
|
-
].filter(Boolean);
|
|
154
|
-
lines.push(
|
|
155
|
-
`- \`${skill.name}\` (${skill.directory})${badges.length ? ` [${badges.join(', ')}]` : ''}: ${skill.description}`
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
lines.push('');
|
|
190
|
+
function renderMarkdown(catalog) {
|
|
191
|
+
const lines = ['# CafeKit Skills Catalog', '', `Skills root: \`${catalog.root}\``,
|
|
192
|
+
`Routable skills: ${catalog.skills.length}`, ''];
|
|
193
|
+
for (const skill of catalog.skills) {
|
|
194
|
+
const intent = skill.when_to_use ? ` Use: ${skill.when_to_use}` : '';
|
|
195
|
+
lines.push(`- \`${skill.name}\` (${skill.directory}, ${skill.category}): ${skill.description}${intent}`);
|
|
159
196
|
}
|
|
160
|
-
|
|
197
|
+
if (catalog.diagnostics.length > 0) {
|
|
198
|
+
lines.push('', '## Diagnostics', '');
|
|
199
|
+
for (const item of catalog.diagnostics) lines.push(`- ${item.code} (${item.directory}): ${item.message}`);
|
|
200
|
+
}
|
|
201
|
+
return `${lines.join('\n').trim()}\n`;
|
|
161
202
|
}
|
|
162
203
|
|
|
163
204
|
function main() {
|
|
164
205
|
const args = parseArgs(process.argv.slice(2));
|
|
165
|
-
if (args.help)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const root = path.resolve(process.cwd(), args.root || defaultSkillsRoot());
|
|
171
|
-
const skills = scanSkills(root);
|
|
172
|
-
if (args.json) {
|
|
173
|
-
console.log(JSON.stringify({ root, total: skills.length, skills }, null, 2));
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
console.log(renderMarkdown(skills, root));
|
|
206
|
+
if (args.help) return usage();
|
|
207
|
+
const requestedRoot = path.resolve(process.cwd(), args.root || defaultSkillsRoot());
|
|
208
|
+
const catalog = scanSkills(requestedRoot);
|
|
209
|
+
if (args.json) console.log(JSON.stringify({ ...catalog, total: catalog.skills.length }, null, 2));
|
|
210
|
+
else console.log(renderMarkdown(catalog));
|
|
177
211
|
}
|
|
178
212
|
|
|
179
213
|
try {
|
|
180
214
|
main();
|
|
181
215
|
} catch (error) {
|
|
182
216
|
console.error(`[skill-catalog] ${error.message}`);
|
|
183
|
-
process.
|
|
217
|
+
process.exitCode = 1;
|
|
184
218
|
}
|
|
@@ -83,9 +83,22 @@ function oneLine(value, label) {
|
|
|
83
83
|
return output.replace(/\n$/, '');
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
function gitBase(root) {
|
|
87
|
-
const
|
|
88
|
-
|
|
86
|
+
function gitBase(root, specsRoot) {
|
|
87
|
+
const specsRelative = path.relative(root, specsRoot).split(path.sep).join('/');
|
|
88
|
+
const sourceHistory = decode(runGit(
|
|
89
|
+
root,
|
|
90
|
+
['log', '-1', '--format=%H', '--', '.', `:(exclude,literal)${specsRelative}`],
|
|
91
|
+
'git log source base',
|
|
92
|
+
)).trim();
|
|
93
|
+
const roots = sourceHistory ? [] : decode(
|
|
94
|
+
runGit(root, ['rev-list', '--max-parents=0', '--reverse', 'HEAD'], 'git rev-list root'),
|
|
95
|
+
'git rev-list root',
|
|
96
|
+
).trim().split('\n');
|
|
97
|
+
if (!sourceHistory && (roots.length === 0 || roots.some((rootId) => !/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/i.test(rootId)))) {
|
|
98
|
+
fail('malformed_git_output', 'git rev-list root did not return commit ids');
|
|
99
|
+
}
|
|
100
|
+
const output = (sourceHistory || roots[0]).toLowerCase();
|
|
101
|
+
if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(output)) fail('malformed_git_output', 'git source base did not return a commit id');
|
|
89
102
|
return output;
|
|
90
103
|
}
|
|
91
104
|
|
|
@@ -211,11 +224,11 @@ function identity(input) {
|
|
|
211
224
|
|
|
212
225
|
function deriveRuntimeProvenance(input) {
|
|
213
226
|
const current = identity(input);
|
|
214
|
-
const base = gitBase(current.root);
|
|
227
|
+
const base = gitBase(current.root, current.specsRoot);
|
|
215
228
|
const first = manifest(current.root, current.specsRoot);
|
|
216
229
|
const head = manifestDigest(first);
|
|
217
230
|
const second = manifest(current.root, current.specsRoot);
|
|
218
|
-
if (JSON.stringify(first) !== JSON.stringify(second) || gitBase(current.root) !== base) fail('worktree_race', 'checkout changed during provenance capture');
|
|
231
|
+
if (JSON.stringify(first) !== JSON.stringify(second) || gitBase(current.root, current.specsRoot) !== base) fail('worktree_race', 'checkout changed during provenance capture');
|
|
219
232
|
const stable = {
|
|
220
233
|
schema_version: CONTEXT_SCHEMA_VERSION,
|
|
221
234
|
project_root: current.root,
|
|
@@ -1733,7 +1733,7 @@ function evaluateFlashPromotion(task, verdict, proof = 'Verification: PASS', cap
|
|
|
1733
1733
|
status: 'in_progress',
|
|
1734
1734
|
receipt: 'FLASH_UNVERIFIED',
|
|
1735
1735
|
blocker: normalized.diagnostic === 'NO_TESTS'
|
|
1736
|
-
? 'awaiting test proof from /
|
|
1736
|
+
? 'awaiting test proof from /cf:test <feature>'
|
|
1737
1737
|
: normalized.diagnostic === 'PARTIAL'
|
|
1738
1738
|
? 'verification is partial; awaiting complete test proof'
|
|
1739
1739
|
: `verification returned ${normalized.verdict}`,
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/status.cjs\"",
|
|
5
5
|
"padding": 0
|
|
6
6
|
},
|
|
7
|
+
"outputStyle": "Junior Developer Mode (Level 1)",
|
|
7
8
|
"hooks": {
|
|
8
9
|
"SessionStart": [
|
|
9
10
|
{
|
|
@@ -35,9 +36,24 @@
|
|
|
35
36
|
]
|
|
36
37
|
}
|
|
37
38
|
],
|
|
39
|
+
"PreCompact": [
|
|
40
|
+
{
|
|
41
|
+
"matcher": "*",
|
|
42
|
+
"hooks": [
|
|
43
|
+
{
|
|
44
|
+
"type": "command",
|
|
45
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/precompact.cjs\""
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
],
|
|
38
50
|
"UserPromptSubmit": [
|
|
39
51
|
{
|
|
40
52
|
"hooks": [
|
|
53
|
+
{
|
|
54
|
+
"type": "command",
|
|
55
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/secret-output-guardrail.cjs\""
|
|
56
|
+
},
|
|
41
57
|
{
|
|
42
58
|
"type": "command",
|
|
43
59
|
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/rules.cjs\""
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: cf:agent-browser
|
|
3
3
|
description: AI-optimized browser automation CLI with context-efficient snapshots. Use for long autonomous sessions, self-verifying workflows, video recording, and cloud browser testing (Browserbase).
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
user-invocable: true
|