hstack 0.1.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.
Files changed (99) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +169 -0
  4. package/VERSION +1 -0
  5. package/dist/cli.js +55 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/doctor.js +155 -0
  8. package/dist/commands/doctor.js.map +1 -0
  9. package/dist/commands/init.js +87 -0
  10. package/dist/commands/init.js.map +1 -0
  11. package/dist/commands/update.js +118 -0
  12. package/dist/commands/update.js.map +1 -0
  13. package/dist/lib/diff.js +120 -0
  14. package/dist/lib/diff.js.map +1 -0
  15. package/dist/lib/git.js +26 -0
  16. package/dist/lib/git.js.map +1 -0
  17. package/dist/lib/paths.js +35 -0
  18. package/dist/lib/paths.js.map +1 -0
  19. package/dist/lib/wire.js +314 -0
  20. package/dist/lib/wire.js.map +1 -0
  21. package/dist/manifest.js +53 -0
  22. package/dist/manifest.js.map +1 -0
  23. package/package.json +54 -0
  24. package/template/.claude/agents/adversarial-reviewer.md +123 -0
  25. package/template/.claude/agents/data-specialist.md +126 -0
  26. package/template/.claude/agents/implementer.md +154 -0
  27. package/template/.claude/agents/planner.md +110 -0
  28. package/template/.claude/agents/product-manager.md +111 -0
  29. package/template/.claude/agents/researcher.md +123 -0
  30. package/template/.claude/agents/security-reviewer.md +123 -0
  31. package/template/.claude/agents/spec-author.md +118 -0
  32. package/template/.claude/agents/test-strategist.md +129 -0
  33. package/template/.claude/agents/ui-ux-briefer.md +105 -0
  34. package/template/.claude/agents/verifier.md +109 -0
  35. package/template/.claude/skills/hstack-adr-new/SKILL.md +118 -0
  36. package/template/.claude/skills/hstack-adversarial-review/SKILL.md +187 -0
  37. package/template/.claude/skills/hstack-branch/SKILL.md +103 -0
  38. package/template/.claude/skills/hstack-change-new/SKILL.md +109 -0
  39. package/template/.claude/skills/hstack-change-plan/SKILL.md +119 -0
  40. package/template/.claude/skills/hstack-commit/SKILL.md +122 -0
  41. package/template/.claude/skills/hstack-configure/SKILL.md +126 -0
  42. package/template/.claude/skills/hstack-data-review/SKILL.md +132 -0
  43. package/template/.claude/skills/hstack-finalize/SKILL.md +159 -0
  44. package/template/.claude/skills/hstack-help/SKILL.md +174 -0
  45. package/template/.claude/skills/hstack-implement/SKILL.md +185 -0
  46. package/template/.claude/skills/hstack-init/SKILL.md +152 -0
  47. package/template/.claude/skills/hstack-module-spec/SKILL.md +105 -0
  48. package/template/.claude/skills/hstack-research/SKILL.md +145 -0
  49. package/template/.claude/skills/hstack-security-review/SKILL.md +133 -0
  50. package/template/.claude/skills/hstack-ship/SKILL.md +128 -0
  51. package/template/.claude/skills/hstack-story-draft/SKILL.md +117 -0
  52. package/template/.claude/skills/hstack-tech-debt-new/SKILL.md +122 -0
  53. package/template/.claude/skills/hstack-tech-debt-resolve/SKILL.md +158 -0
  54. package/template/.claude/skills/hstack-tech-debt-stale/SKILL.md +113 -0
  55. package/template/.claude/skills/hstack-tech-debt-wontfix/SKILL.md +104 -0
  56. package/template/.claude/skills/hstack-telemetry/SKILL.md +96 -0
  57. package/template/.claude/skills/hstack-test-plan/SKILL.md +182 -0
  58. package/template/.claude/skills/hstack-ui-brief/SKILL.md +108 -0
  59. package/template/.claude/skills/hstack-verify/SKILL.md +139 -0
  60. package/template/CLAUDE.md +390 -0
  61. package/template/scripts/telemetry/__init__.py +6 -0
  62. package/template/scripts/telemetry/insights/__init__.py +0 -0
  63. package/template/scripts/telemetry/insights/contract_drift.py +137 -0
  64. package/template/scripts/telemetry/insights/overengineering.py +115 -0
  65. package/template/scripts/telemetry/insights/quality_outcomes.py +131 -0
  66. package/template/scripts/telemetry/insights/token_economics.py +129 -0
  67. package/template/scripts/telemetry/insights/workflow_shape.py +198 -0
  68. package/template/scripts/telemetry/parsers/__init__.py +0 -0
  69. package/template/scripts/telemetry/parsers/bodies.py +87 -0
  70. package/template/scripts/telemetry/parsers/commits.py +219 -0
  71. package/template/scripts/telemetry/parsers/frontmatter.py +322 -0
  72. package/template/scripts/telemetry/parsers/transcripts.py +181 -0
  73. package/template/scripts/telemetry/render.py +311 -0
  74. package/template/scripts/telemetry/report.py +112 -0
  75. package/template/templates/adr.md +38 -0
  76. package/template/templates/adversarial-review.md +54 -0
  77. package/template/templates/change-spec.md +80 -0
  78. package/template/templates/ci-cd.md +27 -0
  79. package/template/templates/data-architecture.md +35 -0
  80. package/template/templates/data-review.md +54 -0
  81. package/template/templates/figma-handoff.md +38 -0
  82. package/template/templates/glossary.md +20 -0
  83. package/template/templates/hardening-checklist.md +73 -0
  84. package/template/templates/incident-runbook.md +57 -0
  85. package/template/templates/infrastructure.md +190 -0
  86. package/template/templates/module-spec.md +49 -0
  87. package/template/templates/mvp-scope.md +34 -0
  88. package/template/templates/persona.md +38 -0
  89. package/template/templates/plan.md +49 -0
  90. package/template/templates/security-review.md +63 -0
  91. package/template/templates/story.md +37 -0
  92. package/template/templates/tech-debt.md +61 -0
  93. package/template/templates/tech-stack.md +41 -0
  94. package/template/templates/telemetry-sidecar.md +184 -0
  95. package/template/templates/test-plan.md +119 -0
  96. package/template/templates/threat-model.md +54 -0
  97. package/template/templates/ui-brief.md +49 -0
  98. package/template/templates/verification.md +63 -0
  99. package/template/templates/vision.md +34 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ All notable changes to hstack are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [SemVer](https://semver.org/).
4
+
5
+ ## [Unreleased] — 0.1.0
6
+
7
+ ### Added
8
+ - **CLI installer.** Three commands shipped on the `hstack` npm package:
9
+ - `hstack init` — copies `template/` into `<consumer>/hstack/`, wires `.claude/agents` (dir-level symlink) and `.claude/skills/hstack-*` (per-skill symlinks), appends the kernel-import line to `<consumer>/CLAUDE.md`, adds `**/.telemetry/` to `<consumer>/.gitignore`, stamps `<consumer>/hstack/VERSION`. Flags: `--yes`, `--force`, `--dry-run`.
10
+ - `hstack update` — diffs `template/` vs `<consumer>/hstack/` at file granularity, surfaces an add/overwrite/remove/symlink-delta plan, prompts for confirmation, then executes. Preserves user content (`context/`, `specs/`, `adr/`, `tech-debt/`, `research/`, `config.yaml`, `telemetry/reports/`). Flags: `--yes`, `--force`, `--dry-run`, `--verbose`.
11
+ - `hstack doctor` — read-only health check. Reports version drift, framework file drift, missing or orphan symlinks, missing wiring lines. Exits 1 on findings.
12
+ - `template/` directory holds framework files distributed to consumers (`CLAUDE.md`, `templates/`, `.claude/agents/`, `.claude/skills/`, `scripts/telemetry/`).
13
+ - `src/manifest.ts` is the canonical framework-vs-user-content boundary.
14
+ - `VERSION` and `CHANGELOG.md` at repo root.
15
+ - macOS and Linux supported; Windows is hard-failed at `hstack init` until v2.
16
+
17
+ ### Changed
18
+ - Framework files relocated from repo root into `template/`. Consumer-facing layout is unchanged — consumers still see `hstack/CLAUDE.md`, `hstack/templates/`, etc. after install.
19
+ - README installation section: `npx hstack init` is now the documented path; manual `cp -r` is the legacy fallback.
20
+
21
+ ### Known limitations (v0.1)
22
+ - No local-edit detection: `hstack update` overwrites consumer hand-edits without warning; the diff preview is the only signal. Hash-manifest mode is planned for v0.2.
23
+ - No CI for the CLI itself; coverage is manual smoke tests across happy / negative paths plus one real consumer (moso-app).
24
+ - No migration scripts: template schema changes between versions need CHANGELOG-driven manual action.
25
+
26
+ ## [0.1.0] - 2026-05-22
27
+
28
+ Initial pre-release. Vendored / symlinked distribution only; npm CLI in progress.
29
+
30
+ - 16 Skills, 10 subagents, 25 templates, kernel.
31
+ - See repo history prior to this changelog for detail.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hugo Ganet
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # hstack
2
+
3
+ A spec-driven engineering workflow that ships as Claude Code Skills and subagents. Configurable per repo. Designed to take a brownfield AI-native SaaS codebase from prototype toward production-grade without adopting a heavyweight methodology framework.
4
+
5
+ hstack sits between an engineer's intent and a merged commit. Scoping, gating, artifact production, multi-tenant safety, audit, reviewability — all flow through it.
6
+
7
+ ## What hstack is
8
+
9
+ A thin, opinionated layer on top of Claude Code that governs how engineers and AI agents collaborate on a codebase. Sixteen Skills, ten subagents, a small set of canonical templates, and one kernel (`CLAUDE.md`) that wins every conflict. AI writes; humans confirm. Artifacts on disk are the state machine — no parallel tracker, no separate dashboard.
10
+
11
+ ## What hstack is not
12
+
13
+ - Not a methodology framework like BMAD or Spec Kit. Patterns were borrowed; the framework was not adopted.
14
+ - Not a project tracker. Frontmatter on artifacts is the tracker.
15
+ - Not a deployment system. Deploys happen outside hstack.
16
+ - Not a SOC 2 / GDPR compliance substrate by itself. v1 is good engineering hygiene; the v2 roadmap names the substrate work required before hstack-governed code can defensibly carry a production-grade label.
17
+
18
+ ## Prerequisites
19
+
20
+ - **Claude Code** installed and authenticated. Pin a minimum version in `hstack/config.yaml` once init runs.
21
+ - **Optional MCPs** the workflow recognizes when present and degrades cleanly when absent: Notion (story / personas / decisions store), Linear or GitHub (alternative story stores), Figma (frame reading for UI work), Supabase (live schema introspection for data review).
22
+ - Nothing else is strictly required. hstack runs against any codebase; the consuming repo's stack details land in `hstack/context/tech-stack.md` during init.
23
+
24
+ ## Installation
25
+
26
+ hstack installs into the consuming repo at the path `hstack/` relative to the repo root via an npm-distributed CLI.
27
+
28
+ ```
29
+ # from the consuming repo root (must be a git repo with a clean working tree)
30
+ npx hstack@latest init
31
+ ```
32
+
33
+ `hstack init` copies the framework files under `template/` into `<consumer>/hstack/`, wires `.claude/agents` (dir-level symlink) and `.claude/skills/hstack-*` (per-skill symlinks), appends the kernel-import line to `<consumer>/CLAUDE.md`, and adds `**/.telemetry/` to `<consumer>/.gitignore`. Use `--dry-run` to preview the plan, `--yes` to skip the confirmation prompt, `--force` to override the dirty-working-tree check.
34
+
35
+ The CLI ships three commands:
36
+
37
+ | Command | What it does |
38
+ | --- | --- |
39
+ | `npx hstack init` | First-time install. Halts if `<consumer>/hstack/` already exists. |
40
+ | `npx hstack update` | Sync framework files to the package version. Preserves user content (`context/`, `specs/`, `adr/`, `tech-debt/`, `research/`, `config.yaml`, `telemetry/reports/`). Surfaces a diff plan before writing. |
41
+ | `npx hstack doctor` | Read-only health check. Reports version drift, framework file drift, missing or orphan symlinks, missing wiring lines. Exits 1 on any finding. |
42
+
43
+ The framework-vs-user-content boundary is canonical in `src/manifest.ts`. **What `init` and `update` write**: `hstack/CLAUDE.md`, `hstack/templates/`, `hstack/.claude/agents/`, `hstack/.claude/skills/`, `hstack/scripts/telemetry/`, `hstack/VERSION`. **What they never touch**: anything under the user-content paths above.
44
+
45
+ ### Manual install (legacy)
46
+
47
+ If you prefer to vendor without the CLI — e.g., to pin to a specific git ref or develop against a fork — copy `template/` into the consuming repo and wire `.claude/` symlinks by hand:
48
+
49
+ ```
50
+ # from the consuming repo root
51
+ cp -r /path/to/hstack/template ./hstack
52
+ ln -s ../hstack/.claude/agents .claude/agents
53
+ mkdir -p .claude/skills
54
+ for d in hstack/.claude/skills/hstack-*/; do
55
+ name=$(basename "$d")
56
+ ln -s "../../hstack/.claude/skills/$name" ".claude/skills/$name"
57
+ done
58
+ echo '> **Engineering workflow:** all changes in this repo are governed by hstack. See @hstack/CLAUDE.md.' >> CLAUDE.md
59
+ echo '**/.telemetry/' >> .gitignore
60
+ git add hstack .claude CLAUDE.md .gitignore && git commit -m "vendor hstack"
61
+ ```
62
+
63
+ `hstack doctor` works against manually-vendored installs too. It will flag the missing `hstack/VERSION` marker as a warning until you run `hstack update --force` to stamp it.
64
+
65
+ Why agents is dir-level but skills is per-skill: consuming repos may want non-hstack skills (e.g., `lyra`, `notion-write`) alongside hstack ones. A dir-level symlink for `.claude/skills/` would evict them. Agents has no such case in practice, so dir-level is cleaner there.
66
+
67
+ ### Maintenance — keeping a consumer in sync
68
+
69
+ Run `npx hstack@latest update` whenever you want to pull the latest framework version. It diffs `template/` against the consumer's `hstack/`, prints a plan (added / modified / removed files plus symlink delta), prompts for confirmation, then executes. The agents dir-level symlink picks up new agents automatically; per-skill symlinks for `.claude/skills/hstack-*` are added or removed by `update` to match the framework state.
70
+
71
+ Run `npx hstack doctor` to audit health without making changes — useful for CI checks, audits before opening a PR against the consumer repo, or onboarding a new contributor.
72
+
73
+ #### Telemetry
74
+
75
+ `hstack/scripts/telemetry/` ships with the framework and is installed by `hstack init` automatically. The `/hstack:telemetry` Skill shells out to `python3 hstack/scripts/telemetry/report.py --window 30`, generating a markdown report at `hstack/telemetry/reports/<YYYY-MM-DD>.md`. The reports directory is git-tracked; per-change `.telemetry/` sidecar dirs are git-ignored (`hstack init` adds the `**/.telemetry/` line for you).
76
+
77
+ Five Skills (`hstack-test-plan`, `hstack-implement`, `hstack-verify`, `hstack-adversarial-review`, `hstack-finalize`) emit small JSON sidecars at their existing terminal commits — schema in `hstack/templates/telemetry-sidecar.md`. The sidecars are derivative — re-runnable from git + frontmatter + transcripts — and exist only to make per-change attribution cheap. Deleting them is harmless.
78
+
79
+ #### Platform support
80
+
81
+ macOS and Linux only in v0.1. Windows is hard-failed at `hstack init` — the dir-level + per-skill symlink wiring needs admin or developer-mode on Windows, and copy-mode fallback is a v2 consideration.
82
+
83
+ ## First run
84
+
85
+ Open a fresh Claude Code session in the consuming repo and run:
86
+
87
+ ```
88
+ /hstack:init
89
+ ```
90
+
91
+ Init is conversational and split into five-to-seven mini-sessions of ten-to-fifteen minutes each — one per product-context document. Each mini-session ends at a commit point so an interruption costs at most one in-flight field. Total elapsed time is 60–90 minutes for a fresh repo. No other Skill runs until init completes.
92
+
93
+ Init produces `hstack/config.yaml` and every required document under `hstack/context/`: vision, glossary, mvp-scope, personas, data-architecture, tech-stack, ci-cd, threat-model, hardening-checklist, incident-runbook. The product-manager subagent drives the interview. If the consuming repo has existing source documents (Notion pages, repo markdown, Google Docs), point the agent at them and it will map content into the canonical templates before walking field-by-field confirmation.
94
+
95
+ After init, run `/hstack:module-spec <area>` once per critical module to reverse-engineer baseline module-specs.
96
+
97
+ ## Per-change workflow
98
+
99
+ Each change moves through up to eleven phases, each backed by one Skill. Conditional phases run only when the change's declared `surfaces` include the relevant tag (`ui`, `db`, `agent`, `auth`, `api`, `infra`).
100
+
101
+ | Phase | Skill | Required when |
102
+ | --- | --- | --- |
103
+ | Story | `/hstack:story-draft` | user-facing change |
104
+ | Scaffold | `/hstack:change-new <area> <slug>` | always |
105
+ | Spec | invoke `spec-author` directly | always |
106
+ | UI brief | `/hstack:ui-brief` | `surfaces` includes `ui` |
107
+ | Figma handoff | cofounder produces, commits `figma-handoff.md` | `surfaces` includes `ui` |
108
+ | Plan | `/hstack:change-plan` | always |
109
+ | Security review | `/hstack:security-review` | always |
110
+ | Data review | `/hstack:data-review` | `surfaces` includes `db` |
111
+ | Implement | `/hstack:implement <change-id> <task-id>` | once per phase |
112
+ | Verify | `/hstack:verify` | always |
113
+ | Adversarial review | `/hstack:adversarial-review` | always — **fresh Claude Code session required** |
114
+ | Ship | `/hstack:ship` | always — read-only scorecard + PR description |
115
+
116
+ Cross-cutting Skills are available throughout: `/hstack:adr-new`, `/hstack:tech-debt-new`, `/hstack:research`. The research Skill supports `--promote <session-id>` to elevate a research session into an ADR, a tech-debt item, or a durable note.
117
+
118
+ The `implementer` is the only subagent that writes code. It refuses every read and write outside `change-spec.in-scope`. Scope-amendments halt and route through `spec-author`; the implementer never extends scope unilaterally.
119
+
120
+ ## Repository layout
121
+
122
+ After init the consuming repo has:
123
+
124
+ ```
125
+ hstack/
126
+ config.yaml # repo-level configuration
127
+ CLAUDE.md # the kernel (authority)
128
+ README.md # this file
129
+ context/ # slow-changing product context
130
+ specs/
131
+ <module>/spec.md # module baseline
132
+ changes/<id>/ # per-change artifacts
133
+ adr/ # Architecture Decision Records
134
+ tech-debt/ # known compromises
135
+ research/
136
+ sessions/ # transient
137
+ promoted/ # durable
138
+ templates/ # canonical templates
139
+ lints/ # pattern-based lint rules
140
+ scripts/ # validators, gate runners
141
+ .claude/
142
+ skills/hstack-*/SKILL.md # 16 Skills
143
+ agents/ # 10 subagent personas
144
+ ```
145
+
146
+ ## Honesty clause: v1 vs v2
147
+
148
+ hstack v1 ships good engineering hygiene: spec discipline, scope-locked implementation, conversational interviews with confirmation gates, append-only ADRs and tech-debt, frontmatter-driven status. It does not by itself deliver SOC 2 / GDPR posture.
149
+
150
+ Three Skills in particular carry v1 / v2 markers in their output:
151
+
152
+ - **security-review.md** — v1 is LLM-scored structured judgment against the hardening checklist; v2 substrate replaces this with executable probes (prompt-injection corpora, RLS bypass attempts, tenant_id fuzzing, secret-redaction tests).
153
+ - **data-review.md** — v1 permits graceful degradation when the Supabase MCP is unreachable for low-stakes changes; v2 hard-fails uniformly.
154
+ - **adversarial-review.md** — v1 fresh-session separation is honor-system, attested in frontmatter; v2 verifies via Claude Code session-id comparison at the CI gate.
155
+
156
+ The Skills frame their output to reflect this. v1 rationales never claim "verified by test." When the honest answer is "structured judgment based on the diff," the artifact says so.
157
+
158
+ The full v2 roadmap lives in the architecture document.
159
+
160
+ ## Reference
161
+
162
+ - [`CLAUDE.md`](./CLAUDE.md) — the kernel. Authority over every Skill, subagent, and template.
163
+ - [Architecture document](https://www.notion.so/360d6791656c813d955af822cb8814d1) — long-form companion to the kernel.
164
+ - [Template schemas and frontmatter contracts](https://www.notion.so/361d6791656c8178bbbbc812fa6426e0) — per-template fields, sections, lifecycle, validation rules.
165
+ - [Adversarial review of the architecture](https://www.notion.so/361d6791656c81f78eb3c97ba4aecbb4) — the 21-finding pressure test that shaped the v1 / v2 split.
166
+
167
+ ## Status
168
+
169
+ hstack v0.1.0. Sixteen Skills, ten subagents, twenty-two templates, the kernel. Enforcement scripts (`hstack/scripts/`) and pattern-based lint rules (`hstack/lints/`) are sketched but not yet implemented — the Skills run as conversational interviews without them, and the CI gate runs in advisory mode until the scripts land. First real use against a consuming repo is the next milestone.
package/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
package/dist/cli.js ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { readFileSync } from "node:fs";
4
+ import pc from "picocolors";
5
+ import { runInit } from "./commands/init.js";
6
+ import { runUpdate } from "./commands/update.js";
7
+ import { runDoctor } from "./commands/doctor.js";
8
+ import { packageVersionFile } from "./lib/paths.js";
9
+ function readVersion() {
10
+ try {
11
+ return readFileSync(packageVersionFile(), "utf8").trim();
12
+ }
13
+ catch {
14
+ return "unknown";
15
+ }
16
+ }
17
+ const program = new Command();
18
+ program
19
+ .name("hstack")
20
+ .description("Spec-driven engineering workflow for Claude Code. See https://github.com/hugoganet/hstack")
21
+ .version(readVersion(), "-v, --version", "print hstack version");
22
+ program
23
+ .command("init")
24
+ .description("Install hstack into the current repo")
25
+ .option("-y, --yes", "skip the confirmation prompt")
26
+ .option("--force", "proceed even if the working tree is dirty")
27
+ .option("--dry-run", "print the plan without making changes")
28
+ .action(async (opts) => {
29
+ const code = await runInit(opts);
30
+ process.exit(code);
31
+ });
32
+ program
33
+ .command("update")
34
+ .description("Sync framework files to the latest version, preserving user content")
35
+ .option("-y, --yes", "skip the confirmation prompt")
36
+ .option("--force", "proceed even if the working tree is dirty")
37
+ .option("--dry-run", "print the plan without making changes")
38
+ .option("--verbose", "list every file action in the plan")
39
+ .action(async (opts) => {
40
+ const code = await runUpdate(opts);
41
+ process.exit(code);
42
+ });
43
+ program
44
+ .command("doctor")
45
+ .description("Verify hstack installation health (read-only)")
46
+ .option("--verbose", "list every affected file in the report")
47
+ .action(async (opts) => {
48
+ const code = await runDoctor(opts);
49
+ process.exit(code);
50
+ });
51
+ program.parseAsync(process.argv).catch((err) => {
52
+ console.error(pc.red(err instanceof Error ? err.message : String(err)));
53
+ process.exit(1);
54
+ });
55
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,kBAAkB,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CACV,2FAA2F,CAC5F;KACA,OAAO,CAAC,WAAW,EAAE,EAAE,eAAe,EAAE,sBAAsB,CAAC,CAAC;AAEnE,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,WAAW,EAAE,8BAA8B,CAAC;KACnD,MAAM,CAAC,SAAS,EAAE,2CAA2C,CAAC;KAC9D,MAAM,CAAC,WAAW,EAAE,uCAAuC,CAAC;KAC5D,MAAM,CAAC,KAAK,EAAE,IAA0D,EAAE,EAAE;IAC3E,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,qEAAqE,CAAC;KAClF,MAAM,CAAC,WAAW,EAAE,8BAA8B,CAAC;KACnD,MAAM,CAAC,SAAS,EAAE,2CAA2C,CAAC;KAC9D,MAAM,CAAC,WAAW,EAAE,uCAAuC,CAAC;KAC5D,MAAM,CAAC,WAAW,EAAE,oCAAoC,CAAC;KACzD,MAAM,CAAC,KAAK,EAAE,IAKd,EAAE,EAAE;IACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,+CAA+C,CAAC;KAC5D,MAAM,CAAC,WAAW,EAAE,wCAAwC,CAAC;KAC7D,MAAM,CAAC,KAAK,EAAE,IAA2B,EAAE,EAAE;IAC5C,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACtD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,155 @@
1
+ import pc from "picocolors";
2
+ import fs from "fs-extra";
3
+ import { readFileSync } from "node:fs";
4
+ import { resolve, basename } from "node:path";
5
+ import { findGitRoot } from "../lib/git.js";
6
+ import { packageTemplateDir, packageVersionFile } from "../lib/paths.js";
7
+ import { planUpdate, pruneNoopActions } from "../lib/wire.js";
8
+ function readPackageVersion() {
9
+ return readFileSync(packageVersionFile(), "utf8").trim();
10
+ }
11
+ export async function runDoctor(opts) {
12
+ const cwd = process.cwd();
13
+ const gitRoot = await findGitRoot(cwd);
14
+ if (!gitRoot) {
15
+ console.error(pc.red("Not inside a git repository. hstack doctor must run from a git repo."));
16
+ return 2;
17
+ }
18
+ const consumerHstack = resolve(gitRoot, "hstack");
19
+ if (!(await fs.pathExists(consumerHstack))) {
20
+ console.log(pc.yellow("hstack is not installed in this repo.") +
21
+ " Run " +
22
+ pc.cyan("npx hstack init") +
23
+ " to install.");
24
+ return 1;
25
+ }
26
+ const templateDir = packageTemplateDir();
27
+ const packageVersion = readPackageVersion();
28
+ // Detect installed version
29
+ const installedVersionFile = resolve(consumerHstack, "VERSION");
30
+ const installedVersion = (await fs.pathExists(installedVersionFile))
31
+ ? (await fs.readFile(installedVersionFile, "utf8")).trim()
32
+ : null;
33
+ // Reuse planUpdate + pruneNoopActions to discover drift
34
+ const rawActions = await planUpdate(gitRoot, templateDir, packageVersion);
35
+ const actions = await pruneNoopActions(rawActions, packageVersion);
36
+ // Classify actions into findings
37
+ const findings = [];
38
+ // Version
39
+ if (installedVersion === null) {
40
+ findings.push({
41
+ level: "warn",
42
+ category: "version",
43
+ message: `hstack/VERSION marker is missing (installed-version unknown; package is v${packageVersion})`,
44
+ });
45
+ }
46
+ else if (installedVersion !== packageVersion) {
47
+ findings.push({
48
+ level: "warn",
49
+ category: "version",
50
+ message: `installed v${installedVersion}, package v${packageVersion} — run \`npx hstack update\``,
51
+ });
52
+ }
53
+ const overwrites = actions.filter((a) => a.kind === "overwrite-file");
54
+ if (overwrites.length > 0) {
55
+ findings.push({
56
+ level: "warn",
57
+ category: "framework-drift",
58
+ message: `${overwrites.length} framework file(s) differ from template`,
59
+ detail: opts.verbose
60
+ ? overwrites.map((a) => ` ${a.relpath}`).join("\n")
61
+ : undefined,
62
+ });
63
+ }
64
+ const adds = actions.filter((a) => a.kind === "add-file");
65
+ if (adds.length > 0) {
66
+ findings.push({
67
+ level: "warn",
68
+ category: "framework-missing",
69
+ message: `${adds.length} framework file(s) missing from hstack/`,
70
+ detail: opts.verbose
71
+ ? adds.map((a) => ` ${a.relpath}`).join("\n")
72
+ : undefined,
73
+ });
74
+ }
75
+ const stragglers = actions.filter((a) => a.kind === "remove-file");
76
+ if (stragglers.length > 0) {
77
+ findings.push({
78
+ level: "warn",
79
+ category: "framework-stale",
80
+ message: `${stragglers.length} file(s) under hstack/ are not part of the framework`,
81
+ detail: opts.verbose
82
+ ? stragglers.map((a) => ` ${a.relpath}`).join("\n")
83
+ : undefined,
84
+ });
85
+ }
86
+ const newLinks = actions.filter((a) => a.kind === "symlink");
87
+ if (newLinks.length > 0) {
88
+ findings.push({
89
+ level: "error",
90
+ category: "symlinks-missing",
91
+ message: `${newLinks.length} skill/agents symlink(s) missing or pointing at wrong target`,
92
+ detail: opts.verbose
93
+ ? newLinks
94
+ .map((a) => ` ${basename(a.to)}`)
95
+ .join("\n")
96
+ : undefined,
97
+ });
98
+ }
99
+ const orphanLinks = actions.filter((a) => a.kind === "remove-symlink");
100
+ if (orphanLinks.length > 0) {
101
+ findings.push({
102
+ level: "warn",
103
+ category: "symlinks-orphan",
104
+ message: `${orphanLinks.length} symlink(s) point at skills not present in the framework`,
105
+ detail: opts.verbose
106
+ ? orphanLinks
107
+ .map((a) => ` ${basename(a.to)}`)
108
+ .join("\n")
109
+ : undefined,
110
+ });
111
+ }
112
+ const missingLines = actions.filter((a) => a.kind === "append-line");
113
+ for (const a of missingLines) {
114
+ const m = a;
115
+ const file = basename(m.file);
116
+ findings.push({
117
+ level: "error",
118
+ category: "wiring",
119
+ message: `${file} is missing the required hstack line`,
120
+ });
121
+ }
122
+ // Render
123
+ console.log(pc.bold(`hstack doctor — ${gitRoot}`));
124
+ console.log("");
125
+ console.log(` package: v${packageVersion}`);
126
+ console.log(` installed: v${installedVersion ?? pc.dim("unknown")}`);
127
+ console.log("");
128
+ if (findings.length === 0) {
129
+ console.log(pc.green("✓ All checks passed."));
130
+ return 0;
131
+ }
132
+ console.log(pc.bold(`${findings.length} finding(s):`));
133
+ for (const f of findings) {
134
+ const tag = f.level === "error" ? pc.red("✗") : pc.yellow("!");
135
+ console.log(` ${tag} [${f.category}] ${f.message}`);
136
+ if (f.detail)
137
+ console.log(pc.dim(f.detail));
138
+ }
139
+ console.log("");
140
+ const hasErrors = findings.some((f) => f.level === "error");
141
+ if (hasErrors) {
142
+ console.log(pc.dim("Run " +
143
+ pc.cyan("npx hstack update") +
144
+ " to repair wiring and sync framework files."));
145
+ }
146
+ else {
147
+ console.log(pc.dim("Run " +
148
+ pc.cyan("npx hstack update") +
149
+ " to sync. Re-run " +
150
+ pc.cyan("hstack doctor --verbose") +
151
+ " for the detailed file list."));
152
+ }
153
+ return 1;
154
+ }
155
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import pc from "picocolors";
2
+ import prompts from "prompts";
3
+ import { readFileSync } from "node:fs";
4
+ import { findGitRoot, isWorkingTreeClean } from "../lib/git.js";
5
+ import { packageTemplateDir, packageVersionFile } from "../lib/paths.js";
6
+ import { planInit, renderPlan, validatePlan, executePlan, } from "../lib/wire.js";
7
+ function readPackageVersion() {
8
+ return readFileSync(packageVersionFile(), "utf8").trim();
9
+ }
10
+ export async function runInit(opts) {
11
+ if (process.platform === "win32") {
12
+ console.error(pc.red("hstack init does not yet support Windows (symlinks need admin / developer mode). Tracked for v2."));
13
+ return 2;
14
+ }
15
+ // 1. Precondition: cwd is inside a git repo
16
+ const cwd = process.cwd();
17
+ const gitRoot = await findGitRoot(cwd);
18
+ if (!gitRoot) {
19
+ console.error(pc.red(`Not inside a git repository. hstack init must run from the root of a git repo.`));
20
+ return 2;
21
+ }
22
+ if (gitRoot !== cwd) {
23
+ console.error(pc.yellow(`Warning: running from ${cwd} but git root is ${gitRoot}. hstack will install at ${gitRoot}/hstack.`));
24
+ }
25
+ // 2. Precondition: working tree is clean
26
+ if (!opts.force) {
27
+ const clean = await isWorkingTreeClean(gitRoot);
28
+ if (!clean) {
29
+ console.error(pc.red(`Working tree is not clean. Commit or stash your changes, or re-run with --force.`));
30
+ return 2;
31
+ }
32
+ }
33
+ // 3. Compute plan
34
+ const templateDir = packageTemplateDir();
35
+ const version = readPackageVersion();
36
+ const actions = await planInit(gitRoot, templateDir, version);
37
+ // 4. Validate
38
+ const blockers = await validatePlan(actions);
39
+ if (blockers.length > 0) {
40
+ console.error(pc.red("hstack init cannot proceed:"));
41
+ for (const b of blockers)
42
+ console.error(pc.red(` - ${b}`));
43
+ return 2;
44
+ }
45
+ // 5. Show plan
46
+ console.log(pc.bold("hstack init will:"));
47
+ console.log(renderPlan(actions, gitRoot));
48
+ console.log("");
49
+ if (opts.dryRun) {
50
+ console.log(pc.dim("Dry run — no changes made."));
51
+ return 0;
52
+ }
53
+ // 6. Confirm
54
+ if (!opts.yes) {
55
+ const { ok } = await prompts({
56
+ type: "confirm",
57
+ name: "ok",
58
+ message: "Proceed?",
59
+ initial: true,
60
+ });
61
+ if (!ok) {
62
+ console.log(pc.dim("Cancelled."));
63
+ return 2;
64
+ }
65
+ }
66
+ // 7. Execute
67
+ try {
68
+ await executePlan(actions);
69
+ }
70
+ catch (err) {
71
+ console.error(pc.red(`init failed: ${err instanceof Error ? err.message : String(err)}`));
72
+ console.error(pc.dim("Partial state may exist. Inspect with `git status`; revert with `git restore` and `rm -rf hstack/`."));
73
+ return 1;
74
+ }
75
+ // 8. Next steps
76
+ console.log("");
77
+ console.log(pc.green("hstack installed."));
78
+ console.log("");
79
+ console.log("Next steps:");
80
+ console.log(" 1. Review the changes: " + pc.cyan("git status"));
81
+ console.log(" 2. Commit: " + pc.cyan("git add . && git commit -m 'chore: install hstack'"));
82
+ console.log(" 3. Open Claude Code in this repo and run " +
83
+ pc.cyan("/hstack:init") +
84
+ " to populate hstack/context/.");
85
+ return 0;
86
+ }
87
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}