* chore(#604): rename get-shit-done/ runtime directory to gsd-core/ Renames the installed runtime directory `get-shit-done/` to `gsd-core/` so the on-disk name matches the package (`@opengsd/gsd-core`), repo, and binary (`gsd-tools`). The npm package name and binary are unchanged; npx/npm consumers are unaffected. Mechanical (bulk, ~90% of the diff): - `git mv get-shit-done gsd-core` - Swept path/identifier references across the repo via `perl -pe 's/get-shit-done(?!-\w)/gsd-core/g'`. The negative lookahead preserves the five legitimate slug variants that are NOT the directory: get-shit-done-{OLD,cc,classic,cli,redux} (old package/repo names). - Build/manifest wiring: package.json (bin, files, coverage globs), tsconfig.build.json (outDir), ~86 .gitignore build-output entries, stryker.config.mjs, scan-ignore files, install.js path strings. - Frozen (not rewritten): CHANGELOG.md history; translated docs (README.<locale>.md and docs/{ja-JP,ko-KR,pt-BR,zh-CN}/). New logic (review here): - src/installer-migrations/003-rename-get-shit-done-to-gsd-core.cts: a proper ADR-0008 installer migration. On upgrade it walks the legacy `~/.claude/get-shit-done/` tree, classifies each file via the prior install manifest, and emits remove-managed / backup-and-remove for managed files while PRESERVING unknown user-added files. Symlink-safe (skips a symlinked root and symlinked entries; bounds-checks every path under configDir). The framework rolls back on install failure. Emptied dirs may remain (framework has no recursive dir-removal primitive) — documented. - scripts/lint-legacy-dir-name.cjs: CI regression guard forbidding the bare `get-shit-done` directory token (split token to avoid self-match; case- insensitive; `(?!-\w)` lookahead allows the slug variants; allowlists CHANGELOG, translated docs, and `gsd-allow-legacy-name` marker lines). Wired into the lint-tests CI job. - Restored scripts/lint-package-identity-drift.cjs detection regexes (the mechanical sweep had wrongly rewritten the old-name patterns it exists to detect) and marked them as intentional legacy references. - TDD tests for the migration and the guard; do.md slash-command guard regex tightened so a `/gsd-core/bin` path segment is not mistaken for a command; changeset + docs/installer-migrations.md row added. Breaking: the installed runtime path moves `~/.claude/get-shit-done/` -> `~/.claude/gsd-core/`. Migration 003 removes the stale legacy dir's managed files (preserving user files) on upgrade. Users with custom hooks/configs hardcoding the old path must update them. Closes #604 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#604): unsweep pending changesets + allowlist injection-example docs CI fixes for the rename PR: - Do not sweep pending .changeset/*.md (ephemeral release-note fragments, like CHANGELOG); reverted those body edits so 5 pre-existing malformed fragments (missing type/pr) no longer enter the PR diff and trip docs-lint. Allowlisted .changeset/ in the legacy-name guard accordingly. - Allowlisted TEST-EXAMPLES.md and docs/explanation/security-model.md in prompt-injection-scan.sh: they contain intentional injection examples / security-model prose; the path-reference rewrites are kept. CodeQL alerts on this PR are pre-existing (alert lines unchanged by this PR; none in the new migration/guard) and are out of scope for the rename. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#604): resolve CodeQL alerts surfaced on this PR The rename diff touched files carrying pre-existing CodeQL findings; per the no-pre-existing-dismissal rule, fixing every surfaced alert rather than waving them off. All behavior-preserving: - scripts/ci-test-scope.cjs: build the config-path match from string .includes() instead of a RegExp over an arg-derived value (js/regex-injection). - src/profile-output.cts: escape backslashes before pipe-escaping desc/safeName so the table-cell escape is complete (js/incomplete-sanitization). - tests/{bug-2643,bug-2808,docs-parity-live-registry}: two-pass HTML-comment strip so a bare/unclosed `<!--` cannot survive (js/incomplete-multi-character-sanitization). - tests/inline-plan-threshold: drop the no-op `\s`->`\s` identity replace, keep the meaningful POSIX-class conversion (js/identity-replacement). Verified: build:lib green; the touched test files + ci-test-scope + profile-output suites pass; lint:legacy-name clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#604): correctly resolve remaining CodeQL alerts (regex-injection + sanitization) The prior commit's fixes for two alerts were ineffective: - ci-test-scope.cjs js/regex-injection: the alert is the CLI-arg-derived `file` reaching static regex `.test(file)` calls (not the config rule). Removed ALL regex over file/t — startsWith/includes/=== string checks + an isWindowsHint helper — so there is no regex sink for the tainted value. - js/incomplete-multi-character-sanitization (3 test files): a single `.replace(/<!--...-->/g,'')` can let `<!--` re-form. Replaced with a fixpoint loop (replace until stable) plus a final bare-opener strip. Verified: no regex over file/t remains; ci-test-scope + the 3 test suites pass; lint:legacy-name clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#604): make ci-test-scope + comment-strippers regex-free to clear CodeQL CodeQL flags the regex PATTERNS syntactically (regex-injection on the --files arg split; incomplete-multi-character-sanitization on the <!--...--> replace), so loop fixes do not satisfy it. Made these paths regex-free: - ci-test-scope.cjs splitFiles: char-by-char separator tokenizer (no /[,\\s]+/). - 3 test files: indexOf/slice HTML-comment stripper (no .replace(/<!--/)). Behavior preserved; ci-test-scope + the 3 suites pass; guard clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#604): unblock security base64 scan on the large rename diff The security job hit its 10m timeout: base64-scan.sh choked on the binary test fixture tests/feat-3594-parser-property-style.test.cjs (embedded NUL/ non-UTF8 bytes -> thousands of bogus blobs + "ignored null byte" warnings), and the ~800-file rename diff is slow to scan regardless. - scripts/base64-scan.sh: skip binary-by-content files (grep -Iq .) — they can't carry base64-obfuscated *text* and feeding NUL bytes through the per-line scanner is pathologically slow. collect_files already filtered binary *extensions*; this catches binary *content* in text extensions. - .github/workflows/security-scan.yml: raise the security job timeout 10m->30m to accommodate very large diffs (the scan itself is unchanged). Verified locally: scan skips the fixture, 0 "ignored null byte" warnings, 0 findings, exit 0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#604): sweep get-shit-done refs introduced by merging next The branch was updated with next (#614/#384/#618 etc.), which reference the get-shit-done/ dir (still named that on next). Swept the stale references in the merged files to gsd-core so the rename stays consistent and lint:legacy-name passes: - commands/gsd/discuss-phase.md (runtime-launcher shim paths) - src/core.cts (getAgentsDir layout comments) - tests/bug-384-agents-runtime-aware.test.cjs (require path to runtime lib) Verified: guard 0 violations; build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#604): exclude gsd-core/ path segments from bug-3683 command cross-ref invariant The #614 runtime-launcher shim added to discuss-phase.md references `${_GSD_RUNTIME_ROOT}/gsd-core/bin/...`. bug-3683's REF_PATTERN excluded path-y refs only via lookbehind, but `}` precedes `/gsd-core/` in the shim, so it mis-read the directory path as a dangling `/gsd-core` command ref (same class as the #604 bug-2954 fix). Added a trailing `(?![\w-]*\/)` so `/gsd-<x>/...` path segments are not treated as slash-command references. Verified locally on BOTH platforms before pushing: - mac (node 26) full suite: 0 failures - gsd-test-runner (linux, node22 image) full suite: 0 failures - bug-3683 + bug-2954 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#604): lazily resolve findProjectRoot in gsd-tools (harden flaky CI) CI intermittently failed state.test's gsd-tools subprocess with "findProjectRoot is not a function" (flip-flopping across legs; not reproducible on mac full suite, gsd-test linux full suite, test:unit, or state.test x8). findProjectRoot is a re-export from core.cjs (sourced from project-root.cjs); binding it via destructure at module-load can be undefined under a load-ordering edge. Resolve it lazily at call time via a small wrapper so the lookup happens after core.cjs is fully initialized. Verified green on BOTH platforms before pushing: - mac (node 26) full suite: 0 failures - gsd-test-runner (linux, node22) full suite: 0 failures - state.test.cjs: 106/106; gsd-tools loads cleanly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#604): allowlist verification-patterns.md placeholder examples in secret scan The rename git-mv'd references/verification-patterns.md into gsd-core/, pulling it into the secret-scan diff. It documents stub/placeholder RED-FLAG env-var examples (illustrative Stripe test-key / database-URL / API-key placeholders) — not real credentials. Added it to .secretscanignore with the strict annotation, mirroring the existing gsd-core/workflows/plan-phase.md exception. Verified locally: secret-scan-lint --strict OK; secret-scan --diff origin/next exits 0 with 0 findings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
244
gsd-core/workflows/pause-work.md
Normal file
244
gsd-core/workflows/pause-work.md
Normal file
@@ -0,0 +1,244 @@
|
||||
<purpose>
|
||||
Create structured `.planning/HANDOFF.json` and `.continue-here.md` handoff files to preserve complete work state across sessions. The JSON provides machine-readable state for `/gsd:resume-work`; the markdown provides human-readable context.
|
||||
</purpose>
|
||||
|
||||
<required_reading>
|
||||
Read all files referenced by the invoking prompt's execution_context before starting.
|
||||
</required_reading>
|
||||
|
||||
<process>
|
||||
|
||||
<step name="detect">
|
||||
## Context Detection
|
||||
|
||||
Determine what kind of work is being paused and set the handoff destination accordingly:
|
||||
|
||||
```bash
|
||||
# Check for active phase
|
||||
phase=$(( ls -lt .planning/phases/*/PLAN.md 2>/dev/null || true ) | head -1 | grep -oP 'phases/\K[^/]+' || true)
|
||||
|
||||
# Check for active spike
|
||||
spike=$(( ls -lt .planning/spikes/*/SPIKE.md .planning/spikes/*/DESIGN.md .planning/spikes/*/README.md 2>/dev/null || true ) | head -1 | grep -oP 'spikes/\K[^/]+' || true)
|
||||
|
||||
# Check for active sketch
|
||||
sketch=$(( ls -lt .planning/sketches/*/README.md .planning/sketches/*/index.html 2>/dev/null || true ) | head -1 | grep -oP 'sketches/\K[^/]+' || true)
|
||||
|
||||
# Check for active deliberation
|
||||
deliberation=$(ls .planning/deliberations/*.md 2>/dev/null | head -1 || true)
|
||||
```
|
||||
|
||||
- **Phase work**: active phase directory → handoff to `.planning/phases/XX-name/.continue-here.md`
|
||||
- **Spike work**: active spike directory or spike-related files (no active phase) → handoff to `.planning/spikes/SPIKE-NNN/.continue-here.md` (create directory if needed)
|
||||
- **Sketch work**: active sketch directory (no active phase/spike) → handoff to `.planning/sketches/.continue-here.md`
|
||||
- **Deliberation work**: active deliberation file (no phase/spike/sketch) → handoff to `.planning/deliberations/.continue-here.md`
|
||||
- **Research work**: research notes exist but no phase/spike/sketch/deliberation → handoff to `.planning/.continue-here.md`
|
||||
- **Default**: no detectable context → handoff to `.planning/.continue-here.md`, note the ambiguity in `<current_state>`
|
||||
|
||||
If phase is detected, proceed with phase handoff path. Otherwise use the first matching non-phase path above.
|
||||
</step>
|
||||
|
||||
<step name="gather">
|
||||
**Collect complete state for handoff:**
|
||||
|
||||
1. **Current position**: Which phase, which plan, which task
|
||||
2. **Work completed**: What got done this session
|
||||
3. **Work remaining**: What's left in current plan/phase
|
||||
4. **Decisions made**: Key decisions and rationale
|
||||
5. **Blockers/issues**: Anything stuck
|
||||
6. **Human actions pending**: Things that need manual intervention (MCP setup, API keys, approvals, manual testing)
|
||||
7. **Background processes**: Any running servers/watchers that were part of the workflow
|
||||
8. **Files modified**: What's changed but not committed
|
||||
9. **Blocking constraints**: Anti-patterns or methodological failures encountered during this session that a resuming agent MUST be aware of before proceeding. Only include items discovered through actual failure — not warnings or predictions. Assign each constraint a `severity`:
|
||||
- `blocking` — The resuming agent MUST demonstrate understanding before proceeding. The discuss-phase and execute-phase workflows will enforce a mandatory understanding check.
|
||||
- `advisory` — Important context but does not gate resumption.
|
||||
|
||||
Ask user for clarifications if needed via conversational questions.
|
||||
|
||||
**Also inspect SUMMARY.md files for false completions:**
|
||||
```bash
|
||||
# Check for placeholder content in existing summaries
|
||||
grep -l "To be filled\|placeholder\|TBD" .planning/phases/*/*.md 2>/dev/null || true
|
||||
```
|
||||
Report any summaries with placeholder content as incomplete items.
|
||||
</step>
|
||||
|
||||
<step name="write_structured">
|
||||
**Write structured handoff to `.planning/HANDOFF.json`:**
|
||||
|
||||
```bash
|
||||
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
|
||||
timestamp=$(gsd_run query current-timestamp full --raw)
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"timestamp": "{timestamp}",
|
||||
"phase": "{phase_number}",
|
||||
"phase_name": "{phase_name}",
|
||||
"phase_dir": "{phase_dir}",
|
||||
"plan": {current_plan_number},
|
||||
"task": {current_task_number},
|
||||
"total_tasks": {total_task_count},
|
||||
"status": "paused",
|
||||
"completed_tasks": [
|
||||
{"id": 1, "name": "{task_name}", "status": "done", "commit": "{short_hash}"},
|
||||
{"id": 2, "name": "{task_name}", "status": "done", "commit": "{short_hash}"},
|
||||
{"id": 3, "name": "{task_name}", "status": "in_progress", "progress": "{what_done}"}
|
||||
],
|
||||
"remaining_tasks": [
|
||||
{"id": 4, "name": "{task_name}", "status": "not_started"},
|
||||
{"id": 5, "name": "{task_name}", "status": "not_started"}
|
||||
],
|
||||
"blockers": [
|
||||
{"description": "{blocker}", "type": "technical|human_action|external", "workaround": "{if any}"}
|
||||
],
|
||||
"human_actions_pending": [
|
||||
{"action": "{what needs to be done}", "context": "{why}", "blocking": true}
|
||||
],
|
||||
"decisions": [
|
||||
{"decision": "{what}", "rationale": "{why}", "phase": "{phase_number}"}
|
||||
],
|
||||
"uncommitted_files": [],
|
||||
"next_action": "{specific first action when resuming}",
|
||||
"context_notes": "{mental state, approach, what you were thinking}"
|
||||
}
|
||||
```
|
||||
</step>
|
||||
|
||||
<step name="write">
|
||||
**Write handoff to the path determined in the detect step** (e.g. `.planning/phases/XX-name/.continue-here.md`, `.planning/spikes/SPIKE-NNN/.continue-here.md`, or `.planning/.continue-here.md`):
|
||||
|
||||
```markdown
|
||||
---
|
||||
context: [phase|spike|sketch|deliberation|research|default]
|
||||
phase: XX-name
|
||||
task: 3
|
||||
total_tasks: 7
|
||||
status: in_progress
|
||||
last_updated: [timestamp from current-timestamp]
|
||||
---
|
||||
|
||||
# BLOCKING CONSTRAINTS — Read Before Anything Else
|
||||
|
||||
> These are not suggestions. Each constraint below was discovered through failure.
|
||||
> Acknowledge each one explicitly before proceeding.
|
||||
|
||||
- [ ] CONSTRAINT: [name] — [what it is] — [structural mitigation required]
|
||||
|
||||
**Do not proceed until all boxes are checked.**
|
||||
|
||||
_If no constraints have been identified yet, remove this section._
|
||||
|
||||
## Critical Anti-Patterns
|
||||
|
||||
| Pattern | Description | Severity | Prevention Mechanism |
|
||||
|---------|-------------|----------|---------------------|
|
||||
| [pattern name] | [what it is and how it manifested] | blocking | [structural step that prevents recurrence — not acknowledgment] |
|
||||
| [pattern name] | [what it is and how it manifested] | advisory | [guidance for avoiding it] |
|
||||
|
||||
**Severity values:** `blocking` — resuming agent must pass understanding check before proceeding. `advisory` — important context, does not gate resumption.
|
||||
|
||||
_Remove rows that do not apply. The discuss-phase and execute-phase workflows parse this table and enforce a mandatory understanding check for any `blocking` rows._
|
||||
|
||||
<current_state>
|
||||
[Where exactly are we? Immediate context]
|
||||
</current_state>
|
||||
|
||||
<completed_work>
|
||||
|
||||
Completed Tasks:
|
||||
- Task 1: [name] - Done
|
||||
- Task 2: [name] - Done
|
||||
- Task 3: [name] - In progress, [what's done]
|
||||
</completed_work>
|
||||
|
||||
<remaining_work>
|
||||
|
||||
- Task 3: [what's left]
|
||||
- Task 4: Not started
|
||||
- Task 5: Not started
|
||||
</remaining_work>
|
||||
|
||||
<decisions_made>
|
||||
|
||||
- Decided to use [X] because [reason]
|
||||
- Chose [approach] over [alternative] because [reason]
|
||||
</decisions_made>
|
||||
|
||||
<blockers>
|
||||
- [Blocker 1]: [status/workaround]
|
||||
</blockers>
|
||||
|
||||
## Required Reading (in order)
|
||||
<!-- List documents the resuming agent must read before acting -->
|
||||
1. [document] — [why it matters]
|
||||
1. `.planning/METHODOLOGY.md` (if it exists) — project analytical lenses; apply before any assumption analysis
|
||||
|
||||
## Critical Anti-Patterns (do NOT repeat these)
|
||||
<!-- Mistakes discovered this session that must be structurally avoided -->
|
||||
- [ANTI-PATTERN]: [what it is] → [structural mitigation]
|
||||
|
||||
## Infrastructure State
|
||||
<!-- Running services, external state, environment specifics -->
|
||||
- [service/env]: [current state]
|
||||
|
||||
## Pre-Execution Critique Required
|
||||
<!-- Fill in ONLY if pausing between design and execution (e.g. spike design done, not yet run) -->
|
||||
- Design artifact: [path]
|
||||
- Critique focus: [key questions the critic should probe]
|
||||
- Gate: Do NOT begin execution until critique is complete and design is revised
|
||||
|
||||
<context>
|
||||
[Mental state, what were you thinking, the plan]
|
||||
</context>
|
||||
|
||||
<next_action>
|
||||
Start with: [specific first action when resuming]
|
||||
</next_action>
|
||||
```
|
||||
|
||||
Be specific enough for a fresh Claude to understand immediately.
|
||||
|
||||
Use `current-timestamp` for last_updated field. You can use init todos (which provides timestamps) or call directly:
|
||||
```bash
|
||||
timestamp=$(gsd_run query current-timestamp full --raw)
|
||||
```
|
||||
</step>
|
||||
|
||||
<step name="commit">
|
||||
```bash
|
||||
gsd_run query commit "wip: [context-name] paused at [X]/[Y]" --files [handoff-path] .planning/HANDOFF.json
|
||||
```
|
||||
</step>
|
||||
|
||||
<step name="confirm">
|
||||
```
|
||||
✓ Handoff created:
|
||||
- .planning/HANDOFF.json (structured, machine-readable)
|
||||
- [handoff-path] (human-readable)
|
||||
|
||||
Current state:
|
||||
|
||||
- Context: [phase|spike|deliberation|research]
|
||||
- Location: [XX-name or SPIKE-NNN]
|
||||
- Task: [X] of [Y]
|
||||
- Status: [in_progress/blocked]
|
||||
- Blockers: [count] ({human_actions_pending count} need human action)
|
||||
- Committed as WIP
|
||||
|
||||
To resume: /gsd:resume-work
|
||||
|
||||
```
|
||||
</step>
|
||||
|
||||
</process>
|
||||
|
||||
<success_criteria>
|
||||
- [ ] Context detected (phase/spike/deliberation/research/default)
|
||||
- [ ] .continue-here.md created at correct path for detected context
|
||||
- [ ] Required Reading, Anti-Patterns, and Infrastructure State sections filled
|
||||
- [ ] Pre-Execution Critique section filled if pausing between design and execution
|
||||
- [ ] Committed as WIP
|
||||
- [ ] User knows location and how to resume
|
||||
</success_criteria>
|
||||
Reference in New Issue
Block a user