cleargate 0.8.2 → 0.10.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/CHANGELOG.md +190 -0
- package/README.md +11 -0
- package/dist/MANIFEST.json +259 -28
- package/dist/{chunk-OM4FAEA7.js → chunk-Q3BTSXCK.js} +69 -3
- package/dist/chunk-Q3BTSXCK.js.map +1 -0
- package/dist/cli.cjs +2621 -548
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2548 -560
- package/dist/cli.js.map +1 -1
- package/dist/lib/ledger.cjs +120 -0
- package/dist/lib/ledger.cjs.map +1 -0
- package/dist/lib/ledger.d.cts +64 -0
- package/dist/lib/ledger.d.ts +64 -0
- package/dist/lib/ledger.js +96 -0
- package/dist/lib/ledger.js.map +1 -0
- package/dist/templates/cleargate-planning/.claude/agents/architect.md +10 -8
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-contradict.md +108 -0
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +49 -3
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +6 -1
- package/dist/templates/cleargate-planning/.claude/agents/developer.md +29 -2
- package/dist/templates/cleargate-planning/.claude/agents/qa.md +50 -1
- package/dist/templates/cleargate-planning/.claude/agents/reporter.md +31 -9
- package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-task.sh +148 -0
- package/dist/templates/cleargate-planning/.claude/hooks/session-start.sh +6 -0
- package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +314 -96
- package/dist/templates/cleargate-planning/.claude/settings.json +4 -0
- package/dist/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +473 -0
- package/dist/templates/cleargate-planning/.cleargate/config.example.yml +19 -0
- package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-enforcement.md +542 -0
- package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +102 -428
- package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +31 -0
- package/dist/templates/cleargate-planning/.cleargate/knowledge/sprint-closeout-checklist.md +71 -0
- package/dist/templates/cleargate-planning/.cleargate/scripts/assert_story_files.mjs +24 -2
- package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +387 -27
- package/dist/templates/cleargate-planning/.cleargate/scripts/dedupe_frontmatter.mjs +219 -0
- package/dist/templates/cleargate-planning/.cleargate/scripts/lib/report-filename.mjs +54 -0
- package/dist/templates/cleargate-planning/.cleargate/scripts/prep_doc_refresh.mjs +378 -0
- package/dist/templates/cleargate-planning/.cleargate/scripts/prep_qa_context.mjs +888 -0
- package/dist/templates/cleargate-planning/.cleargate/scripts/sprint_trends.mjs +71 -0
- package/dist/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +355 -13
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +20 -20
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_prep_qa_context.sh +482 -0
- package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +125 -0
- package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +24 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +32 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +48 -14
- package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +37 -3
- package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +50 -0
- package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +98 -29
- package/dist/templates/cleargate-planning/.cleargate/templates/proposal.md +17 -4
- package/dist/templates/cleargate-planning/.cleargate/templates/sprint_report.md +23 -4
- package/dist/templates/cleargate-planning/.cleargate/templates/story.md +55 -3
- package/dist/templates/cleargate-planning/CLAUDE.md +28 -10
- package/dist/templates/cleargate-planning/MANIFEST.json +259 -28
- package/dist/{whoami-CX7CXJD5.js → whoami-W4U6DPVG.js} +17 -17
- package/dist/whoami-W4U6DPVG.js.map +1 -0
- package/package.json +13 -2
- package/templates/cleargate-planning/.claude/agents/architect.md +10 -8
- package/templates/cleargate-planning/.claude/agents/cleargate-wiki-contradict.md +108 -0
- package/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +49 -3
- package/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +6 -1
- package/templates/cleargate-planning/.claude/agents/developer.md +29 -2
- package/templates/cleargate-planning/.claude/agents/qa.md +50 -1
- package/templates/cleargate-planning/.claude/agents/reporter.md +31 -9
- package/templates/cleargate-planning/.claude/hooks/pre-tool-use-task.sh +148 -0
- package/templates/cleargate-planning/.claude/hooks/session-start.sh +6 -0
- package/templates/cleargate-planning/.claude/hooks/token-ledger.sh +314 -96
- package/templates/cleargate-planning/.claude/settings.json +4 -0
- package/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +473 -0
- package/templates/cleargate-planning/.cleargate/config.example.yml +19 -0
- package/templates/cleargate-planning/.cleargate/knowledge/cleargate-enforcement.md +542 -0
- package/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +102 -428
- package/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +31 -0
- package/templates/cleargate-planning/.cleargate/knowledge/sprint-closeout-checklist.md +71 -0
- package/templates/cleargate-planning/.cleargate/scripts/assert_story_files.mjs +24 -2
- package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +387 -27
- package/templates/cleargate-planning/.cleargate/scripts/dedupe_frontmatter.mjs +219 -0
- package/templates/cleargate-planning/.cleargate/scripts/lib/report-filename.mjs +54 -0
- package/templates/cleargate-planning/.cleargate/scripts/prep_doc_refresh.mjs +378 -0
- package/templates/cleargate-planning/.cleargate/scripts/prep_qa_context.mjs +888 -0
- package/templates/cleargate-planning/.cleargate/scripts/sprint_trends.mjs +71 -0
- package/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +355 -13
- package/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +20 -20
- package/templates/cleargate-planning/.cleargate/scripts/test/test_prep_qa_context.sh +482 -0
- package/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +125 -0
- package/templates/cleargate-planning/.cleargate/templates/Bug.md +24 -1
- package/templates/cleargate-planning/.cleargate/templates/CR.md +32 -1
- package/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +48 -14
- package/templates/cleargate-planning/.cleargate/templates/epic.md +37 -3
- package/templates/cleargate-planning/.cleargate/templates/hotfix.md +50 -0
- package/templates/cleargate-planning/.cleargate/templates/initiative.md +98 -29
- package/templates/cleargate-planning/.cleargate/templates/sprint_report.md +23 -4
- package/templates/cleargate-planning/.cleargate/templates/story.md +55 -3
- package/templates/cleargate-planning/CLAUDE.md +28 -10
- package/templates/cleargate-planning/MANIFEST.json +259 -28
- package/dist/chunk-OM4FAEA7.js.map +0 -1
- package/dist/whoami-CX7CXJD5.js.map +0 -1
- package/templates/cleargate-planning/.cleargate/templates/proposal.md +0 -61
|
@@ -7,32 +7,45 @@ This file is the content `cleargate init` injects into a downstream user's `CLAU
|
|
|
7
7
|
<!-- CLEARGATE:START -->
|
|
8
8
|
## 🔄 ClearGate Planning Framework
|
|
9
9
|
|
|
10
|
-
This repository uses **ClearGate** — a standalone planning framework for AI coding agents. ClearGate scaffolds *how work is planned* (
|
|
10
|
+
This repository uses **ClearGate** — a standalone planning framework for AI coding agents. ClearGate scaffolds *how work is planned* (initiatives → epics → stories → sprints) and defines a four-agent loop for execution. ClearGate does not run builds, tests, or deployments; execution tooling remains the target repo's own.
|
|
11
11
|
|
|
12
12
|
**Session-start orientation (read in this order):**
|
|
13
13
|
1. `.cleargate/wiki/index.md` — compiled awareness layer (~3k tokens). Lists active sprint, in-flight items, recent shipments, open gates, planned work, and topic synthesis pages. **Read this first** to know what exists before grepping raw files. If absent, run `cleargate wiki build`.
|
|
14
14
|
2. `.cleargate/knowledge/cleargate-protocol.md` — delivery protocol (non-negotiable rules).
|
|
15
15
|
3. `.cleargate/FLASHCARD.md` — lessons tagged by topic (`#schema`, `#auth`, etc.). Grep for your area before starting.
|
|
16
|
+
4. `.cleargate/knowledge/cleargate-enforcement.md` — hook-enforced rules (worktree mechanics, file-surface contract, lifecycle reconciler, lane rubric, doctor exit codes, etc.). Read only when a CLI hook surfaces an error or when triaging a v2-mode question.
|
|
16
17
|
|
|
17
18
|
**Triage first, draft second.** Every user request gets classified (Epic / Story / CR / Bug / Pull / Push) *before* any drafting. If the type is ambiguous, ask ONE targeted question — do not guess.
|
|
18
19
|
|
|
19
|
-
**
|
|
20
|
+
**Sprint execution.** When a sprint is active, the orchestration playbook lives at `.claude/skills/sprint-execution/SKILL.md` — load it before dispatching any execution agent (Architect / Developer / QA / Reporter). The skill is the canonical four-agent-loop spec; the always-on CLAUDE.md keeps only the halt-rules and the load-skill contract.
|
|
20
21
|
|
|
21
|
-
**
|
|
22
|
+
**Skill auto-load directive.** When the SessionStart banner emits `Load skill: <name>`, invoke the Skill tool to load it before continuing. Claude Code's description-match auto-load is advisory; this rule is the contract.
|
|
23
|
+
|
|
24
|
+
**Codebase is source of truth.** Wiki, memory, and `context_source` are derived caches. On conflict between cache and code, the code wins; the cache rebuilds. Before stating that a capability exists or doesn't exist, grep the code.
|
|
25
|
+
|
|
26
|
+
**Duplicate check before drafting.** Before drafting an Initiative or work item, grep `.cleargate/delivery/archive/` + `.cleargate/FLASHCARD.md` for similar past work. If you find overlap, surface it as a one-liner (*"This is very close to STORY-003-05 shipped in SPRINT-01 — are you extending it or redoing it?"*) instead of drafting a duplicate. If the request names an integration, feature, or capability, also grep the source tree for existing implementations and cite findings in `## Existing Surfaces`.
|
|
27
|
+
|
|
28
|
+
**Halt at gates.** You halt at Gate 1 (Initiative approval) and Gate 2 (Ambiguity resolution) and wait for explicit human sign-off. You never call `cleargate_push_item` without `approved: true` (hard reject) and explicit human confirmation. Readiness gates (`cached_gate_result.pass`) are advisory by default — the push proceeds and the item body receives an `[advisory: gate_failed — <criteria>]` prefix; opt into hard-reject via `STRICT_PUSH_GATES=true` on the MCP server.
|
|
29
|
+
|
|
30
|
+
**Sprint mode.** Read `execution_mode:` in the active sprint's frontmatter before spawning Developer/QA. `v1` = advisory; `v2` = enforce the rules in `cleargate-enforcement.md`. Default `v1`.
|
|
31
|
+
|
|
32
|
+
**Brief is the universal pre-push handshake.** Every work-item template's `<instructions>` block tells you to render a Brief in chat after Writing the document — Summary / Open Questions / Edge Cases / Risks / Ambiguity. Halt for human review. When ambiguity reaches 🟢, push via `cleargate_push_item` automatically — the same approval covers Gate 1 and the push.
|
|
33
|
+
|
|
34
|
+
**Boundary gates (CR-017).** `cleargate sprint init` runs the decomposition gate; `close_sprint.mjs` runs the lifecycle reconciler. Both block in v2.
|
|
35
|
+
|
|
36
|
+
**Sprint close is Gate-4-class (CR-019).** Run `close_sprint.mjs` with no flags first; surface the prompt verbatim; halt. Never pass `--assume-ack` autonomously. Pre-close enforces Steps 2.7 (no leftover worktrees) + 2.8 (sprint branch merged to main) under v2; failure halts close. Post-close prints a 6-item handoff list (Step 8) summarizing commits, merge state, wiki ingest, flashcards, artifacts, and next-sprint preflight.
|
|
22
37
|
|
|
23
38
|
**Drafting work items:**
|
|
24
|
-
- Use the templates in `.cleargate/templates/` (`
|
|
39
|
+
- Use the templates in `.cleargate/templates/` (`epic.md`, `story.md`, `CR.md`, `Bug.md`, `Sprint Plan Template.md`, `initiative.md`).
|
|
25
40
|
- Save drafts to `.cleargate/delivery/pending-sync/{TYPE}-{ID}-{Name}.md`.
|
|
26
41
|
- After `cleargate_push_item` returns a Remote ID, update the frontmatter AND move the file to `.cleargate/delivery/archive/` — these two happen atomically, never one without the other.
|
|
27
42
|
- **Story granularity.** When decomposing an epic into stories, run the Granularity Rubric at the top of `story.md`. If a candidate story trips any signal (unrelated goals joined, >5 Gherkin scenarios, subsystems span, L4 complexity), emit two stories with consecutive IDs instead. Splits and merges are free at decomposition time — no remote IDs exist yet.
|
|
28
43
|
|
|
29
|
-
**
|
|
30
|
-
|
|
31
|
-
- `
|
|
32
|
-
- `qa.md` — independent verification gate; re-runs checks; never commits, never edits.
|
|
33
|
-
- `reporter.md` — one sprint retrospective at sprint end; synthesizes token ledger + git log + flashcards into `REPORT.md`.
|
|
44
|
+
**Initiative Intake.** Stakeholder input arrives via two paths: (1) MCP pull — call `cleargate_pull_initiative` with the remote ID; the tool writes `pending-sync/INITIATIVE-NNN_*.md` automatically; read the result and present a Brief. (2) Manual paste — human pastes the text; triage it, write `pending-sync/INITIATIVE-NNN_*.md` using `templates/initiative.md`, present a Brief. In both cases, after Gate 1 the file moves to `archive/` stamped with `triaged_at:` and `spawned_items:`.
|
|
45
|
+
|
|
46
|
+
**State-aware surface.** At session start, `cleargate doctor --session-start` (invoked by the SessionStart hook) emits one banner line before any other output: `ClearGate state: pre-member — local planning enabled, sync requires join.` OR `ClearGate state: member (project: <project_id>) — full surface enabled.` In **pre-member** state (no valid join token on disk), only local-planning commands are reachable: `init`, `join`, `whoami`, `wiki *`, `gate *`, `stamp`, `doctor`, `scaffold-lint`, `sprint *`, `story *`, `state *`, `upgrade`, `uninstall`. Commands `push`, `pull`, `sync`, `sync-log`, `conflicts`, and `admin *` (except `admin login`) require membership and exit 2 with a redirect: `Run: cleargate join <invite-url>`. If the SessionStart banner says `pre-member`, do not suggest push/pull/sync to the user — instead ask for an invite URL and direct them to `cleargate join`.
|
|
34
47
|
|
|
35
|
-
**Conversational style.** Keep replies terse. Details live in the work-item file and `REPORT.md`, not in chat. State results and next steps; skip narration of your own thought process.
|
|
48
|
+
**Conversational style.** Keep replies terse. Details live in the work-item file and `REPORT.md`, not in chat. State results and next steps; skip narration of your own thought process. After Writing or Editing any file under `.cleargate/delivery/**`, briefly note the ingest result if the PostToolUse hook surfaced one — one short sentence (`✅ ingested as <bucket>/<id>.md` / `⚠️ gate failed: <criterion>` / `🔴 ingest error — see .cleargate/hook-log/gate-check.log`). Do not narrate when nothing fired (skip-excluded paths). This is conversational confirmation, not retry logic.
|
|
36
49
|
|
|
37
50
|
**Support infrastructure.** Flashcard protocol: `.claude/skills/flashcard/SKILL.md`. Token-ledger hook: `.claude/hooks/token-ledger.sh`, wired via `.claude/settings.json` (SubagentStop) — auto-logs agent cost per sprint for the Reporter.
|
|
38
51
|
|
|
@@ -41,4 +54,9 @@ This repository uses **ClearGate** — a standalone planning framework for AI co
|
|
|
41
54
|
**Project overrides.** Content OUTSIDE this `<!-- CLEARGATE:START -->...<!-- CLEARGATE:END -->` block takes precedence where it conflicts with ClearGate defaults.
|
|
42
55
|
|
|
43
56
|
**Scope reminder.** ClearGate is a *planning* framework. It scaffolds how work gets planned and how the four-agent loop runs. It does not replace your project's build system, CI, test runner, or deployment tooling.
|
|
57
|
+
|
|
58
|
+
**Guardrails for the conversational agent:**
|
|
59
|
+
- Sprint close requires explicit human ack. Run close_sprint.mjs without flags first; surface the "re-run with --assume-ack" prompt verbatim and halt. Never pass --assume-ack yourself — that flag is reserved for automated tests.
|
|
60
|
+
|
|
61
|
+
**Doc & metadata refresh on close.** During Gate 4 ack, read `.cleargate/sprint-runs/<id>/.doc-refresh-checklist.md` (generated by `prep_doc_refresh.mjs`) and apply or punt each `- [ ]` item per the canonical list at `.cleargate/knowledge/sprint-closeout-checklist.md`. Items already marked `- [x]` indicate "no changes detected, skip."
|
|
44
62
|
<!-- CLEARGATE:END -->
|
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
"cleargate_version": "0.
|
|
3
|
-
"generated_at": "2026-
|
|
2
|
+
"cleargate_version": "0.10.0",
|
|
3
|
+
"generated_at": "2026-05-02T19:21:41.996Z",
|
|
4
4
|
"files": [
|
|
5
5
|
{
|
|
6
6
|
"path": ".claude/agents/architect.md",
|
|
7
|
-
"sha256": "
|
|
7
|
+
"sha256": "5aa58a549f74ecc73be1630428ef1903faae5c3779b7b5371307c5cb63621026",
|
|
8
|
+
"tier": "agent",
|
|
9
|
+
"overwrite_policy": "always",
|
|
10
|
+
"preserve_on_uninstall": false
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"path": ".claude/agents/cleargate-wiki-contradict.md",
|
|
14
|
+
"sha256": "1b7ca28889dfa1ab704e05b90179547bee1ae683b68722c99a1daec990e8572b",
|
|
8
15
|
"tier": "agent",
|
|
9
16
|
"overwrite_policy": "always",
|
|
10
17
|
"preserve_on_uninstall": false
|
|
11
18
|
},
|
|
12
19
|
{
|
|
13
20
|
"path": ".claude/agents/cleargate-wiki-ingest.md",
|
|
14
|
-
"sha256": "
|
|
21
|
+
"sha256": "4b14aed168d30807a1325de8c065bb57e2bc66271a0cffc71a21481c227b453b",
|
|
15
22
|
"tier": "agent",
|
|
16
23
|
"overwrite_policy": "always",
|
|
17
24
|
"preserve_on_uninstall": false
|
|
18
25
|
},
|
|
19
26
|
{
|
|
20
27
|
"path": ".claude/agents/cleargate-wiki-lint.md",
|
|
21
|
-
"sha256": "
|
|
28
|
+
"sha256": "42067fd728e64ac1ff1ace5822b8f8c3ddf1ba70fd0fbddf0e8cb19d5d699e77",
|
|
22
29
|
"tier": "agent",
|
|
23
30
|
"overwrite_policy": "always",
|
|
24
31
|
"preserve_on_uninstall": false
|
|
@@ -32,21 +39,21 @@
|
|
|
32
39
|
},
|
|
33
40
|
{
|
|
34
41
|
"path": ".claude/agents/developer.md",
|
|
35
|
-
"sha256": "
|
|
42
|
+
"sha256": "55790014320187e500f6b904756bbc8bda4806274805e883d62492bf75a34f12",
|
|
36
43
|
"tier": "agent",
|
|
37
44
|
"overwrite_policy": "always",
|
|
38
45
|
"preserve_on_uninstall": false
|
|
39
46
|
},
|
|
40
47
|
{
|
|
41
48
|
"path": ".claude/agents/qa.md",
|
|
42
|
-
"sha256": "
|
|
49
|
+
"sha256": "b6ac9d814e1bbd1fb9a062ce7775e34da1d1e5e6fc35140b977f30b2632654fa",
|
|
43
50
|
"tier": "agent",
|
|
44
51
|
"overwrite_policy": "always",
|
|
45
52
|
"preserve_on_uninstall": false
|
|
46
53
|
},
|
|
47
54
|
{
|
|
48
55
|
"path": ".claude/agents/reporter.md",
|
|
49
|
-
"sha256": "
|
|
56
|
+
"sha256": "d8e11e0a5eeb7bf298df2e79ce0f6b8b4d87e3a2d6666f458ae143ef8e593ea1",
|
|
50
57
|
"tier": "agent",
|
|
51
58
|
"overwrite_policy": "always",
|
|
52
59
|
"preserve_on_uninstall": false
|
|
@@ -86,9 +93,16 @@
|
|
|
86
93
|
"overwrite_policy": "always",
|
|
87
94
|
"preserve_on_uninstall": false
|
|
88
95
|
},
|
|
96
|
+
{
|
|
97
|
+
"path": ".claude/hooks/pre-tool-use-task.sh",
|
|
98
|
+
"sha256": "79fdd30e3f301cb89757aa2279a5fb8cc3a91493b62d5c801517853500368e7f",
|
|
99
|
+
"tier": "hook",
|
|
100
|
+
"overwrite_policy": "always",
|
|
101
|
+
"preserve_on_uninstall": false
|
|
102
|
+
},
|
|
89
103
|
{
|
|
90
104
|
"path": ".claude/hooks/session-start.sh",
|
|
91
|
-
"sha256": "
|
|
105
|
+
"sha256": "b266a5567cc84c02d041e570569962c003daaa69b6aee244173e740dedbf4ee2",
|
|
92
106
|
"tier": "hook",
|
|
93
107
|
"overwrite_policy": "pin-aware",
|
|
94
108
|
"preserve_on_uninstall": false
|
|
@@ -102,14 +116,14 @@
|
|
|
102
116
|
},
|
|
103
117
|
{
|
|
104
118
|
"path": ".claude/hooks/token-ledger.sh",
|
|
105
|
-
"sha256": "
|
|
119
|
+
"sha256": "b766f18e005dea89d63c2dae9c436e3e52ef0e4828ea895ce94abfecc68f0ce2",
|
|
106
120
|
"tier": "hook",
|
|
107
121
|
"overwrite_policy": "always",
|
|
108
122
|
"preserve_on_uninstall": false
|
|
109
123
|
},
|
|
110
124
|
{
|
|
111
125
|
"path": ".claude/settings.json",
|
|
112
|
-
"sha256": "
|
|
126
|
+
"sha256": "8c3c8fe2bd2a2c23e3faa56fad94352c66a11646d12a4ca79ff95d578e589ec0",
|
|
113
127
|
"tier": "cli-config",
|
|
114
128
|
"overwrite_policy": "merge-3way",
|
|
115
129
|
"preserve_on_uninstall": false
|
|
@@ -121,6 +135,13 @@
|
|
|
121
135
|
"overwrite_policy": "always",
|
|
122
136
|
"preserve_on_uninstall": false
|
|
123
137
|
},
|
|
138
|
+
{
|
|
139
|
+
"path": ".claude/skills/sprint-execution/SKILL.md",
|
|
140
|
+
"sha256": "f403bb55f4cdce4b82ce3fdd59b03dd55d8f3f64bdc0e1d1c2abf9b2121efa3d",
|
|
141
|
+
"tier": "skill",
|
|
142
|
+
"overwrite_policy": "always",
|
|
143
|
+
"preserve_on_uninstall": false
|
|
144
|
+
},
|
|
124
145
|
{
|
|
125
146
|
"path": ".cleargate/FLASHCARD.md",
|
|
126
147
|
"sha256": null,
|
|
@@ -128,65 +149,275 @@
|
|
|
128
149
|
"overwrite_policy": "skip",
|
|
129
150
|
"preserve_on_uninstall": true
|
|
130
151
|
},
|
|
152
|
+
{
|
|
153
|
+
"path": ".cleargate/knowledge/cleargate-enforcement.md",
|
|
154
|
+
"sha256": "11ff8004145d627ce3885976304797465e07ea80f2e37001304afa9087852e7f",
|
|
155
|
+
"tier": "protocol",
|
|
156
|
+
"overwrite_policy": "merge-3way",
|
|
157
|
+
"preserve_on_uninstall": false
|
|
158
|
+
},
|
|
131
159
|
{
|
|
132
160
|
"path": ".cleargate/knowledge/cleargate-protocol.md",
|
|
133
|
-
"sha256": "
|
|
161
|
+
"sha256": "50e999717b9c9e1c11638f3f2433f413d177ed8ddf3cffdbb20b50c8807b1fc5",
|
|
134
162
|
"tier": "protocol",
|
|
135
163
|
"overwrite_policy": "merge-3way",
|
|
136
164
|
"preserve_on_uninstall": false
|
|
137
165
|
},
|
|
138
166
|
{
|
|
139
167
|
"path": ".cleargate/knowledge/readiness-gates.md",
|
|
140
|
-
"sha256": "
|
|
168
|
+
"sha256": "6125b57bfdcdd5d4fabe886770d9b062d76df9a232f4997dbedf3322aefdf1b5",
|
|
141
169
|
"tier": "protocol",
|
|
142
170
|
"overwrite_policy": "merge-3way",
|
|
143
171
|
"preserve_on_uninstall": false
|
|
144
172
|
},
|
|
173
|
+
{
|
|
174
|
+
"path": ".cleargate/knowledge/sprint-closeout-checklist.md",
|
|
175
|
+
"sha256": "d44f57445188bdefb18b39c6c121a1f52d32d9ca6122df91e54855e87fc2233e",
|
|
176
|
+
"tier": "protocol",
|
|
177
|
+
"overwrite_policy": "merge-3way",
|
|
178
|
+
"preserve_on_uninstall": false
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"path": ".cleargate/scripts/assert_story_files.mjs",
|
|
182
|
+
"sha256": "74db9e12008492e40c77cc9bffac4c689621ac5eededf9b342a87e45f918f003",
|
|
183
|
+
"tier": "script",
|
|
184
|
+
"overwrite_policy": "always",
|
|
185
|
+
"preserve_on_uninstall": false
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"path": ".cleargate/scripts/close_sprint.mjs",
|
|
189
|
+
"sha256": "d02be1cb8e0290782197a8b775c52b8f3064aaf661f5466c218dadb62179690a",
|
|
190
|
+
"tier": "script",
|
|
191
|
+
"overwrite_policy": "always",
|
|
192
|
+
"preserve_on_uninstall": false
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"path": ".cleargate/scripts/constants.mjs",
|
|
196
|
+
"sha256": "6f3fd11046bfd3d7f6b90b9ca70e02612a5db05ca21f2f2db3dce4473e720ce4",
|
|
197
|
+
"tier": "script",
|
|
198
|
+
"overwrite_policy": "always",
|
|
199
|
+
"preserve_on_uninstall": false
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"path": ".cleargate/scripts/dedupe_frontmatter.mjs",
|
|
203
|
+
"sha256": "6bf2816399cad2ab6f8f770de5eb920c3547b6fad9295c81f08aa6a4f894ef21",
|
|
204
|
+
"tier": "script",
|
|
205
|
+
"overwrite_policy": "always",
|
|
206
|
+
"preserve_on_uninstall": false
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"path": ".cleargate/scripts/file_surface_diff.sh",
|
|
210
|
+
"sha256": "a1c250ba35face9124183273fb04d45fdd4f8e43f405be4a765aeb58582753e9",
|
|
211
|
+
"tier": "script",
|
|
212
|
+
"overwrite_policy": "always",
|
|
213
|
+
"preserve_on_uninstall": false
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"path": ".cleargate/scripts/gate-checks.json",
|
|
217
|
+
"sha256": "188ef9995ce14e609ecf042563bab44d461df5315a4fd698e3eebfaf84db3b6a",
|
|
218
|
+
"tier": "script",
|
|
219
|
+
"overwrite_policy": "always",
|
|
220
|
+
"preserve_on_uninstall": false
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"path": ".cleargate/scripts/init_gate_config.sh",
|
|
224
|
+
"sha256": "47f4a9c6609d22d66acc9ccbceb1a144ad590d5ed17159ae5fb9811002a087e8",
|
|
225
|
+
"tier": "script",
|
|
226
|
+
"overwrite_policy": "always",
|
|
227
|
+
"preserve_on_uninstall": false
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"path": ".cleargate/scripts/init_sprint.mjs",
|
|
231
|
+
"sha256": "1d0f41df4325ea32981256aec15ed43eef09aba2a16ab4ba6d310cd61685556e",
|
|
232
|
+
"tier": "script",
|
|
233
|
+
"overwrite_policy": "always",
|
|
234
|
+
"preserve_on_uninstall": false
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"path": ".cleargate/scripts/lib/report-filename.mjs",
|
|
238
|
+
"sha256": "c26e2c0557f5e33d84058fc34db5c3258e5050093eabeb09fb22d067e458a8e2",
|
|
239
|
+
"tier": "script",
|
|
240
|
+
"overwrite_policy": "always",
|
|
241
|
+
"preserve_on_uninstall": false
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"path": ".cleargate/scripts/pre_gate_common.sh",
|
|
245
|
+
"sha256": "fd9af416b6db636901354fca64e60adcce9d4ce71dac96f2d718562a4bdb27e0",
|
|
246
|
+
"tier": "script",
|
|
247
|
+
"overwrite_policy": "always",
|
|
248
|
+
"preserve_on_uninstall": false
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"path": ".cleargate/scripts/pre_gate_runner.sh",
|
|
252
|
+
"sha256": "7f221089a353391f6e917c03a6813a26b6650a8b4e7e1c6a2bd845fa4ae081ca",
|
|
253
|
+
"tier": "script",
|
|
254
|
+
"overwrite_policy": "always",
|
|
255
|
+
"preserve_on_uninstall": false
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"path": ".cleargate/scripts/prefill_report.mjs",
|
|
259
|
+
"sha256": "bee417d96150410f78262a7fb4f485bf2f2e4191b8818085bdf60a664ebf7d62",
|
|
260
|
+
"tier": "script",
|
|
261
|
+
"overwrite_policy": "always",
|
|
262
|
+
"preserve_on_uninstall": false
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"path": ".cleargate/scripts/prep_doc_refresh.mjs",
|
|
266
|
+
"sha256": "822f887fc6c2754d2314f72b8ae62e1f20707b350b04c9867f9fd65068b21d79",
|
|
267
|
+
"tier": "script",
|
|
268
|
+
"overwrite_policy": "always",
|
|
269
|
+
"preserve_on_uninstall": false
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"path": ".cleargate/scripts/prep_qa_context.mjs",
|
|
273
|
+
"sha256": "68d69678f72fd6aa64bcf359fbd74f9c5b6b4fe598374f13c1261148b9907cab",
|
|
274
|
+
"tier": "script",
|
|
275
|
+
"overwrite_policy": "always",
|
|
276
|
+
"preserve_on_uninstall": false
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"path": ".cleargate/scripts/run_script.sh",
|
|
280
|
+
"sha256": "63ff100bb56361b06825d20dc601975e6df32bb688fe112b0d705dc45129ca20",
|
|
281
|
+
"tier": "script",
|
|
282
|
+
"overwrite_policy": "always",
|
|
283
|
+
"preserve_on_uninstall": false
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"path": ".cleargate/scripts/sprint_trends.mjs",
|
|
287
|
+
"sha256": "58732d158dcffca71fdc935200bbf9f8f14058cec7e05590345c335151dfa156",
|
|
288
|
+
"tier": "script",
|
|
289
|
+
"overwrite_policy": "always",
|
|
290
|
+
"preserve_on_uninstall": false
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"path": ".cleargate/scripts/state.schema.json",
|
|
294
|
+
"sha256": "d4e1c076764e5dc0573805502b3164d3b7d4977871cb67f5eca8a5035aeee37d",
|
|
295
|
+
"tier": "script",
|
|
296
|
+
"overwrite_policy": "always",
|
|
297
|
+
"preserve_on_uninstall": false
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"path": ".cleargate/scripts/suggest_improvements.mjs",
|
|
301
|
+
"sha256": "7d5853bf477447ae9090485648c3ba9426419504c6d36626c32454bf578c74a6",
|
|
302
|
+
"tier": "script",
|
|
303
|
+
"overwrite_policy": "always",
|
|
304
|
+
"preserve_on_uninstall": false
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
"path": ".cleargate/scripts/surface-whitelist.txt",
|
|
308
|
+
"sha256": "c1c14349265d741570dc4b0e61501c2a9e898a25cefad93911ef1298cf4d74c7",
|
|
309
|
+
"tier": "script",
|
|
310
|
+
"overwrite_policy": "always",
|
|
311
|
+
"preserve_on_uninstall": false
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"path": ".cleargate/scripts/test_ratchet.mjs",
|
|
315
|
+
"sha256": "429f6034ad6946f906c9068e9604d5348898687af0cf56badcae673b04369c5b",
|
|
316
|
+
"tier": "script",
|
|
317
|
+
"overwrite_policy": "always",
|
|
318
|
+
"preserve_on_uninstall": false
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
"path": ".cleargate/scripts/test/test_assert_story_files.sh",
|
|
322
|
+
"sha256": "6aace15a0de4d07b4b9e7454d2b38e266b7a80e265281135a050bd9f6be83aab",
|
|
323
|
+
"tier": "script",
|
|
324
|
+
"overwrite_policy": "always",
|
|
325
|
+
"preserve_on_uninstall": false
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"path": ".cleargate/scripts/test/test_file_surface.sh",
|
|
329
|
+
"sha256": "ada0e9583717a38bd912c0af16bb0e11c0b719a96df6dd511c879f0cf367788d",
|
|
330
|
+
"tier": "script",
|
|
331
|
+
"overwrite_policy": "always",
|
|
332
|
+
"preserve_on_uninstall": false
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
"path": ".cleargate/scripts/test/test_flashcard_gate.sh",
|
|
336
|
+
"sha256": "0e05a7fbaa86aeb9401e7df09696b9c547896512c41aa738a7c812d69d135916",
|
|
337
|
+
"tier": "script",
|
|
338
|
+
"overwrite_policy": "always",
|
|
339
|
+
"preserve_on_uninstall": false
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"path": ".cleargate/scripts/test/test_prep_qa_context.sh",
|
|
343
|
+
"sha256": "fd198bbc5d1faeaebd18ac72e5bcc2d84f931f035175bd51048ee04dcbd7ae0d",
|
|
344
|
+
"tier": "script",
|
|
345
|
+
"overwrite_policy": "always",
|
|
346
|
+
"preserve_on_uninstall": false
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"path": ".cleargate/scripts/test/test_test_ratchet.sh",
|
|
350
|
+
"sha256": "bfa13cb347824a525b636538d330a3ee3765f7908707f94149f2ffe69439729b",
|
|
351
|
+
"tier": "script",
|
|
352
|
+
"overwrite_policy": "always",
|
|
353
|
+
"preserve_on_uninstall": false
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"path": ".cleargate/scripts/update_state.mjs",
|
|
357
|
+
"sha256": "19eb2a3f7b0cc027a2805a49ba14029bcb70dbc8e98299375a375a6fe4adf2c5",
|
|
358
|
+
"tier": "script",
|
|
359
|
+
"overwrite_policy": "always",
|
|
360
|
+
"preserve_on_uninstall": false
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"path": ".cleargate/scripts/validate_bounce_readiness.mjs",
|
|
364
|
+
"sha256": "e4c6bead578a75a4f62fddbc1bccd40e92cc64f6136b3f893bb7cf50bacbd6ff",
|
|
365
|
+
"tier": "script",
|
|
366
|
+
"overwrite_policy": "always",
|
|
367
|
+
"preserve_on_uninstall": false
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
"path": ".cleargate/scripts/validate_state.mjs",
|
|
371
|
+
"sha256": "a1ad7e5f0525d3302759f9a04514e7205141c124abeb42fcda1f9d6042eca926",
|
|
372
|
+
"tier": "script",
|
|
373
|
+
"overwrite_policy": "always",
|
|
374
|
+
"preserve_on_uninstall": false
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
"path": ".cleargate/scripts/write_dispatch.sh",
|
|
378
|
+
"sha256": "4af4035555f4c6852ffd8f4635734931cfa2baef706f27f001bf0b2c64f7a0be",
|
|
379
|
+
"tier": "script",
|
|
380
|
+
"overwrite_policy": "always",
|
|
381
|
+
"preserve_on_uninstall": false
|
|
382
|
+
},
|
|
145
383
|
{
|
|
146
384
|
"path": ".cleargate/templates/Bug.md",
|
|
147
|
-
"sha256": "
|
|
385
|
+
"sha256": "d58c3d5d19387e7749c62570931a829fd1fc31bda83b6edba2b0854dafd6936d",
|
|
148
386
|
"tier": "template",
|
|
149
387
|
"overwrite_policy": "merge-3way",
|
|
150
388
|
"preserve_on_uninstall": false
|
|
151
389
|
},
|
|
152
390
|
{
|
|
153
391
|
"path": ".cleargate/templates/CR.md",
|
|
154
|
-
"sha256": "
|
|
392
|
+
"sha256": "434ac96bfd9aa8732a89d18ceb546101737b2b6fdc1b3858b5ea0153837bc6ee",
|
|
155
393
|
"tier": "template",
|
|
156
394
|
"overwrite_policy": "merge-3way",
|
|
157
395
|
"preserve_on_uninstall": false
|
|
158
396
|
},
|
|
159
397
|
{
|
|
160
398
|
"path": ".cleargate/templates/epic.md",
|
|
161
|
-
"sha256": "
|
|
399
|
+
"sha256": "bbb250b5ca905ed6f48b55b0c982296899d04a492f9427195960cee3e3632594",
|
|
162
400
|
"tier": "template",
|
|
163
401
|
"overwrite_policy": "merge-3way",
|
|
164
402
|
"preserve_on_uninstall": false
|
|
165
403
|
},
|
|
166
404
|
{
|
|
167
405
|
"path": ".cleargate/templates/hotfix.md",
|
|
168
|
-
"sha256": "
|
|
406
|
+
"sha256": "2d4fe14f12dbdae75cd8298bc547f39da89ecc9aaf917d32b3298a9b4936aaa2",
|
|
169
407
|
"tier": "template",
|
|
170
408
|
"overwrite_policy": "merge-3way",
|
|
171
409
|
"preserve_on_uninstall": false
|
|
172
410
|
},
|
|
173
411
|
{
|
|
174
412
|
"path": ".cleargate/templates/initiative.md",
|
|
175
|
-
"sha256": "
|
|
176
|
-
"tier": "template",
|
|
177
|
-
"overwrite_policy": "merge-3way",
|
|
178
|
-
"preserve_on_uninstall": false
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
"path": ".cleargate/templates/proposal.md",
|
|
182
|
-
"sha256": "227907f5de028453168c487e9c4ec4d4acd578298d13d658f7a7b63ef76dc23d",
|
|
413
|
+
"sha256": "08730306824f184a7d972346640493f100a5d1b44f0efe0ed855e1acedfd65d6",
|
|
183
414
|
"tier": "template",
|
|
184
415
|
"overwrite_policy": "merge-3way",
|
|
185
416
|
"preserve_on_uninstall": false
|
|
186
417
|
},
|
|
187
418
|
{
|
|
188
419
|
"path": ".cleargate/templates/Sprint Plan Template.md",
|
|
189
|
-
"sha256": "
|
|
420
|
+
"sha256": "8c359d0d7d06706cbae4c7c28777229ca3f8c4e1cc819795b4d39b349acbe9c1",
|
|
190
421
|
"tier": "template",
|
|
191
422
|
"overwrite_policy": "merge-3way",
|
|
192
423
|
"preserve_on_uninstall": false
|
|
@@ -200,14 +431,14 @@
|
|
|
200
431
|
},
|
|
201
432
|
{
|
|
202
433
|
"path": ".cleargate/templates/sprint_report.md",
|
|
203
|
-
"sha256": "
|
|
434
|
+
"sha256": "84e32e956eb1e8a9c97be1c346b695df316a9e47e17402f3d6581e3ffdbc4d2d",
|
|
204
435
|
"tier": "template",
|
|
205
436
|
"overwrite_policy": "merge-3way",
|
|
206
437
|
"preserve_on_uninstall": false
|
|
207
438
|
},
|
|
208
439
|
{
|
|
209
440
|
"path": ".cleargate/templates/story.md",
|
|
210
|
-
"sha256": "
|
|
441
|
+
"sha256": "a1413c4af5d854163741e92575fb913b93bdac1c1b7cfc59be8c3e0c8780eac0",
|
|
211
442
|
"tier": "template",
|
|
212
443
|
"overwrite_policy": "merge-3way",
|
|
213
444
|
"preserve_on_uninstall": false
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/auth/acquire.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\nexport const ConfigSchema = z\n .object({\n mcpUrl: z.string().url().optional(),\n profile: z.string().min(1).default('default'),\n logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n })\n .strict();\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/** Partial raw config used for each layer before merge */\ntype RawConfig = Partial<{\n mcpUrl: string | undefined;\n profile: string | undefined;\n logLevel: string | undefined;\n}>;\n\nexport interface LoadConfigOptions {\n flags?: RawConfig;\n env?: NodeJS.ProcessEnv;\n configPath?: string;\n}\n\n/**\n * Synchronously loads and merges config from all layers:\n * flags > env > config file > zod defaults\n */\nexport function loadConfig(opts: LoadConfigOptions = {}): Config {\n const {\n flags = {},\n env = process.env,\n configPath,\n } = opts;\n\n // Resolve config file path\n const resolvedConfigPath =\n configPath ??\n (() => {\n const home = os.homedir();\n if (!home) return null;\n return path.join(home, '.cleargate', 'config.json');\n })();\n\n // Layer: file\n let fileLayer: RawConfig = {};\n if (resolvedConfigPath) {\n try {\n const raw = fs.readFileSync(resolvedConfigPath, 'utf8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n `Failed to parse config file at ${resolvedConfigPath}: invalid JSON`,\n );\n }\n // Validate file contents strictly (unknown keys will throw here)\n const fileResult = ConfigSchema.safeParse(parsed);\n if (!fileResult.success) {\n throw new Error(\n `Invalid config file at ${resolvedConfigPath}: ${fileResult.error.message}`,\n );\n }\n fileLayer = fileResult.data;\n } catch (err) {\n // Re-throw parse/validation errors; silently skip only ENOENT\n if (\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'ENOENT'\n ) {\n // file doesn't exist — skip silently\n } else {\n throw err;\n }\n }\n }\n\n // Layer: env\n const envLayer: RawConfig = {};\n if (env['CLEARGATE_MCP_URL']) {\n envLayer.mcpUrl = env['CLEARGATE_MCP_URL'];\n }\n if (env['CLEARGATE_PROFILE']) {\n envLayer.profile = env['CLEARGATE_PROFILE'];\n }\n if (env['CLEARGATE_LOG_LEVEL']) {\n envLayer.logLevel = env['CLEARGATE_LOG_LEVEL'];\n }\n\n // Merge: flags > env > file (start from {} so zod defaults fill in missing fields)\n const merged: Record<string, unknown> = {\n ...fileLayer,\n ...envLayer,\n ...(flags.mcpUrl !== undefined ? { mcpUrl: flags.mcpUrl } : {}),\n ...(flags.profile !== undefined ? { profile: flags.profile } : {}),\n ...(flags.logLevel !== undefined ? { logLevel: flags.logLevel } : {}),\n };\n\n // Remove undefined values so zod defaults apply properly\n for (const key of Object.keys(merged)) {\n if (merged[key] === undefined) {\n delete merged[key];\n }\n }\n\n const result = ConfigSchema.safeParse(merged);\n if (!result.success) {\n throw new Error(`Config validation failed: ${result.error.message}`);\n }\n\n return result.data;\n}\n\n/**\n * Asserts mcpUrl is present, throws a user-friendly error if not.\n */\nexport function requireMcpUrl(cfg: Config): string {\n if (cfg.mcpUrl === undefined) {\n throw new Error(\n 'mcpUrl not configured. Run `cleargate join <invite-url>` first.',\n );\n }\n return cfg.mcpUrl;\n}\n","/**\n * acquireAccessToken — resolve a short-lived MCP access-token JWT.\n *\n * Resolution order (first success wins):\n * 1. CLEARGATE_MCP_TOKEN env var — CI / dev short-circuit (assumed JWT, not verified locally).\n * 2. In-memory single-flight cache (keyed by `${profile}::${mcpUrl}`) — returns cached token\n * if still valid (expires 60s before access token's `exp` claim).\n * 3. Stored refresh token (keychain/file) + POST /auth/refresh → rotates refresh token, returns access token.\n *\n * Errors surface to caller with a clear message so command handlers can exit cleanly.\n *\n * Lives here (not in mcp-client.ts) because the refresh flow needs TokenStore + mcpUrl and\n * mcp-client.ts is kept thin (just: host, bearer, JSON-RPC).\n */\nimport { createTokenStore } from './factory.js';\nimport type { TokenStore } from './token-store.js';\n\n// ── Single-flight in-memory cache ─────────────────────────────────────────────\n// Process-local; naturally cleared when the Node CLI exits.\n// Key: `${profile}::${mcpUrl}` — R1 mitigation: two profiles in same process never collide.\n// Env-token path (CLEARGATE_MCP_TOKEN) bypasses this cache entirely.\n\nconst CACHE = new Map<string, { accessToken: string; expiresAtMs: number }>();\n\n/** Test seam: clear the acquire cache between tests. */\nexport function __resetAcquireCache(): void {\n CACHE.clear();\n}\n\n/** Decode a JWT payload without verifying the signature (CLI-side only). */\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n const padded = parts[1].replace(/-/g, '+').replace(/_/g, '/');\n const json = Buffer.from(padded, 'base64').toString('utf8');\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nexport interface AcquireOptions {\n mcpUrl: string;\n profile: string;\n /** Force a fresh /auth/refresh even if the cache has a valid entry. */\n forceRefresh?: boolean;\n /** Test seam: overrides globalThis.fetch */\n fetch?: typeof globalThis.fetch;\n /** Test seam: overrides createTokenStore */\n createStore?: () => Promise<TokenStore>;\n /** Test seam: overrides process.env lookup */\n env?: NodeJS.ProcessEnv;\n /** Test seam: overrides Date.now() for expiry calculations. */\n now?: () => number;\n}\n\nexport class AcquireError extends Error {\n constructor(\n message: string,\n public readonly code:\n | 'env_token'\n | 'no_stored_token'\n | 'invalid_token'\n | 'token_revoked'\n | 'transport'\n | 'unexpected_status'\n | 'bad_response',\n ) {\n super(message);\n this.name = 'AcquireError';\n }\n}\n\n/**\n * Returns a bearer string suitable for Authorization headers against /mcp and\n * /admin-api. Rotates the stored refresh token on success.\n */\nexport async function acquireAccessToken(opts: AcquireOptions): Promise<string> {\n const env = opts.env ?? process.env;\n const nowFn = opts.now ?? Date.now;\n\n // 1. Env short-circuit — CI / dev / manual paste. Assumed to be a valid JWT.\n // Env tokens are NOT cached — they have no known exp without decoding + the\n // env is set per-invocation in CI anyway.\n const envToken = env['CLEARGATE_MCP_TOKEN'];\n if (envToken && envToken.length > 0) {\n return envToken;\n }\n\n // 2. Single-flight cache check (skip when forceRefresh is set).\n const cacheKey = `${opts.profile}::${opts.mcpUrl}`;\n if (!opts.forceRefresh) {\n const cached = CACHE.get(cacheKey);\n if (cached && nowFn() < cached.expiresAtMs) {\n return cached.accessToken;\n }\n }\n\n // 3. Stored refresh token → POST /auth/refresh.\n const store = await (opts.createStore ?? createTokenStore)();\n const stored = await store.load(opts.profile);\n if (!stored) {\n throw new AcquireError(\n `No stored credentials for profile '${opts.profile}'. Run \\`cleargate join <invite-url>\\` first, or export CLEARGATE_MCP_TOKEN.`,\n 'no_stored_token',\n );\n }\n\n const fetchFn = opts.fetch ?? globalThis.fetch;\n\n let response: Response;\n try {\n response = await fetchFn(`${opts.mcpUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ refresh_token: stored }),\n });\n } catch (err) {\n throw new AcquireError(\n `cannot reach ${opts.mcpUrl} (${err instanceof Error ? err.message : String(err)})`,\n 'transport',\n );\n }\n\n if (response.status === 401) {\n const body = (await response.json().catch(() => ({}))) as { error?: string };\n if (body.error === 'token_revoked') {\n throw new AcquireError(\n 'refresh token was revoked. Run `cleargate join <invite-url>` to re-authenticate.',\n 'token_revoked',\n );\n }\n throw new AcquireError(\n 'refresh token is invalid or expired. Run `cleargate join <invite-url>` to re-authenticate.',\n 'invalid_token',\n );\n }\n\n if (!response.ok) {\n throw new AcquireError(`unexpected status ${response.status} from /auth/refresh`, 'unexpected_status');\n }\n\n const body = (await response.json().catch(() => null)) as\n | { access_token?: unknown; refresh_token?: unknown }\n | null;\n if (\n !body ||\n typeof body.access_token !== 'string' ||\n typeof body.refresh_token !== 'string' ||\n body.access_token.length === 0 ||\n body.refresh_token.length === 0\n ) {\n throw new AcquireError('server returned unexpected /auth/refresh response shape', 'bad_response');\n }\n\n // Rotate — store the new refresh token so the next call uses a fresh jti.\n await store.save(opts.profile, body.refresh_token);\n\n const accessToken = body.access_token;\n\n // 4. Cache the new access token (expire 60s before the JWT exp claim).\n const payload = decodeJwtPayload(accessToken);\n const exp = payload?.exp;\n if (typeof exp === 'number' && Number.isFinite(exp)) {\n const expiresAtMs = (exp - 60) * 1000;\n CACHE.set(cacheKey, { accessToken, expiresAtMs });\n }\n // If exp is missing or non-numeric, do NOT cache — next call will re-refresh.\n\n return accessToken;\n}\n"],"mappings":"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","names":["body"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/whoami.ts"],"sourcesContent":["/**\n * cleargate whoami — smoke-test command that proves the stored refresh token\n * can be exchanged for a short-lived MCP access token, decodes the JWT payload\n * (no verification — just introspection), and prints identity fields.\n *\n * This is the first command to exercise the acquireAccessToken flow end-to-end;\n * sync/pull/push will be wired in follow-up stories.\n */\nimport { Buffer } from 'node:buffer';\nimport { loadConfig, requireMcpUrl } from '../config.js';\nimport { acquireAccessToken, AcquireError } from '../auth/acquire.js';\n\nexport interface WhoamiOptions {\n profile: string;\n mcpUrlFlag?: string;\n /** Test seam: replaces globalThis.fetch */\n fetch?: typeof globalThis.fetch;\n stdout?: (s: string) => void;\n stderr?: (s: string) => void;\n exit?: (code: number) => never;\n}\n\nfunction decodeJwtPayload(jwt: string): Record<string, unknown> | null {\n const parts = jwt.split('.');\n if (parts.length !== 3) return null;\n try {\n const json = Buffer.from(parts[1]!, 'base64url').toString('utf8');\n return JSON.parse(json);\n } catch {\n return null;\n }\n}\n\nexport async function whoamiHandler(opts: WhoamiOptions): Promise<void> {\n const stdout = opts.stdout ?? ((s) => process.stdout.write(s));\n const stderr = opts.stderr ?? ((s) => process.stderr.write(s));\n const exit = opts.exit ?? ((c: number): never => process.exit(c));\n\n const cfg = loadConfig({ flags: { profile: opts.profile, mcpUrl: opts.mcpUrlFlag } });\n let mcpUrl: string;\n try {\n mcpUrl = requireMcpUrl(cfg);\n } catch (err) {\n stderr(`cleargate: ${err instanceof Error ? err.message : String(err)}\\n`);\n exit(5);\n return;\n }\n\n let accessToken: string;\n try {\n accessToken = await acquireAccessToken({\n mcpUrl,\n profile: opts.profile,\n fetch: opts.fetch,\n });\n } catch (err) {\n if (err instanceof AcquireError) {\n stderr(`cleargate: ${err.message}\\n`);\n exit(err.code === 'transport' ? 2 : 5);\n return;\n }\n stderr(`cleargate: internal error: ${err instanceof Error ? err.message : String(err)}\\n`);\n exit(99);\n return;\n }\n\n const claims = decodeJwtPayload(accessToken);\n if (!claims) {\n stderr('cleargate: access token received but could not decode payload.\\n');\n exit(7);\n return;\n }\n\n stdout(\n [\n `mcp_url: ${mcpUrl}`,\n `profile: ${opts.profile}`,\n `member_id: ${claims.sub ?? '?'}`,\n `project_id: ${claims.project_id ?? '?'}`,\n `role: ${claims.role ?? '?'}`,\n `expires_at: ${typeof claims.exp === 'number' ? new Date(claims.exp * 1000).toISOString() : '?'}`,\n '',\n ].join('\\n'),\n );\n}\n"],"mappings":";;;;;;;;;;AAQA,SAAS,cAAc;AAcvB,SAAS,iBAAiB,KAA6C;AACrE,QAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,MAAI;AACF,UAAM,OAAO,OAAO,KAAK,MAAM,CAAC,GAAI,WAAW,EAAE,SAAS,MAAM;AAChE,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,cAAc,MAAoC;AACtE,QAAM,SAAS,KAAK,WAAW,CAAC,MAAM,QAAQ,OAAO,MAAM,CAAC;AAC5D,QAAM,SAAS,KAAK,WAAW,CAAC,MAAM,QAAQ,OAAO,MAAM,CAAC;AAC5D,QAAM,OAAO,KAAK,SAAS,CAAC,MAAqB,QAAQ,KAAK,CAAC;AAE/D,QAAM,MAAM,WAAW,EAAE,OAAO,EAAE,SAAS,KAAK,SAAS,QAAQ,KAAK,WAAW,EAAE,CAAC;AACpF,MAAI;AACJ,MAAI;AACF,aAAS,cAAc,GAAG;AAAA,EAC5B,SAAS,KAAK;AACZ,WAAO,cAAc,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AACzE,SAAK,CAAC;AACN;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,kBAAc,MAAM,mBAAmB;AAAA,MACrC;AAAA,MACA,SAAS,KAAK;AAAA,MACd,OAAO,KAAK;AAAA,IACd,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,QAAI,eAAe,cAAc;AAC/B,aAAO,cAAc,IAAI,OAAO;AAAA,CAAI;AACpC,WAAK,IAAI,SAAS,cAAc,IAAI,CAAC;AACrC;AAAA,IACF;AACA,WAAO,8BAA8B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AACzF,SAAK,EAAE;AACP;AAAA,EACF;AAEA,QAAM,SAAS,iBAAiB,WAAW;AAC3C,MAAI,CAAC,QAAQ;AACX,WAAO,kEAAkE;AACzE,SAAK,CAAC;AACN;AAAA,EACF;AAEA;AAAA,IACE;AAAA,MACE,eAAe,MAAM;AAAA,MACrB,eAAe,KAAK,OAAO;AAAA,MAC3B,eAAe,OAAO,OAAO,GAAG;AAAA,MAChC,eAAe,OAAO,cAAc,GAAG;AAAA,MACvC,eAAe,OAAO,QAAQ,GAAG;AAAA,MACjC,eAAe,OAAO,OAAO,QAAQ,WAAW,IAAI,KAAK,OAAO,MAAM,GAAI,EAAE,YAAY,IAAI,GAAG;AAAA,MAC/F;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;","names":[]}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
<instructions> FOLLOW THIS EXACT STRUCTURE. Output sections in order 1-4.
|
|
2
|
-
YAML Frontmatter: Proposal ID, Status, Author, and the crucial approved boolean.
|
|
3
|
-
§1 Initiative & Context: The "Why" and "What".
|
|
4
|
-
§2 Technical Architecture & Constraints: Architecture constraints, data flow, dependencies.
|
|
5
|
-
§3 Touched Files: Real files that will need modification.
|
|
6
|
-
Output location: .cleargate/delivery/pending-sync/PROPOSAL-{Name}.md
|
|
7
|
-
|
|
8
|
-
Document Hierarchy Position: LEVEL 0 (Proposal → Epic → Story)
|
|
9
|
-
|
|
10
|
-
CRITICAL PHASE GATE: Do NOT generate Epics or Stories, and do NOT invoke cleargate_push_item, until the Human has reviewed this document and manually changed approved: false to approved: true in the frontmatter.
|
|
11
|
-
|
|
12
|
-
Do NOT output these instructions. </instructions>
|
|
13
|
-
|
|
14
|
-
proposal_id: "PROP-{ID}" status: "Draft / In Review / Approved" author: "{AI Agent / Vibe Coder}" approved: false
|
|
15
|
-
created_at: "2026-04-17T00:00:00Z"
|
|
16
|
-
updated_at: "2026-04-17T00:00:00Z"
|
|
17
|
-
created_at_version: "strategy-phase-pre-init"
|
|
18
|
-
updated_at_version: "strategy-phase-pre-init"
|
|
19
|
-
server_pushed_at_version: null
|
|
20
|
-
draft_tokens:
|
|
21
|
-
input: null
|
|
22
|
-
output: null
|
|
23
|
-
cache_read: null
|
|
24
|
-
cache_creation: null
|
|
25
|
-
model: null
|
|
26
|
-
sessions: []
|
|
27
|
-
cached_gate_result:
|
|
28
|
-
pass: null
|
|
29
|
-
failing_criteria: []
|
|
30
|
-
last_gate_check: null
|
|
31
|
-
# Sync attribution. Optional; stamped by `cleargate push` / `cleargate pull`.
|
|
32
|
-
pushed_by: null # set by push: which user pushed
|
|
33
|
-
pushed_at: null # set by push: ISO-8601 timestamp
|
|
34
|
-
last_pulled_by: null # set by pull: which user pulled
|
|
35
|
-
last_pulled_at: null # set by pull: ISO-8601 timestamp
|
|
36
|
-
last_remote_update: null # set by pull: server's last-modified timestamp
|
|
37
|
-
source: "local-authored" # flips to "remote-authored" on intake
|
|
38
|
-
last_synced_status: null # required for conflict-detector; status at last sync
|
|
39
|
-
last_synced_body_sha: null # sha256 of body at last sync
|
|
40
|
-
PROPOSAL-{ID}: {Initiative Name}
|
|
41
|
-
1. Initiative & Context
|
|
42
|
-
1.1 Objective
|
|
43
|
-
{1-2 sentences explaining the high-level goal and business value.}
|
|
44
|
-
|
|
45
|
-
1.2 The "Why"
|
|
46
|
-
{Reason 1}
|
|
47
|
-
{Reason 2}
|
|
48
|
-
2. Technical Architecture & Constraints
|
|
49
|
-
2.1 Dependencies
|
|
50
|
-
{List required external APIs, packages, or systems}
|
|
51
|
-
2.2 System Constraints
|
|
52
|
-
Constraint Details
|
|
53
|
-
Architectural Rules {e.g., Must use purely functional components, etc.}
|
|
54
|
-
Security {e.g., Data must be encrypted at rest.}
|
|
55
|
-
3. Scope Impact (Touched Files & Data)
|
|
56
|
-
3.1 Known Files
|
|
57
|
-
path/to/existing/file.ext - {Explanation of expected change}
|
|
58
|
-
3.2 Expected New Entities
|
|
59
|
-
path/to/new/file.ext - {Explanation of purpose}
|
|
60
|
-
🔒 Approval Gate
|
|
61
|
-
(Vibe Coder: Review this proposal. If the architecture and context are correct, change approved: false to approved: true in the YAML frontmatter. Only then is the AI authorized to proceed with Epic/Story decomposition.)
|