@hegemonart/get-design-done 1.57.1 → 1.57.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +26 -41
- package/.claude-plugin/plugin.json +23 -48
- package/CHANGELOG.md +139 -0
- package/README.md +166 -511
- package/SKILL.md +4 -6
- package/agents/README.md +33 -36
- package/agents/a11y-mapper.md +3 -3
- package/agents/component-benchmark-harvester.md +6 -6
- package/agents/component-benchmark-synthesizer.md +3 -3
- package/agents/compose-executor.md +3 -3
- package/agents/cost-forecaster.md +2 -2
- package/agents/design-auditor.md +7 -7
- package/agents/design-authority-watcher.md +15 -15
- package/agents/design-context-builder.md +4 -4
- package/agents/design-context-checker-gate.md +1 -1
- package/agents/design-discussant.md +2 -2
- package/agents/design-doc-writer.md +1 -1
- package/agents/design-executor.md +2 -2
- package/agents/design-figma-writer.md +2 -2
- package/agents/design-fixer.md +7 -7
- package/agents/design-integration-checker-gate.md +1 -1
- package/agents/design-integration-checker.md +1 -1
- package/agents/design-paper-writer.md +3 -3
- package/agents/design-pencil-writer.md +1 -1
- package/agents/design-planner.md +21 -0
- package/agents/design-reflector.md +39 -39
- package/agents/design-research-synthesizer.md +1 -0
- package/agents/design-start-writer.md +1 -1
- package/agents/design-update-checker.md +5 -5
- package/agents/design-verifier-gate.md +1 -1
- package/agents/design-verifier.md +52 -48
- package/agents/ds-generator.md +2 -2
- package/agents/ds-migration-planner.md +4 -4
- package/agents/email-executor.md +9 -9
- package/agents/experiment-result-ingester.md +3 -3
- package/agents/flutter-executor.md +5 -5
- package/agents/gdd-graph-refresh.md +3 -3
- package/agents/gdd-intel-updater.md +2 -2
- package/agents/motion-mapper.md +2 -2
- package/agents/motion-verifier.md +4 -4
- package/agents/pdf-executor.md +8 -8
- package/agents/perf-analyzer.md +17 -17
- package/agents/pr-commenter.md +9 -9
- package/agents/prototype-gate.md +2 -2
- package/agents/quality-gate-runner.md +1 -1
- package/agents/rollout-coordinator.md +3 -3
- package/agents/swift-executor.md +4 -4
- package/agents/ticket-sync-agent.md +6 -6
- package/agents/user-research-synthesizer.md +2 -2
- package/connections/connections.md +44 -45
- package/connections/cursor.md +72 -0
- package/connections/preview.md +3 -3
- package/hooks/first-run-nudge.cjs +171 -0
- package/hooks/gdd-intel-trigger.js +243 -0
- package/hooks/gdd-mcp-circuit-breaker.js +62 -7
- package/hooks/gdd-precompact-snapshot.js +50 -29
- package/hooks/gdd-protected-paths.js +150 -18
- package/hooks/gdd-risk-gate.js +93 -1
- package/hooks/gdd-sessionstart-recap.js +59 -24
- package/hooks/hooks.json +13 -4
- package/hooks/inject-using-gdd.cjs +188 -0
- package/hooks/update-check.cjs +511 -0
- package/package.json +9 -3
- package/reference/STATE-TEMPLATE.md +10 -13
- package/reference/audit-scoring.md +1 -1
- package/reference/cache-tier-doctrine.md +46 -0
- package/reference/config-schema.md +9 -9
- package/reference/i18n.md +1 -1
- package/reference/intel-schema.md +37 -2
- package/reference/meta-rules.md +4 -4
- package/reference/model-tiers.md +2 -2
- package/reference/registry.json +101 -94
- package/reference/runtime-models.md +11 -1
- package/reference/shared-preamble.md +13 -14
- package/reference/skill-graph.md +22 -3
- package/scripts/bootstrap.cjs +373 -0
- package/scripts/injection-patterns.cjs +58 -0
- package/scripts/lib/apply-reflections/incubator-proposals.cjs +57 -26
- package/scripts/lib/install/converters/codex-plugin.cjs +5 -2
- package/scripts/lib/install/converters/cursor.cjs +20 -0
- package/scripts/lib/issue-reporter/report-flow.cjs +1 -1
- package/scripts/lib/manifest/skills.json +75 -28
- package/scripts/lib/state/query-surface.cjs +67 -9
- package/scripts/lib/state/state-store.cjs +68 -26
- package/scripts/lib/worktree-resolve.cjs +4 -16
- package/sdk/cli/commands/stage.ts +17 -0
- package/sdk/cli/index.js +14 -0
- package/skills/README.md +46 -0
- package/skills/bootstrap-ds/SKILL.md +1 -1
- package/skills/cache-manager/SKILL.md +3 -3
- package/skills/cache-manager/cache-policy.md +1 -1
- package/skills/compare/SKILL.md +1 -1
- package/skills/design/SKILL.md +19 -0
- package/skills/explore/SKILL.md +11 -0
- package/skills/figma-write/SKILL.md +13 -2
- package/skills/new-cycle/SKILL.md +1 -1
- package/skills/paper-write/SKILL.md +54 -0
- package/skills/peer-cli-customize/SKILL.md +0 -1
- package/skills/peers/SKILL.md +1 -1
- package/skills/pencil-write/SKILL.md +54 -0
- package/skills/reflect/procedures/capability-gap-scan.md +0 -1
- package/skills/report-issue/SKILL.md +2 -2
- package/skills/report-issue/report-issue-procedure.md +0 -1
- package/skills/router/SKILL.md +2 -2
- package/skills/synthesize/SKILL.md +1 -1
- package/skills/turn-closeout/SKILL.md +1 -1
- package/skills/verify/verify-procedure.md +10 -11
- package/skills/warm-cache/SKILL.md +1 -1
- package/dist/claude-code/.claude/skills/add-backlog/SKILL.md +0 -48
- package/dist/claude-code/.claude/skills/analyze-dependencies/SKILL.md +0 -95
- package/dist/claude-code/.claude/skills/apply-reflections/SKILL.md +0 -109
- package/dist/claude-code/.claude/skills/apply-reflections/apply-reflections-procedure.md +0 -170
- package/dist/claude-code/.claude/skills/audit/SKILL.md +0 -79
- package/dist/claude-code/.claude/skills/bandit-status/SKILL.md +0 -94
- package/dist/claude-code/.claude/skills/benchmark/SKILL.md +0 -65
- package/dist/claude-code/.claude/skills/bootstrap-ds/SKILL.md +0 -43
- package/dist/claude-code/.claude/skills/brief/SKILL.md +0 -145
- package/dist/claude-code/.claude/skills/budget/SKILL.md +0 -45
- package/dist/claude-code/.claude/skills/cache-manager/SKILL.md +0 -66
- package/dist/claude-code/.claude/skills/cache-manager/cache-policy.md +0 -126
- package/dist/claude-code/.claude/skills/check-update/SKILL.md +0 -98
- package/dist/claude-code/.claude/skills/compare/SKILL.md +0 -82
- package/dist/claude-code/.claude/skills/compare/compare-rubric.md +0 -171
- package/dist/claude-code/.claude/skills/complete-cycle/SKILL.md +0 -81
- package/dist/claude-code/.claude/skills/connections/SKILL.md +0 -71
- package/dist/claude-code/.claude/skills/connections/connections-onboarding.md +0 -608
- package/dist/claude-code/.claude/skills/context/SKILL.md +0 -137
- package/dist/claude-code/.claude/skills/continue/SKILL.md +0 -24
- package/dist/claude-code/.claude/skills/darkmode/SKILL.md +0 -76
- package/dist/claude-code/.claude/skills/darkmode/darkmode-audit-procedure.md +0 -258
- package/dist/claude-code/.claude/skills/debug/SKILL.md +0 -41
- package/dist/claude-code/.claude/skills/debug/debug-feedback-loops.md +0 -119
- package/dist/claude-code/.claude/skills/design/SKILL.md +0 -99
- package/dist/claude-code/.claude/skills/design/design-procedure.md +0 -304
- package/dist/claude-code/.claude/skills/discover/SKILL.md +0 -78
- package/dist/claude-code/.claude/skills/discover/discover-procedure.md +0 -222
- package/dist/claude-code/.claude/skills/discuss/SKILL.md +0 -96
- package/dist/claude-code/.claude/skills/do/SKILL.md +0 -45
- package/dist/claude-code/.claude/skills/explore/SKILL.md +0 -107
- package/dist/claude-code/.claude/skills/explore/explore-procedure.md +0 -267
- package/dist/claude-code/.claude/skills/export/SKILL.md +0 -30
- package/dist/claude-code/.claude/skills/extract-learnings/SKILL.md +0 -114
- package/dist/claude-code/.claude/skills/fast/SKILL.md +0 -91
- package/dist/claude-code/.claude/skills/figma-extract/SKILL.md +0 -64
- package/dist/claude-code/.claude/skills/figma-write/SKILL.md +0 -39
- package/dist/claude-code/.claude/skills/graphify/SKILL.md +0 -49
- package/dist/claude-code/.claude/skills/health/SKILL.md +0 -99
- package/dist/claude-code/.claude/skills/health/health-mcp-detection.md +0 -44
- package/dist/claude-code/.claude/skills/health/health-skill-length-report.md +0 -69
- package/dist/claude-code/.claude/skills/help/SKILL.md +0 -87
- package/dist/claude-code/.claude/skills/instinct/SKILL.md +0 -111
- package/dist/claude-code/.claude/skills/list-assumptions/SKILL.md +0 -61
- package/dist/claude-code/.claude/skills/list-pins/SKILL.md +0 -27
- package/dist/claude-code/.claude/skills/live/SKILL.md +0 -98
- package/dist/claude-code/.claude/skills/locale/SKILL.md +0 -51
- package/dist/claude-code/.claude/skills/map/SKILL.md +0 -89
- package/dist/claude-code/.claude/skills/migrate/SKILL.md +0 -70
- package/dist/claude-code/.claude/skills/migrate-context/SKILL.md +0 -123
- package/dist/claude-code/.claude/skills/new-addendum/SKILL.md +0 -81
- package/dist/claude-code/.claude/skills/new-cycle/SKILL.md +0 -37
- package/dist/claude-code/.claude/skills/new-cycle/milestone-completeness-rubric.md +0 -87
- package/dist/claude-code/.claude/skills/new-project/SKILL.md +0 -53
- package/dist/claude-code/.claude/skills/new-skill/SKILL.md +0 -90
- package/dist/claude-code/.claude/skills/next/SKILL.md +0 -68
- package/dist/claude-code/.claude/skills/note/SKILL.md +0 -48
- package/dist/claude-code/.claude/skills/openrouter-status/SKILL.md +0 -86
- package/dist/claude-code/.claude/skills/optimize/SKILL.md +0 -97
- package/dist/claude-code/.claude/skills/override/SKILL.md +0 -86
- package/dist/claude-code/.claude/skills/pause/SKILL.md +0 -77
- package/dist/claude-code/.claude/skills/peer-cli-add/SKILL.md +0 -88
- package/dist/claude-code/.claude/skills/peer-cli-add/peer-cli-protocol.md +0 -161
- package/dist/claude-code/.claude/skills/peer-cli-customize/SKILL.md +0 -90
- package/dist/claude-code/.claude/skills/peers/SKILL.md +0 -96
- package/dist/claude-code/.claude/skills/pin/SKILL.md +0 -37
- package/dist/claude-code/.claude/skills/plan/SKILL.md +0 -105
- package/dist/claude-code/.claude/skills/plan/plan-procedure.md +0 -278
- package/dist/claude-code/.claude/skills/plant-seed/SKILL.md +0 -48
- package/dist/claude-code/.claude/skills/pr-branch/SKILL.md +0 -32
- package/dist/claude-code/.claude/skills/progress/SKILL.md +0 -107
- package/dist/claude-code/.claude/skills/quality-gate/SKILL.md +0 -90
- package/dist/claude-code/.claude/skills/quality-gate/threat-modeling.md +0 -101
- package/dist/claude-code/.claude/skills/quick/SKILL.md +0 -44
- package/dist/claude-code/.claude/skills/reapply-patches/SKILL.md +0 -32
- package/dist/claude-code/.claude/skills/recall/SKILL.md +0 -75
- package/dist/claude-code/.claude/skills/reflect/SKILL.md +0 -85
- package/dist/claude-code/.claude/skills/reflect/procedures/capability-gap-scan.md +0 -120
- package/dist/claude-code/.claude/skills/report-issue/SKILL.md +0 -53
- package/dist/claude-code/.claude/skills/report-issue/report-issue-procedure.md +0 -120
- package/dist/claude-code/.claude/skills/resume/SKILL.md +0 -93
- package/dist/claude-code/.claude/skills/review-backlog/SKILL.md +0 -46
- package/dist/claude-code/.claude/skills/review-decisions/SKILL.md +0 -42
- package/dist/claude-code/.claude/skills/roi/SKILL.md +0 -54
- package/dist/claude-code/.claude/skills/rollout-status/SKILL.md +0 -35
- package/dist/claude-code/.claude/skills/router/SKILL.md +0 -89
- package/dist/claude-code/.claude/skills/router/capability-gap-emitter.md +0 -65
- package/dist/claude-code/.claude/skills/router/router-pick-emitter.md +0 -78
- package/dist/claude-code/.claude/skills/router/router-rules.md +0 -84
- package/dist/claude-code/.claude/skills/scan/SKILL.md +0 -92
- package/dist/claude-code/.claude/skills/scan/scan-procedure.md +0 -732
- package/dist/claude-code/.claude/skills/settings/SKILL.md +0 -87
- package/dist/claude-code/.claude/skills/ship/SKILL.md +0 -48
- package/dist/claude-code/.claude/skills/sketch/SKILL.md +0 -78
- package/dist/claude-code/.claude/skills/sketch-wrap-up/SKILL.md +0 -92
- package/dist/claude-code/.claude/skills/skill-manifest/SKILL.md +0 -79
- package/dist/claude-code/.claude/skills/spike/SKILL.md +0 -67
- package/dist/claude-code/.claude/skills/spike-wrap-up/SKILL.md +0 -86
- package/dist/claude-code/.claude/skills/start/SKILL.md +0 -67
- package/dist/claude-code/.claude/skills/start/start-procedure.md +0 -115
- package/dist/claude-code/.claude/skills/state/SKILL.md +0 -106
- package/dist/claude-code/.claude/skills/stats/SKILL.md +0 -51
- package/dist/claude-code/.claude/skills/style/SKILL.md +0 -71
- package/dist/claude-code/.claude/skills/style/style-doc-procedure.md +0 -150
- package/dist/claude-code/.claude/skills/synthesize/SKILL.md +0 -94
- package/dist/claude-code/.claude/skills/timeline/SKILL.md +0 -66
- package/dist/claude-code/.claude/skills/todo/SKILL.md +0 -64
- package/dist/claude-code/.claude/skills/turn-closeout/SKILL.md +0 -95
- package/dist/claude-code/.claude/skills/undo/SKILL.md +0 -31
- package/dist/claude-code/.claude/skills/unlock-decision/SKILL.md +0 -54
- package/dist/claude-code/.claude/skills/unpin/SKILL.md +0 -31
- package/dist/claude-code/.claude/skills/update/SKILL.md +0 -56
- package/dist/claude-code/.claude/skills/using-gdd/SKILL.md +0 -78
- package/dist/claude-code/.claude/skills/verify/SKILL.md +0 -113
- package/dist/claude-code/.claude/skills/verify/verify-procedure.md +0 -512
- package/dist/claude-code/.claude/skills/warm-cache/SKILL.md +0 -81
- package/dist/claude-code/.claude/skills/watch-authorities/SKILL.md +0 -82
- package/dist/claude-code/.claude/skills/zoom-out/SKILL.md +0 -26
- package/hooks/first-run-nudge.sh +0 -82
- package/hooks/inject-using-gdd.sh +0 -72
- package/hooks/run-hook.cmd +0 -35
- package/hooks/update-check.sh +0 -251
- package/scripts/lib/audit-aggregator/index.cjs +0 -219
- package/scripts/lib/hedge-ensemble.cjs +0 -217
- package/skills/discover/SKILL.md +0 -78
- package/skills/discover/discover-procedure.md +0 -222
- package/skills/new-cycle/milestone-completeness-rubric.md +0 -87
- package/skills/scan/SKILL.md +0 -92
- package/skills/scan/scan-procedure.md +0 -732
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# Runtime Models - Per-Runtime Tier→Model Adapter Map
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Single canonical map from Anthropic tier names (`opus|sonnet|haiku`) and runtime-neutral reasoning-class aliases (`high|medium|low`) to concrete model identifiers for each of the 14 runtimes the multi-runtime installer ships to.
|
|
4
|
+
|
|
5
|
+
> ## ⚠️ Verification status
|
|
6
|
+
>
|
|
7
|
+
> 4 of 14 runtime entries below are **verified** against their author docs (claude, codex, gemini, qwen).
|
|
8
|
+
>
|
|
9
|
+
> 10 entries are **unverified** placeholder fills (Anthropic-default mapping where the runtime is BYOK / multi-provider; or single-tier marker when only one model is exposed). Their `source_url` is prefixed with `<TODO: confirm at …>`. Treat these tier names as best-effort; the resolved model may differ for users whose runtime config diverges from the published default.
|
|
10
|
+
>
|
|
11
|
+
> Unverified: kilo, copilot, cursor, windsurf, antigravity, augment, trae, codebuddy, cline, opencode.
|
|
12
|
+
>
|
|
13
|
+
> The schema (`reference/schemas/runtime-models.schema.json`) explicitly accepts the placeholder marker so the file ships shape-valid; the unverified-ness is a content gap, not a structural defect.
|
|
4
14
|
|
|
5
15
|
This file is parsed by `scripts/lib/install/parse-runtime-models.cjs` and consumed by:
|
|
6
16
|
|
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
name: shared-preamble
|
|
3
3
|
type: preamble
|
|
4
4
|
version: 2.0.0
|
|
5
|
-
phase: 28.5
|
|
6
5
|
tags: [shared, preamble, principles, design-quality, agent-import, cache-prefix, extracted]
|
|
7
|
-
last_updated: 2026-
|
|
6
|
+
last_updated: 2026-06-03
|
|
8
7
|
---
|
|
9
8
|
|
|
10
|
-
#
|
|
9
|
+
# GDD Agent Shared Preamble
|
|
11
10
|
|
|
12
|
-
> **This file is imported via `@reference/shared-preamble.md` as the first line of every agent body in `agents/*.md`. Its placement is essential for Anthropic's 5-minute prompt cache (see `./model-tiers.md`
|
|
11
|
+
> **This file is imported via `@reference/shared-preamble.md` as the first line of every agent body in `agents/*.md`. Its placement is essential for Anthropic's 5-minute prompt cache (see `./model-tiers.md`): because every agent opens with the identical preamble prefix, the second and subsequent agent spawns in a session pay `cached_input_per_1m` rates rather than full `input_per_1m` rates for these bytes. Do not inline this content into agent bodies - always import.**
|
|
13
12
|
>
|
|
14
|
-
> **
|
|
13
|
+
> **This file is an aggregator.** The framework-invariant subsections (Required Reading Discipline, Writes Protocol, Deviation Handling, Completion Markers, Context-Exhaustion & Budget awareness) live in `./meta-rules.md` (tier L0) so the L2 heuristics/anti-patterns/checklists churn never invalidates the L0 prefix.
|
|
15
14
|
>
|
|
16
|
-
> **
|
|
15
|
+
> **This file also serves the design-family skills.** Sections below the agent-preamble block (## Design Quality Pillars, ## Token-First Reasoning, ## Output Contract Reminders, ## Connection Handshake Summary) are the canonical home for principle-recitation that previously inlined across `skills/audit`, `skills/style`, `skills/darkmode`, `skills/compare`, `skills/figma-write`, `skills/connections`, `skills/benchmark`. Skills cross-link here instead of restating these lists.
|
|
17
16
|
|
|
18
17
|
@reference/meta-rules.md
|
|
19
18
|
|
|
@@ -21,16 +20,16 @@ last_updated: 2026-05-18
|
|
|
21
20
|
|
|
22
21
|
Two distinct consumers, one canonical home:
|
|
23
22
|
|
|
24
|
-
1. **Agents** (`agents/*.md`) import this file via `@reference/shared-preamble.md` to inherit the
|
|
25
|
-
2. **Skills** (`skills/<name>/SKILL.md`) cross-link to specific sections (`./shared-preamble.md#design-quality-pillars`, etc.) instead of restating recurring principle lists inline. This is the
|
|
23
|
+
1. **Agents** (`agents/*.md`) import this file via `@reference/shared-preamble.md` to inherit the GDD framework identity + L0 invariants (cache-stable prefix). Agents do not "read" the design-family sections below; those are passive content the cache covers for free.
|
|
24
|
+
2. **Skills** (`skills/<name>/SKILL.md`) cross-link to specific sections (`./shared-preamble.md#design-quality-pillars`, etc.) instead of restating recurring principle lists inline. This is the extract-then-link discipline: principle text lives in one place; skills point at it.
|
|
26
25
|
|
|
27
26
|
## Framework Identity
|
|
28
27
|
|
|
29
|
-
You are a
|
|
28
|
+
You are a GDD agent operating under the `get-design-done` plugin contract (see `agents/README.md` for the full authoring contract). You are spawned by a pipeline stage (or by another agent) via the Claude Code `Task` tool with a fully self-contained prompt. You have **zero session memory** - everything you need is in the prompt string and the files listed inside its `<required_reading>` block.
|
|
30
29
|
|
|
31
30
|
You are one step in a pipeline. You do not own the pipeline. The orchestrator decides what runs next based on your output.
|
|
32
31
|
|
|
33
|
-
## Ordering Convention
|
|
32
|
+
## Ordering Convention
|
|
34
33
|
|
|
35
34
|
Your agent body is structured in this exact order so the cache prefix stays stable:
|
|
36
35
|
|
|
@@ -42,9 +41,9 @@ Do not reorder. Do not inline this preamble. Do not splice dynamic content ahead
|
|
|
42
41
|
|
|
43
42
|
## Pre-Warming
|
|
44
43
|
|
|
45
|
-
The `/gdd:warm-cache` command
|
|
44
|
+
The `/gdd:warm-cache` command pre-warms this identical prefix in the Anthropic cache before a design sprint, so the first real agent spawn of the sprint is already a cache hit on the shared-preamble bytes. You do not need to do anything special to participate - just keep the import directive at the top of your body.
|
|
46
45
|
|
|
47
|
-
## Design Philosophy Layer
|
|
46
|
+
## Design Philosophy Layer
|
|
48
47
|
|
|
49
48
|
The framework is anchored to three design philosophy references that agents may read during brief, audit, and verify stages:
|
|
50
49
|
|
|
@@ -106,8 +105,8 @@ Probe pattern (used by `skills/darkmode`, `skills/compare`, `skills/figma-write`
|
|
|
106
105
|
2. **Live tool call** - invoke a metadata endpoint (e.g., `preview_list`, `get_metadata`). Success → `available`. Error → `unavailable`.
|
|
107
106
|
3. **Write to STATE.md `<connections>`** - three-value schema (`available | unavailable | not_configured`). Never add new values.
|
|
108
107
|
|
|
109
|
-
For full per-connection probe scripts (figma, refero, preview, etc.) see the individual `connections/<name>.md` files. For the onboarding wizard flow, see `./connections-onboarding.md
|
|
108
|
+
For full per-connection probe scripts (figma, refero, preview, etc.) see the individual `connections/<name>.md` files. For the onboarding wizard flow, see `./connections-onboarding.md`.
|
|
110
109
|
|
|
111
110
|
---
|
|
112
111
|
|
|
113
|
-
*Imported by: every file under `agents/*.md` (except `agents/README.md`). Cross-linked by: design-family skills under `skills/{audit,style,darkmode,compare,figma-write,connections,benchmark}/SKILL.md`.
|
|
112
|
+
*Imported by: every file under `agents/*.md` (except `agents/README.md`). Cross-linked by: design-family skills under `skills/{audit,style,darkmode,compare,figma-write,connections,benchmark}/SKILL.md`. Edits to this file affect every agent simultaneously - verify across the full agent suite before committing.*
|
package/reference/skill-graph.md
CHANGED
|
@@ -9,13 +9,12 @@ is a `composes_with` edge (the source calls the target as sub-orchestration); a
|
|
|
9
9
|
a `next_skills` edge (a pipeline hint for what runs next). Stage grouping is best-effort and
|
|
10
10
|
inferred from the skill name; skills with no stage keyword fall under Utility.
|
|
11
11
|
|
|
12
|
-
Skills: 94. Composition edges:
|
|
12
|
+
Skills: 94. Composition edges: 19 composes_with, 6 next_skills.
|
|
13
13
|
|
|
14
14
|
```mermaid
|
|
15
15
|
flowchart TD
|
|
16
16
|
subgraph intake["Intake"]
|
|
17
17
|
n_brief["brief"]
|
|
18
|
-
n_discover["discover"]
|
|
19
18
|
n_new_cycle["new-cycle"]
|
|
20
19
|
n_new_project["new-project"]
|
|
21
20
|
n_start["start"]
|
|
@@ -52,7 +51,6 @@ flowchart TD
|
|
|
52
51
|
n_complete_cycle["complete-cycle"]
|
|
53
52
|
n_quality_gate["quality-gate"]
|
|
54
53
|
n_review_backlog["review-backlog"]
|
|
55
|
-
n_scan["scan"]
|
|
56
54
|
n_turn_closeout["turn-closeout"]
|
|
57
55
|
n_verify["verify"]
|
|
58
56
|
end
|
|
@@ -91,10 +89,12 @@ flowchart TD
|
|
|
91
89
|
n_note["note"]
|
|
92
90
|
n_openrouter_status["openrouter-status"]
|
|
93
91
|
n_override["override"]
|
|
92
|
+
n_paper_write["paper-write"]
|
|
94
93
|
n_pause["pause"]
|
|
95
94
|
n_peer_cli_add["peer-cli-add"]
|
|
96
95
|
n_peer_cli_customize["peer-cli-customize"]
|
|
97
96
|
n_peers["peers"]
|
|
97
|
+
n_pencil_write["pencil-write"]
|
|
98
98
|
n_pin["pin"]
|
|
99
99
|
n_plant_seed["plant-seed"]
|
|
100
100
|
n_pr_branch["pr-branch"]
|
|
@@ -122,10 +122,29 @@ flowchart TD
|
|
|
122
122
|
n_zoom_out["zoom-out"]
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
+
n_apply_reflections --> n_audit
|
|
126
|
+
n_brief --> n_explore
|
|
125
127
|
n_brief -.-> n_explore
|
|
128
|
+
n_compare --> n_verify
|
|
129
|
+
n_complete_cycle --> n_audit
|
|
130
|
+
n_darkmode --> n_audit
|
|
131
|
+
n_design --> n_figma_write
|
|
132
|
+
n_design --> n_paper_write
|
|
133
|
+
n_design --> n_pencil_write
|
|
126
134
|
n_design -.-> n_verify
|
|
135
|
+
n_discuss --> n_list_assumptions
|
|
136
|
+
n_explore --> n_discuss
|
|
137
|
+
n_explore --> n_list_assumptions
|
|
138
|
+
n_explore --> n_sketch
|
|
127
139
|
n_explore -.-> n_plan
|
|
140
|
+
n_new_cycle --> n_brief
|
|
141
|
+
n_new_project --> n_brief
|
|
128
142
|
n_new_project -.-> n_brief
|
|
129
143
|
n_plan -.-> n_design
|
|
144
|
+
n_ship --> n_pr_branch
|
|
145
|
+
n_sketch --> n_sketch_wrap_up
|
|
146
|
+
n_spike --> n_spike_wrap_up
|
|
147
|
+
n_verify --> n_audit
|
|
148
|
+
n_verify --> n_debug
|
|
130
149
|
n_verify -.-> n_ship
|
|
131
150
|
```
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pure-Node port of scripts/bootstrap.sh.
|
|
6
|
+
*
|
|
7
|
+
* Original: scripts/bootstrap.sh — get-design-done SessionStart bootstrap.
|
|
8
|
+
* Auto-provisions companion resources that get-design-done references but
|
|
9
|
+
* which are not Claude Code plugins (so they cannot be listed in `dependencies`).
|
|
10
|
+
*
|
|
11
|
+
* Idempotency: a marker file under ${CLAUDE_PLUGIN_DATA}/bootstrap-manifest.txt
|
|
12
|
+
* is compared byte-for-byte to the bundled scripts/bootstrap-manifest.txt.
|
|
13
|
+
* If they match, the script no-ops — only first install (or a manifest bump)
|
|
14
|
+
* triggers the network/IO work.
|
|
15
|
+
*
|
|
16
|
+
* Behavior preserved from the .sh:
|
|
17
|
+
* - Env-var fallbacks: CLAUDE_PLUGIN_DATA → ~/.claude/plugins/data/get-design-done,
|
|
18
|
+
* CLAUDE_PLUGIN_ROOT → resolved relative to this script (../).
|
|
19
|
+
* - Windows backslash normalization for both env vars (\ → /).
|
|
20
|
+
* - mkdir -p of PLUGIN_DATA, ~/.claude/libs, ~/.claude/skills.
|
|
21
|
+
* - Clone (--depth 1 --quiet) or `git -C <target> pull --quiet --ff-only`
|
|
22
|
+
* for VoltAgent/awesome-design-md. We DO shell out to the `git` CLI
|
|
23
|
+
* (that's a real dep, not bash) via spawnSync — the rule against
|
|
24
|
+
* spawnSync is specifically against spawnSync('bash', …).
|
|
25
|
+
* - Soft-notice (stderr only) if ~/.claude/skills/emil-design-eng is absent.
|
|
26
|
+
* - Ensures cwd/.design/budget.json with the literal default JSON from the .sh
|
|
27
|
+
* (written atomically via .tmp + rename).
|
|
28
|
+
* - Ensures cwd/.design/telemetry/.
|
|
29
|
+
* - Copies manifest → marker on success.
|
|
30
|
+
* - Silent-on-failure: every error path collapses to exit 0. Only logs go to
|
|
31
|
+
* stderr with the `[get-design-done bootstrap]` prefix.
|
|
32
|
+
*
|
|
33
|
+
* Sourcing-guard pattern: helpers are exported on module.exports; main() only
|
|
34
|
+
* runs when this file is the entry point (require.main === module). Tests can
|
|
35
|
+
* require() this module and exercise helpers without triggering the network
|
|
36
|
+
* clone or the cwd/.design/ side effects.
|
|
37
|
+
*
|
|
38
|
+
* Module.exports.run({argv, env, cwd}) accepts optional injection for tests.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
const fs = require('node:fs');
|
|
42
|
+
const path = require('node:path');
|
|
43
|
+
const os = require('node:os');
|
|
44
|
+
const { spawnSync } = require('node:child_process');
|
|
45
|
+
|
|
46
|
+
const LOG_PREFIX = '[get-design-done bootstrap]';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Stderr logger matching the .sh `log()` function.
|
|
50
|
+
* @param {string} msg
|
|
51
|
+
*/
|
|
52
|
+
function log(msg) {
|
|
53
|
+
// The .sh used: printf '[get-design-done bootstrap] %s\n' "$*" >&2
|
|
54
|
+
process.stderr.write(`${LOG_PREFIX} ${msg}\n`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Normalize Windows backslashes to forward slashes, mirroring the bash
|
|
59
|
+
* `${VAR//\\//}` parameter expansion used in the .sh.
|
|
60
|
+
* @param {string|undefined|null} p
|
|
61
|
+
* @returns {string}
|
|
62
|
+
*/
|
|
63
|
+
function normalizeSlashes(p) {
|
|
64
|
+
if (p === undefined || p === null) return '';
|
|
65
|
+
return String(p).replace(/\\/g, '/');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Default for CLAUDE_PLUGIN_DATA — matches the .sh fallback exactly.
|
|
70
|
+
* Returns forward-slash form so the bash-style normalization is a no-op
|
|
71
|
+
* here; the env-var path still gets normalized in resolveContext.
|
|
72
|
+
* @param {string} home
|
|
73
|
+
*/
|
|
74
|
+
function defaultPluginData(home) {
|
|
75
|
+
return normalizeSlashes(path.join(home, '.claude', 'plugins', 'data', 'get-design-done'));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Default for CLAUDE_PLUGIN_ROOT — matches the .sh fallback:
|
|
80
|
+
* `cd "$(dirname "$0")/.." && pwd`
|
|
81
|
+
* In Node terms: the parent of __dirname.
|
|
82
|
+
*/
|
|
83
|
+
function defaultPluginRoot() {
|
|
84
|
+
return normalizeSlashes(path.resolve(__dirname, '..'));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the full set of paths/flags the script needs.
|
|
89
|
+
* Pure — no IO. Exposed for tests.
|
|
90
|
+
* @param {{env?: NodeJS.ProcessEnv, home?: string}} [opts]
|
|
91
|
+
*/
|
|
92
|
+
function resolveContext(opts = {}) {
|
|
93
|
+
const env = opts.env || process.env;
|
|
94
|
+
const home = opts.home || os.homedir();
|
|
95
|
+
|
|
96
|
+
const pluginDataRaw = env.CLAUDE_PLUGIN_DATA || defaultPluginData(home);
|
|
97
|
+
const pluginData = normalizeSlashes(pluginDataRaw);
|
|
98
|
+
|
|
99
|
+
const pluginRootRaw = env.CLAUDE_PLUGIN_ROOT || defaultPluginRoot();
|
|
100
|
+
const pluginRoot = normalizeSlashes(pluginRootRaw);
|
|
101
|
+
|
|
102
|
+
const manifest = `${pluginRoot}/scripts/bootstrap-manifest.txt`;
|
|
103
|
+
const marker = `${pluginData}/bootstrap-manifest.txt`;
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
home,
|
|
107
|
+
pluginData,
|
|
108
|
+
pluginRoot,
|
|
109
|
+
manifest,
|
|
110
|
+
marker,
|
|
111
|
+
libsDir: path.join(home, '.claude', 'libs'),
|
|
112
|
+
skillsDir: path.join(home, '.claude', 'skills'),
|
|
113
|
+
awesomeRepoTarget: path.join(home, '.claude', 'libs', 'awesome-design-md'),
|
|
114
|
+
emilSkillTarget: path.join(home, '.claude', 'skills', 'emil-design-eng'),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Best-effort `mkdir -p`. Swallows EEXIST; logs and swallows everything else.
|
|
120
|
+
* @param {string} dir
|
|
121
|
+
*/
|
|
122
|
+
function ensureDir(dir) {
|
|
123
|
+
try {
|
|
124
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
125
|
+
} catch (err) {
|
|
126
|
+
if (err && err.code !== 'EEXIST') {
|
|
127
|
+
log(`mkdir failed for ${dir} (${err.code || err.message}) — continuing`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Byte-for-byte comparison of two files. Returns true only if both exist and
|
|
134
|
+
* have identical contents. Any error path → false (we'd rather re-run than
|
|
135
|
+
* skip).
|
|
136
|
+
* @param {string} a
|
|
137
|
+
* @param {string} b
|
|
138
|
+
*/
|
|
139
|
+
function filesEqual(a, b) {
|
|
140
|
+
try {
|
|
141
|
+
if (!fs.existsSync(a) || !fs.existsSync(b)) return false;
|
|
142
|
+
const bufA = fs.readFileSync(a);
|
|
143
|
+
const bufB = fs.readFileSync(b);
|
|
144
|
+
if (bufA.length !== bufB.length) return false;
|
|
145
|
+
return bufA.equals(bufB);
|
|
146
|
+
} catch {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Match the .sh `clone_or_update`:
|
|
153
|
+
* - target/.git exists → `git -C target pull --quiet --ff-only`, log on fail
|
|
154
|
+
* - target exists, no .git → log+skip
|
|
155
|
+
* - target absent → `git clone --quiet --depth 1 <url> <target>`, log on fail
|
|
156
|
+
*
|
|
157
|
+
* We invoke the `git` CLI directly via spawnSync. spawnSync('git', …) is fine —
|
|
158
|
+
* the prohibition is on spawnSync('bash', …).
|
|
159
|
+
*
|
|
160
|
+
* @param {string} repoUrl
|
|
161
|
+
* @param {string} target
|
|
162
|
+
*/
|
|
163
|
+
function cloneOrUpdate(repoUrl, target) {
|
|
164
|
+
let isGitCheckout = false;
|
|
165
|
+
let targetExists = false;
|
|
166
|
+
try {
|
|
167
|
+
targetExists = fs.existsSync(target);
|
|
168
|
+
if (targetExists) {
|
|
169
|
+
isGitCheckout = fs.existsSync(path.join(target, '.git'));
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
172
|
+
// fall through — treat as absent
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (isGitCheckout) {
|
|
176
|
+
log(`updating ${target}`);
|
|
177
|
+
const r = spawnSync('git', ['-C', target, 'pull', '--quiet', '--ff-only'], {
|
|
178
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
179
|
+
windowsHide: true,
|
|
180
|
+
});
|
|
181
|
+
if (r.error || r.status !== 0) {
|
|
182
|
+
log(`pull failed for ${target} (continuing)`);
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (targetExists) {
|
|
188
|
+
log(`${target} exists and is not a git checkout — skipping`);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Defense in depth: refuse repoUrl / target arguments that look like git
|
|
193
|
+
// CLI flags (e.g. --upload-pack=evil). Even though both args originate
|
|
194
|
+
// from compile-time constants in resolveContext(), a future refactor
|
|
195
|
+
// could let env-derived values reach this point — fail closed.
|
|
196
|
+
if (typeof repoUrl !== 'string' || repoUrl.startsWith('-') ||
|
|
197
|
+
typeof target !== 'string' || target.startsWith('-')) {
|
|
198
|
+
log(`refusing suspicious clone args for ${repoUrl} -> ${target}`);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
log(`cloning ${repoUrl} -> ${target}`);
|
|
203
|
+
// Use `--` to terminate option parsing so a malicious URL that looks
|
|
204
|
+
// like a flag is treated as a positional arg by git.
|
|
205
|
+
const r = spawnSync('git', ['clone', '--quiet', '--depth', '1', '--', repoUrl, target], {
|
|
206
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
207
|
+
windowsHide: true,
|
|
208
|
+
});
|
|
209
|
+
if (r.error || r.status !== 0) {
|
|
210
|
+
log(`clone failed for ${repoUrl}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Default budget.json content — copied verbatim from the heredoc in the .sh
|
|
216
|
+
* (BUDGET_EOF block, lines 60–69). Trailing newline preserved to match
|
|
217
|
+
* `cat > file <<'EOF'` output.
|
|
218
|
+
*/
|
|
219
|
+
const DEFAULT_BUDGET_JSON = `{
|
|
220
|
+
"per_task_cap_usd": 2.00,
|
|
221
|
+
"per_phase_cap_usd": 20.00,
|
|
222
|
+
"tier_overrides": {},
|
|
223
|
+
"auto_downgrade_on_cap": true,
|
|
224
|
+
"cache_ttl_seconds": 3600,
|
|
225
|
+
"enforcement_mode": "enforce"
|
|
226
|
+
}
|
|
227
|
+
`;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Atomic write: write to <dest>.tmp then rename. Silent on failure.
|
|
231
|
+
* @param {string} dest
|
|
232
|
+
* @param {string} content
|
|
233
|
+
*/
|
|
234
|
+
function atomicWrite(dest, content) {
|
|
235
|
+
const tmp = `${dest}.tmp`;
|
|
236
|
+
try {
|
|
237
|
+
fs.writeFileSync(tmp, content);
|
|
238
|
+
fs.renameSync(tmp, dest);
|
|
239
|
+
return true;
|
|
240
|
+
} catch (err) {
|
|
241
|
+
log(`write failed for ${dest} (${err && (err.code || err.message)}) — continuing`);
|
|
242
|
+
// Best-effort cleanup of the .tmp; ignore any error.
|
|
243
|
+
try { fs.unlinkSync(tmp); } catch {}
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Ensure cwd/.design/budget.json (with defaults) and cwd/.design/telemetry/.
|
|
250
|
+
* Mirrors lines 56–73 of the .sh.
|
|
251
|
+
* @param {string} cwd
|
|
252
|
+
*/
|
|
253
|
+
function ensureDesignDir(cwd) {
|
|
254
|
+
const designDir = path.join(cwd, '.design');
|
|
255
|
+
ensureDir(designDir);
|
|
256
|
+
|
|
257
|
+
const budgetPath = path.join(designDir, 'budget.json');
|
|
258
|
+
let budgetExists = false;
|
|
259
|
+
try {
|
|
260
|
+
budgetExists = fs.existsSync(budgetPath);
|
|
261
|
+
} catch {
|
|
262
|
+
budgetExists = false;
|
|
263
|
+
}
|
|
264
|
+
if (!budgetExists) {
|
|
265
|
+
atomicWrite(budgetPath, DEFAULT_BUDGET_JSON);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
ensureDir(path.join(designDir, 'telemetry'));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Best-effort `cp manifest marker`. The .sh wraps this in `if [[ -f MANIFEST ]]`.
|
|
273
|
+
* @param {string} manifest
|
|
274
|
+
* @param {string} marker
|
|
275
|
+
*/
|
|
276
|
+
function copyManifestToMarker(manifest, marker) {
|
|
277
|
+
try {
|
|
278
|
+
if (!fs.existsSync(manifest)) return;
|
|
279
|
+
} catch {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
const data = fs.readFileSync(manifest);
|
|
284
|
+
// Write atomically so a partial copy doesn't leave a half-written marker
|
|
285
|
+
// that would later equal-compare false but trigger weird states.
|
|
286
|
+
const tmp = `${marker}.tmp`;
|
|
287
|
+
fs.writeFileSync(tmp, data);
|
|
288
|
+
fs.renameSync(tmp, marker);
|
|
289
|
+
} catch (err) {
|
|
290
|
+
log(`copy manifest→marker failed (${err && (err.code || err.message)}) — continuing`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Main entry — equivalent to executing bootstrap.sh top-to-bottom.
|
|
296
|
+
* Always returns 0 (silent-on-failure policy from the .sh: `set -u` + final
|
|
297
|
+
* `exit 0`; no `set -e`, every IO action is guarded). Optional opts allow
|
|
298
|
+
* tests to inject env/cwd/home without mutating process state.
|
|
299
|
+
*
|
|
300
|
+
* @param {{env?: NodeJS.ProcessEnv, cwd?: string, home?: string}} [opts]
|
|
301
|
+
* @returns {number} exit code (always 0)
|
|
302
|
+
*/
|
|
303
|
+
function run(opts = {}) {
|
|
304
|
+
const ctx = resolveContext({ env: opts.env, home: opts.home });
|
|
305
|
+
const cwd = opts.cwd || process.cwd();
|
|
306
|
+
|
|
307
|
+
// mkdir -p "${PLUGIN_DATA}" "${HOME}/.claude/libs" "${HOME}/.claude/skills"
|
|
308
|
+
ensureDir(ctx.pluginData);
|
|
309
|
+
ensureDir(ctx.libsDir);
|
|
310
|
+
ensureDir(ctx.skillsDir);
|
|
311
|
+
|
|
312
|
+
// Early-exit: bundled manifest matches last-run marker.
|
|
313
|
+
if (filesEqual(ctx.manifest, ctx.marker)) {
|
|
314
|
+
return 0;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Required library: VoltAgent/awesome-design-md.
|
|
318
|
+
cloneOrUpdate(
|
|
319
|
+
'https://github.com/VoltAgent/awesome-design-md.git',
|
|
320
|
+
ctx.awesomeRepoTarget
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
// Soft notice for companion skills we cannot auto-install.
|
|
324
|
+
try {
|
|
325
|
+
if (!fs.existsSync(ctx.emilSkillTarget)) {
|
|
326
|
+
log('optional: emil-design-eng skill not found in ~/.claude/skills. See get-design-done README for install options.');
|
|
327
|
+
}
|
|
328
|
+
} catch {
|
|
329
|
+
// ignore — emil notice is purely advisory
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Phase 10.1: .design/budget.json + .design/telemetry/ (D-12).
|
|
333
|
+
ensureDesignDir(cwd);
|
|
334
|
+
|
|
335
|
+
// Record success so we don't re-run until the bundled manifest changes.
|
|
336
|
+
copyManifestToMarker(ctx.manifest, ctx.marker);
|
|
337
|
+
|
|
338
|
+
return 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
module.exports = {
|
|
342
|
+
run,
|
|
343
|
+
// Helpers exported so test/suite/* can exercise them in isolation
|
|
344
|
+
// (sourcing-guard equivalent).
|
|
345
|
+
log,
|
|
346
|
+
normalizeSlashes,
|
|
347
|
+
defaultPluginData,
|
|
348
|
+
defaultPluginRoot,
|
|
349
|
+
resolveContext,
|
|
350
|
+
ensureDir,
|
|
351
|
+
filesEqual,
|
|
352
|
+
cloneOrUpdate,
|
|
353
|
+
atomicWrite,
|
|
354
|
+
ensureDesignDir,
|
|
355
|
+
copyManifestToMarker,
|
|
356
|
+
DEFAULT_BUDGET_JSON,
|
|
357
|
+
LOG_PREFIX,
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// Run main() only when invoked as the entry point.
|
|
361
|
+
if (require.main === module) {
|
|
362
|
+
// Match the .sh: always exit 0 unless a programmer error blows up.
|
|
363
|
+
// run() never throws; if it ever did, we'd still rather no-op silently
|
|
364
|
+
// than crash a SessionStart hook.
|
|
365
|
+
try {
|
|
366
|
+
process.exit(run());
|
|
367
|
+
} catch (err) {
|
|
368
|
+
// Last-resort guard. Surface to stderr (the hook is fire-and-forget)
|
|
369
|
+
// then exit 0 to match silent-on-failure.
|
|
370
|
+
try { log(`unhandled error: ${err && (err.stack || err.message || String(err))} — exiting 0`); } catch {}
|
|
371
|
+
process.exit(0);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Shared prompt-injection patterns — single source of truth for both
|
|
3
|
+
// hooks/gdd-read-injection-scanner.js (runtime hook) and
|
|
4
|
+
// scripts/run-injection-scanner-ci.cjs (CI scanner).
|
|
5
|
+
// Add new patterns here; both consumers pick them up automatically.
|
|
6
|
+
//
|
|
7
|
+
// Phase 14.5 adds three new families: invisible-Unicode obfuscation,
|
|
8
|
+
// HTML-comment instruction hijacks, and secret-exfil trigger patterns.
|
|
9
|
+
|
|
10
|
+
// Zero-width + word-joiner + BOM + bidi overrides. Used for detection
|
|
11
|
+
// AND as a normalization stripper for hooks that run scan after NFKC.
|
|
12
|
+
const _CONTEXT_INVISIBLE_CHARS = /[\u200B-\u200D\u2060\uFEFF\u202A-\u202E]/;
|
|
13
|
+
|
|
14
|
+
const INJECTION_PATTERNS = [
|
|
15
|
+
// ── classic prompt-injection verbs ──────────────────────────────────
|
|
16
|
+
{ name: 'ignore previous', re: /ignore\s+(all\s+)?(previous|prior|above)\s+instructions?/i },
|
|
17
|
+
{ name: 'disregard previous', re: /disregard\s+(all\s+)?(previous|prior|above)\s+instructions?/i },
|
|
18
|
+
{ name: 'forget previous', re: /forget\s+(the\s+|all\s+)?(previous|prior|above)/i },
|
|
19
|
+
{ name: 'you are now a different', re: /you\s+are\s+now\s+a\s+different/i },
|
|
20
|
+
{ name: 'system: you are', re: /system\s*:\s*you\s+are/i },
|
|
21
|
+
{ name: 'role tag injection', re: /<\s*\/?\s*(system|assistant|human)\s*>/i },
|
|
22
|
+
{ name: '[INST] fragment', re: /\[INST\]/i },
|
|
23
|
+
{ name: '### instruction fragment',re: /###\s*instruction/i },
|
|
24
|
+
|
|
25
|
+
// ── invisible-Unicode obfuscation (14.5 new family) ─────────────────
|
|
26
|
+
{ name: 'invisible-unicode chars', re: _CONTEXT_INVISIBLE_CHARS },
|
|
27
|
+
{ name: 'bidi-override instruction', re: /[\u202A-\u202E][^\n]*(ignore|disregard|forget|system\s*:)/i },
|
|
28
|
+
|
|
29
|
+
// ── HTML-comment / hidden-element instruction hijack (14.5 new) ─────
|
|
30
|
+
{ name: 'html-comment system', re: /<!--\s*system\s*:/i },
|
|
31
|
+
{ name: 'html-comment assistant', re: /<!--\s*assistant\s*:/i },
|
|
32
|
+
{ name: 'html-comment ignore', re: /<!--\s*(ignore|disregard|forget)\b/i },
|
|
33
|
+
{ name: 'hidden div system', re: /<div\s+[^>]*style\s*=\s*["'][^"']*display\s*:\s*none[^"']*["'][^>]*>\s*(system|ignore|disregard)/i },
|
|
34
|
+
{ name: 'hidden span system', re: /<span\s+[^>]*style\s*=\s*["'][^"']*visibility\s*:\s*hidden[^"']*["'][^>]*>\s*(system|ignore|disregard)/i },
|
|
35
|
+
{ name: 'zero-font-size trick', re: /style\s*=\s*["'][^"']*font-size\s*:\s*0[^"']*["'][^>]*>\s*(ignore|system|disregard)/i },
|
|
36
|
+
|
|
37
|
+
// ── secret-exfil trigger patterns (14.5 new) ─────────────────────────
|
|
38
|
+
{ name: 'curl-with-api-key-env', re: /curl\s+[^|\n]*\$\{?[A-Z][A-Z0-9_]*_(KEY|TOKEN|SECRET|PASSWORD|AUTH)\}?/ },
|
|
39
|
+
{ name: 'cat-dotenv', re: /\bcat\s+\.env(\.[a-z]+)?\b/ },
|
|
40
|
+
{ name: 'printenv-leak', re: /\bprintenv\b[^\n]{0,80}\|\s*(curl|wget|nc|ssh)/ },
|
|
41
|
+
{ name: 'tar-home-netcat', re: /\btar\s+c[fzvj]+\s+-\s+~[^\n]*\|\s*(nc|ssh|curl)/ },
|
|
42
|
+
{ name: 'env-dot-leak', re: /process\.env\.[A-Z][A-Z0-9_]*_(KEY|TOKEN|SECRET)\s*[^;,\n]*(fetch|axios|XMLHttpRequest|http\.request)/ },
|
|
43
|
+
{ name: 'ssh-key-cat', re: /\bcat\s+~?\/?\.ssh\/id_(rsa|ed25519|ecdsa|dsa)\b/ },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Apply patterns to content and return matched pattern names (deduped).
|
|
48
|
+
*/
|
|
49
|
+
function scan(content) {
|
|
50
|
+
if (typeof content !== 'string' || !content) return [];
|
|
51
|
+
const hits = [];
|
|
52
|
+
for (const { name, re } of INJECTION_PATTERNS) {
|
|
53
|
+
if (re.test(content)) hits.push(name);
|
|
54
|
+
}
|
|
55
|
+
return hits;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = { INJECTION_PATTERNS, _CONTEXT_INVISIBLE_CHARS, scan };
|