cf2e66b39ee3dfed910258eccfa886ae2e02feaf
8 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b8c33647d8 |
refactor(tests): retire output-grep & source-grep via typed surfaces (finish #2974) (#462)
* refactor(#455): implement typed surfaces to retire grep tests Production surfaces added: - hooks/managed-hooks-registry.cjs: new CJS module exporting MANAGED_HOOKS as a typed array; gsd-check-update-worker.js now requires it instead of declaring an inline array - bin/install.js: elevate inline gsdHooks to module-level GSD_UNINSTALL_HOOKS, export it alongside runtimeMap/allRuntimes (already exported) - scripts/build-hooks.js: export HOOKS_TO_COPY; guard build() behind require.main===module so tests can require the file without triggering a build - get-shit-done/bin/lib/init.cjs: add --json mode to agent-skills command, emitting typed IR { agent_type, block, skills_count } for test assertions - get-shit-done/bin/gsd-tools.cjs: wire --json flag for agent-skills dispatch Category-B source-grep migrations: - tests/managed-hooks.test.cjs: require MANAGED_HOOKS from registry, drop fs.readFileSync+regex - tests/orphaned-hooks.test.cjs: require MANAGED_HOOKS+HOOKS_TO_COPY as typed exports - tests/hooks-opt-in.test.cjs: replace gsdHooks regex-parse with GSD_UNINSTALL_HOOKS import - tests/install-minimal-hooks.test.cjs: replace gsdHooks regex-parse with GSD_UNINSTALL_HOOKS - tests/copilot-install.test.cjs: replace src.includes() checks with typed assertions on runtimeMap, allRuntimes, parseRuntimeInput, buildRuntimePromptText - tests/agent-skills.test.cjs: migrate to --json typed IR assertions pending-migration-to-typed-ir token cleared (87 of 87 files): - 78 files already had source-text-is-the-product; removed duplicate token - 5 files already used typed assertions; reclassified or annotated - 4 files required individual reclassification to source-text-is-the-product or architectural-invariant Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#455): update workflow-guard test to typed GSD_UNINSTALL_HOOKS import; isolate HOME in runtime-launcher (D) test Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#455): guard install.js main() behind require.main===module so the typed export is require-safe Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(#455): document --json typed surfaces for agent-skills, progress, validate context Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(#455): add changeset fragment for new --json surfaces Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#455): complete grep migration for files flagged by lint-tests The branch commit 4e630d99 stripped `allow-test-rule: pending-migration-to-typed-ir` from ~80 test files without replacing their assertions or adding the correct exemption annotation. The files were NOT source-grep tests — they read .md workflow/agent/command/reference files (source-text-is-the-product) or hook source files for structural invariants (structural-regression-guard). No assertion logic was changed; only the correct allow-test-rule annotation was added to each file per CONTRIBUTING.md exception matrix. 73 files: `source-text-is-the-product` — workflow/agent/command/reference .md 7 files: `structural-regression-guard` — hook .js / bin/install.js structural checks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
918f987a19 |
feat(#2982): extend no-source-grep lint to catch var-binding readFileSync.includes() (#2985)
* feat(#2982): extend no-source-grep lint to catch var-binding readFileSync.includes() The base lint (scripts/lint-no-source-grep.cjs) only catches readFileSync(...).<text-method>() chained directly. The much more common var-binding form escapes it: const src = fs.readFileSync(p, 'utf8'); // 50 lines later if (src.includes('foo')) {} // ← still grep, lint missed it Scan of the test suite found ~141 files using this pattern. Implementation built TDD per #2982 with structured-IR assertions: scripts/lint-no-source-grep-extras.cjs - detectVarBindingViolations(src) — pure detector, two passes: pass 1 collects vars bound from readFileSync, pass 2 finds any <var>.<includes|startsWith|endsWith|match|search>( on those vars. - detectWrappedAssertOkMatch(src) — flags assert.ok(<expr>.match(...)) which escapes the assert.match rule. - VIOLATION enum exposes stable codes for tests to assert on. scripts/lint-no-source-grep.cjs - Wires the new detectors into the existing per-file check; one additional violation row per file with the first 3 sample tokens. tests/bug-2982-lint-var-binding.test.cjs - 13 tests, all assertions on typed VIOLATION enum / structured records. Covers all 5 text-match methods, multi-var, no-bind, string literal (must NOT trigger), wrapped assert.ok(.match), and assert.match (must NOT double-flag). Migration backlog (#2974 expanded scope): - 42 files annotated `// allow-test-rule: source-text-is-the-product` (legitimate — they read .md/.json/.yml files whose deployed text IS the product) - 3 files annotated `// allow-test-rule: pending-migration-to-typed-ir [#2974]` (read .cjs/.js source — clear migration debt) - 95 files annotated `pending-migration-to-typed-ir [#2974]` with `Per-file review may reclassify as source-text-is-the-product during migration` (mixed — manual review under #2974) After this lands the lint reports 0 violations on main; new violations in PRs surface immediately. Closes #2982 Refs #2974 * test(#2982): fix truncated test name per CR The label ended with a bare '(' from a copy-paste mishap. Now reads 'does NOT flag .matchAll(...) — matchAll is not match, so assert.ok(.matchAll(...)) is not flagged'. * chore(#2982): add changeset fragment for PR #2985 * chore(#2982): add changeset fragment for PR #2985 |
||
|
|
af2dba2328 |
fix(hooks): detect Claude Code via stdin session_id (closes #2520) (#2521)
* fix(hooks): detect Claude Code via stdin session_id, not filtered env (#2520) The #2344 fix assumed `CLAUDECODE` would propagate to hook subprocesses. On Claude Code v2.1.116 it doesn't — Claude Code applies a separate env filter to PreToolUse hook commands that drops bare CLAUDECODE and CLAUDE_SESSION_ID, keeping only CLAUDE_CODE_*-prefixed vars plus CLAUDE_PROJECT_DIR. As a result every Edit/Write on an existing file produced a redundant READ-BEFORE-EDIT advisory inside Claude Code. Use `data.session_id` from the hook's stdin JSON as the primary Claude Code signal (it's part of Claude Code's documented PreToolUse hook-input schema). Keep CLAUDE_CODE_ENTRYPOINT / CLAUDE_CODE_SSE_PORT env checks as propagation-verified fallbacks, and keep the legacy CLAUDE_SESSION_ID / CLAUDECODE checks for back-compat and future-proofing. Add tests/bug-2520-read-guard-hook-subprocess-env.test.cjs, which spawns the hook with an env mirroring the actual Claude Code hook-subprocess filter. Extend the legacy test harnesses to also strip the propagation-verified CLAUDE_CODE_* vars so positive-path tests keep passing when the suite itself runs inside a Claude Code session (same class of leak as #2370 / PR #2375, now covering the new detection signals). Non-Claude-host behavior (OpenCode / MiniMax) is unchanged: with no `session_id` on stdin and no CLAUDE_CODE_* env var, the advisory still fires. Closes #2520 * test(2520): isolate session_id signal from env fallbacks in regression test Per reviewer feedback (Copilot + CodeRabbit on #2521): the session_id isolation test used the helper's default CLAUDE_CODE_ENTRYPOINT / CLAUDE_CODE_SSE_PORT values, so the env fallback would rescue the skip even if the primary `data.session_id` check regressed. Pass an explicit env override that clears those fallbacks, so only the stdin `session_id` signal can trigger the skip. Other cases (env-only fallback, negative / non-Claude host) already override env appropriately. --------- Co-authored-by: forfrossen <forfrossensvart@gmail.com> |
||
|
|
86fb9c85c3 |
docs(sdk): registry docs and gsd-sdk query call sites (#2302 Track B) (#2340)
* feat(sdk): golden parity harness and query handler CJS alignment (#2302 Track A) Golden/read-only parity tests and registry alignment, query handler fixes (check-completion, state-mutation, commit, validate, summary, etc.), and WAITING.json dual-write for .gsd/.planning readers. Refs gsd-build/get-shit-done#2341 * fix(sdk): getMilestoneInfo matches GSD ROADMAP (🟡, last bold, STATE fallback) - Recognize in-flight 🟡 milestone bullets like 🚧. - Derive from last **vX.Y Title** before ## Phases when emoji absent. - Fall back to STATE.md milestone when ROADMAP is missing; use last bare vX.Y in cleaned text instead of first (avoids v1.0 from shipped list). - Fixes init.execute-phase milestone_version and buildStateFrontmatter after state.begin-phase (syncStateFrontmatter). * feat(sdk): phase list, plan task structure, requirements extract handlers - Register phase.list-plans, phase.list-artifacts, plan.task-structure, requirements.extract-from-plans (SDK-only; golden-policy exceptions). - Add unit tests; document in QUERY-HANDLERS.md. - writeProfile: honor --output, render dimensions, return profile_path and dimensions_scored. * feat(sdk): centralize getGsdAgentsDir in query helpers Extract agent directory resolution to helpers (GSD_AGENTS_DIR, primary ~/.claude/agents, legacy path). Use from init and docs-init init bundles. docs(15): add 15-CONTEXT for autonomous phase-15 run. * feat(sdk): query CLI CJS fallback and session correlation - createRegistry(eventStream, sessionId) threads correlation into mutation events - gsd-sdk query falls back to gsd-tools.cjs when no native handler matches (disable with GSD_QUERY_FALLBACK=off); stderr bridge warnings - Export createRegistry from @gsd-build/sdk; add sdk/README.md - Update QUERY-HANDLERS.md and registry module docs for fallback + sessionId - Agents: prefer node dist/cli.js query over cat/grep for STATE and plans * fix(sdk): init phase_found parity, docs-init agents path, state field extract - Normalize findPhase not-found to null before roadmap fallback (matches findPhaseInternal) - docs-init: use detectRuntime + resolveAgentsDir for checkAgentsInstalled - state.cjs stateExtractField: horizontal whitespace only after colon (YAML progress guard) - Tests: commit_docs default true; config-get golden uses temp config; golden integration green Refs: #2302 * refactor(sdk): share SessionJsonlRecord in profile-extract-messages CodeRabbit nit: dedupe JSONL record shape for isGenuineUserMessage and streamExtractMessages. * fix(sdk): address CodeRabbit major threads (paths, gates, audit, verify) - Resolve @file: and CLI JSON indirection relative to projectDir; guard empty normalized query command - plan.task-structure + intel extract/patch-meta: resolvePathUnderProject containment - check.config-gates: safe string booleans; plan_checker alias precedence over plan_check default - state.validate/sync: phaseTokenMatches + comparePhaseNum ordering - verify.schema-drift: token match phase dirs; files_modified from parsed frontmatter - audit-open: has_scan_errors, unreadable rows, human report when scans fail - requirements PLANNED key PLAN for root PLAN.md; gsd-tools timeout note - ingest-docs: repo-root path containment; classifier output slug-hash Golden parity test strips has_scan_errors until CJS adds field. * fix: Resolve CodeRabbit security and quality findings - Secure intel.ts and cli.ts against path traversal - Catch and validate git add status in commit.ts - Expand roadmap milestone marker extraction - Fix parsing array-of-objects in frontmatter YAML - Fix unhandled config evaluations - Improve coverage test parity mapping * docs(sdk): registry docs and gsd-sdk query call sites (#2302 Track B) Update CHANGELOG, architecture and user guides, workflow call sites, and read-guard tests for gsd-sdk query; sync ARCHITECTURE.md command/workflow counts and directory-tree totals with the repo (80 commands, 77 workflows). Address CodeRabbit: fix markdown tables and emphasis; align CLI-TOOLS GSDTools and state.read docs with implementation; correct roadmap handler name in universal-anti-patterns; resolve settings workflow config path without relying on config_path from state.load. Refs gsd-build/get-shit-done#2340 * test: raise planner character extraction limit to 48K * fix(sdk): resolve build TS error and doc conflict markers |
||
|
|
794f7e1b0b |
feat: /gsd-ultraplan-phase [BETA] — offload plan phase to Claude Code ultraplan (#2378)
* docs: add design spec for /gsd-ultraplan-phase beta command Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add /gsd-ultraplan-phase [BETA] command Offloads GSD plan phase to Claude Code's ultraplan cloud infrastructure. Plan drafts remotely while terminal stays free; browser UI for inline comments and revisions; imports back via existing /gsd-import --from. Intentionally isolated from /gsd-plan-phase so upstream ultraplan changes cannot break the core planning pipeline. Closes #2374 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: resolve 5 pre-existing test failures before PR - ARCHITECTURE.md: update command count 75→80 and workflow count 72→77 (stale doc counts; also incremented by new ultraplan-phase files) - sketch.md: add TEXT_MODE plain-text fallback for AskUserQuestion (#2012) - read-guard.test.cjs: clear CLAUDECODE env var alongside CLAUDE_SESSION_ID so positive-path hook tests pass when run inside a Claude Code session Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add BETA.md with /gsd-ultraplan-phase user documentation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address CodeRabbit review — MD040 fence labels and sketch.md TEXT_MODE duplicate - Add language identifiers to all unlabeled fenced blocks in ultraplan-phase.md and design spec (resolves MD040) - Remove duplicate TEXT_MODE explanation from sketch.md mood_intake step (was identical to the banner step definition) - Make AskUserQuestion conditional explicit in mood_intake prose Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
71af170a08 |
fix(tests): clear CLAUDECODE env var in read-guard test runner (#2375)
The hook skips its advisory on two env vars: CLAUDE_SESSION_ID and CLAUDECODE. runHook() cleared CLAUDE_SESSION_ID but inherited CLAUDECODE from process.env, so tests run inside a Claude Code session silently no-oped and produced no stdout, causing JSON.parse to throw. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
21d2bd039d |
fix(hooks): skip read-guard advisory on Claude Code runtime (#2001)
* fix(hooks): skip read-guard advisory on Claude Code runtime (#1984) Claude Code natively enforces read-before-edit at the runtime level, so the gsd-read-guard.js advisory is redundant — it wastes ~80 tokens per Write/Edit call and clutters tool flow with system-reminder noise. Add early exit when CLAUDE_SESSION_ID is set (standard Claude Code session env var). Non-Claude runtimes (OpenCode, Gemini, etc.) that lack native read-before-edit enforcement continue to receive the advisory as before. Closes #1984 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(hooks): sanitize runHook env to prevent test failures in Claude Code The runHook() test helper now blanks CLAUDE_SESSION_ID so positive-path tests pass even when the test suite runs inside a Claude Code session. The new skip test passes the env var explicitly via envOverrides. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
9d626de5fa |
fix(hooks): add read-before-edit guard for non-Claude runtimes (#1645)
* fix(hooks): add read-before-edit guidance for non-Claude runtimes When models that don't natively enforce read-before-edit hit the guard, the error message now includes explicit instruction to Read first. This prevents infinite retry loops that burn through usage. Closes #1628 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(build): register gsd-read-guard.js in HOOKS_TO_COPY and harden tests The hook was missing from scripts/build-hooks.js, so global installs would never receive the hook file in hooks/dist/. Also adds tests for build registration, install uninstall list, and non-string file_path. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |