Commit graph

3141 commits

Author SHA1 Message Date
Copilot
21b2b6c795 fix: recursive key sorting in tool-call loop guard hash function (#1962)
* Initial plan

* fix: use recursive-sort replacer in hashToolCall to preserve nested properties

The array replacer in JSON.stringify acted as a property-name whitelist at
every nesting level, stripping all nested object properties and causing
structurally different tool calls to produce identical hashes. This led to
false-positive loop detection for tools with nested/array arguments like
ask_user_questions, plan_clarify, browser_batch, etc.

Replace with a function replacer that recursively sorts object keys while
preserving array order and primitive values.

Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gsd-build/gsd-2/sessions/c10384bc-a2f9-46b8-8380-43ea451ed39d

* fix: add missing codeFilesChanged to mergeMilestoneToMain mock in journal-integration test

Pre-existing typecheck failure: the mock was missing the codeFilesChanged
property added to the mergeMilestoneToMain return type.

Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gsd-build/gsd-2/sessions/debb019f-2fc8-4c76-b809-ecfe48993eff

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: glittercowboy <186001655+glittercowboy@users.noreply.github.com>
2026-03-22 09:54:03 -06:00
Lex Christopherson
17a2f55edb fix: use path.sep for cross-platform path traversal guards and test assertions
Path traversal guards used hardcoded "/" separator which fails on Windows
where resolve() produces backslash paths. Test assertions also used
forward-slash path fragments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 09:39:21 -06:00
Lex Christopherson
97241ea19c fix(tests): use cross-platform path split in run-manager timestamp test
The test split on "/" which fails on Windows where paths use "\".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 09:31:08 -06:00
Jay the Reaper
2a3493c291 fix(pi-coding-agent): prevent crash when login is cancelled 2026-03-22 22:25:20 +07:00
TÂCHES
2aa01b8a60 feat(gsd): declarative workflow engine — YAML-defined workflows through the auto-loop (#2024)
* docs(S01): add slice plan

* feat(S01/T01): Created four engine abstraction layer files: engine-type…

- src/resources/extensions/gsd/engine-types.ts
- src/resources/extensions/gsd/workflow-engine.ts
- src/resources/extensions/gsd/execution-policy.ts
- src/resources/extensions/gsd/engine-resolver.ts

* test(S01/T02): Added activeEngineId to AutoSession lifecycle (property,…

- src/resources/extensions/gsd/auto/session.ts
- src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts

* chore(M001/S02): auto-commit after research-slice

* docs(S02): add slice plan

* feat(S02/T01): Created DevWorkflowEngine and DevExecutionPolicy classes…

- src/resources/extensions/gsd/dev-workflow-engine.ts
- src/resources/extensions/gsd/dev-execution-policy.ts
- src/resources/extensions/gsd/engine-resolver.ts
- src/resources/extensions/gsd/auto.ts

* test(S02/T02): Added 18 contract tests for dev engine wrapper and updat…

- src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts
- src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts

* docs(S03): add slice plan

* chore(S03/T01): Added definition-loader.ts with V1 YAML schema validati…

- src/resources/extensions/gsd/definition-loader.ts
- src/resources/extensions/gsd/tests/definition-loader.test.ts

* feat(S03/T02): Added graph.ts with YAML I/O, DAG dependency queries, im…

- src/resources/extensions/gsd/graph.ts
- src/resources/extensions/gsd/tests/graph-operations.test.ts

* docs(S04): add slice plan

* test(S04/T01): Created run-manager with createRun/listRuns, CustomWorkf…

- src/resources/extensions/gsd/run-manager.ts
- src/resources/extensions/gsd/custom-workflow-engine.ts
- src/resources/extensions/gsd/custom-execution-policy.ts
- src/resources/extensions/gsd/tests/run-manager.test.ts
- src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts

* feat(S04/T02): Extended engine-resolver with custom engine branch, adde…

- src/resources/extensions/gsd/engine-resolver.ts
- src/resources/extensions/gsd/auto/session.ts
- src/resources/extensions/gsd/auto.ts
- src/resources/extensions/gsd/auto-dashboard.ts

* test(S04/T03): Added polymorphic custom engine dispatch path to autoLoo…

- src/resources/extensions/gsd/auto/loop.ts
- src/resources/extensions/gsd/auto/phases.ts
- src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts

* docs(S05): add slice plan

* feat(S05/T01): Created custom-verification.ts with four policy handlers…

- src/resources/extensions/gsd/custom-verification.ts
- src/resources/extensions/gsd/custom-execution-policy.ts
- src/resources/extensions/gsd/engine-resolver.ts
- src/resources/extensions/gsd/tests/custom-verification.test.ts

* feat(S05/T02): Created context-injector.ts with injectContext() that re…

- src/resources/extensions/gsd/context-injector.ts
- src/resources/extensions/gsd/custom-workflow-engine.ts
- src/resources/extensions/gsd/tests/context-injector.test.ts

* docs(S06): add slice plan

* test(S06/T01): Wired expandIteration() into resolveDispatch() with DEFI…

- src/resources/extensions/gsd/custom-workflow-engine.ts
- src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts
- src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts

* docs(S07): add slice plan

* feat(S07/T01): Added six `/gsd workflow` subcommands (new, run, list, v…

- src/resources/extensions/gsd/commands/handlers/workflow.ts
- src/resources/extensions/gsd/commands/catalog.ts
- src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts

* fix(S07/T02): Added updateProgressWidget call in custom engine path and…

- src/resources/extensions/gsd/auto/loop.ts
- src/resources/extensions/gsd/dashboard-overlay.ts
- src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts

* docs(S08): add slice plan

* docs(S08/T01): Created 7-file router-pattern skill for conversational Y…

- src/resources/skills/create-workflow/SKILL.md
- src/resources/skills/create-workflow/workflows/create-from-scratch.md
- src/resources/skills/create-workflow/workflows/create-from-template.md
- src/resources/skills/create-workflow/references/yaml-schema-v1.md
- src/resources/skills/create-workflow/references/verification-policies.md
- src/resources/skills/create-workflow/references/feature-patterns.md
- src/resources/skills/create-workflow/templates/workflow-definition.yaml

* test(S08/T02): Created 3 example workflow definitions (blog-post-pipeli…

- src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml
- src/resources/skills/create-workflow/templates/code-audit.yaml
- src/resources/skills/create-workflow/templates/release-checklist.yaml
- src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts

* docs(S09): add slice plan

* test(S09/T01): Comprehensive e2e integration test proving the full work…

- src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts

* chore: remove .gsd/ artifacts from tracking (already in .gitignore)

* fix(skills): resolve broken cross-references in create-workflow workflow files

Paths in workflows/ referenced references/ as siblings, but they need
../references/ since they're resolved relative to the workflows/ directory.

* fix: resolve typecheck failures — .ts→.js imports, MapIterator.some(), LoadedGSDPreferences unwrap, constructor args

- Convert .ts import extensions to .js in source files to match codebase
  convention (tests keep .ts since tsconfig.extensions allows it)
- Use [...idCounts.values()].some() instead of MapIterator.some()
- Unwrap LoadedGSDPreferences.preferences for DispatchContext.prefs
- Pass runDir to CustomExecutionPolicy constructor in tests

* fix: add codeFilesChanged to mergeMilestoneToMain mock (synced with main)

* fix(tests): write DEFINITION.yaml in integration tests, fix error message assertion

Root cause: S06 (iterate) added DEFINITION.yaml reading to
resolveDispatch(), but S04's integration tests only wrote GRAPH.yaml.
The missing file threw ENOENT, swallowed by the blanket catch, causing
steps to stay 'pending' silently.

Fixes:
- custom-engine-loop-integration: write DEFINITION.yaml in all 5 tests
- custom-workflow-engine: verify test creates temp dir with definition
- dev-engine-wrapper: update error regex — resolver validates activeRunDir
  before engine ID, so 'Unknown engine' is never reached

* fix: address 13 audit findings from self-review of workflow engine PR

Critical:
- Fix verify-before-reconcile ordering — verify step output before
  marking complete in GRAPH.yaml, so failed verification triggers retry
- Fix GSD_ENGINE_BYPASS kill switch — check env var in autoLoop before
  entering custom engine block instead of throwing from resolveEngine
- Add shell-command injection guard with suspicious pattern detection

High:
- Add ReDoS timeout guard (5s) for iterate regex patterns
- Centralize DEFINITION.yaml parsing into readFrozenDefinition() with
  schema: "core" restriction, eliminating 3 independent parse+cast sites
- Persist activeEngineId/activeRunDir in paused-session.json and restore
  on resume so custom workflows survive /exit
- Clean up engine state on startAuto failure in workflow run handler

Medium:
- Coerce params values to strings in definition-loader (YAML numbers/bools)
- Add path traversal guard (resolve + startsWith) in context-injector
  and custom-verification content-heuristic
- Use function replacer in expandIteration to prevent $ escaping bugs

Low:
- Fix skill docs CLI syntax (remove --param prefix)
- Use resolveProjectRoot instead of process.cwd() in catalog completions
- Rename isHookUnit → skipArtifactVerification for clarity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 08:51:47 -06:00
Derek Pearson
6cfd1c385c fix(skills): address QA round 23
QA23-1: Resolve custom Gradle version-catalog accessor names by
matching settings.gradle(.kts) create(name) declarations to catalog
filenames by basename, so ./gradle/foo.versions.toml and similar valid
path spellings are recognized.

QA23-2: Exclude Poetry group dependencies from FastAPI framework
classification to avoid dev/test-only FastAPI deps implying application
usage.

Add regression tests for:
- settings-defined catalog accessors that differ from TOML basename
- Poetry group FastAPI false positives
2026-03-22 09:07:32 -04:00
Derek Pearson
ea765166b1 fix(skills): address QA round 22
QA22-1: Support deeper pip-tools layouts under requirements/**
(e.g. requirements/dev/base.in) for Python/FastAPI detection and
requirements.txt marker normalization.

QA22-2: Resolve Gradle version-catalog accessor names from
settings.gradle(.kts) create(name) { from(files(...versions.toml)) }
blocks instead of assuming the accessor must equal the TOML basename.

Also treat settings.gradle(.kts) like other Gradle files for comment
stripping during catalog parsing.
2026-03-22 09:00:34 -04:00
Derek Pearson
aab9b0cb33 fix(skills): address QA round 21
QA21-1: Recognize pip-tools style requirement manifests, including
requirements.in, requirements-dev.in, and files under requirements/*.in
or requirements/*.txt, for Python/FastAPI detection and nested marker
normalization.

QA21-2: Generalize Spring Boot version-catalog detection beyond the
default libs accessor by supporting any *.versions.toml catalog name and
matching its corresponding accessor in build.gradle(.kts).

Also fix the root-level requirements/base.in path matcher and add
regression tests for custom catalog accessors and pip-tools layouts.
2026-03-22 08:56:20 -04:00
Derek Pearson
c77d35e9f7 fix(skills): address QA round 20
QA20-1: Make Spring Boot bundle detection order-independent by first
collecting library aliases across version catalogs and then resolving
bundle aliases against that complete set.

QA20-2: Recognize common split Python requirements layouts
(requirements/base.txt, requirements-dev.txt, etc.) as requirements
sources for both Python/FastAPI detection and nested marker
normalization.

Also repair the detector helper block after the prior patch splice and
keep the full regression suite green.
2026-03-22 08:51:13 -04:00
Matt Haynes
28e3c2e72c fix: prevent SIGTSTP crash on Windows (#2018) 2026-03-22 06:47:07 -06:00
Derek Pearson
f860fe0a91 fix(skills): address QA round 19
QA19-1: In pyproject dependency parsing, treat Poetry/table-form keys
as dependency names and only scan quoted requirement specs on
[project] dependencies / optional-dependency array lines. Prevents
extras like extras = ["fastapi"] from emitting dep:fastapi.

QA19-2: Support legacy Gradle Spring Boot declaration styles via
apply plugin: 'org.springframework.boot' and apply(plugin = ...).

QA19-3: Scope Maven Spring Boot detection to org.springframework.boot
groupId instead of any artifactId that happens to start with
spring-boot.

Add regression tests for:
- Poetry dependency table extras mentioning fastapi
- legacy apply plugin Spring Boot detection
- Maven artifactId-only spring-boot false positive
2026-03-22 08:46:08 -04:00
Derek Pearson
d8443b89e5 fix(skills): address QA round 18
QA18-1: Replace token-level FastAPI matching with package-name-aware
parsing for requirements.txt and pyproject dependency sections so extras
like my-sdk[fastapi] and unrelated fastapi tokens do not emit
dep:fastapi.

QA18-2: Scope direct Spring Boot detection to actual plugin/dependency
declarations instead of arbitrary spring-boot text, and fix Kotlin DSL
plugin syntax matching (id("org.springframework.boot")).

Add regression tests for:
- dependency extras mentioning fastapi
- build metadata mentioning spring-boot
- Kotlin DSL Spring Boot plugin detection
2026-03-22 08:41:42 -04:00
Derek Pearson
414a1433ba fix(skills): address QA round 17
QA17-1: Support multiline arrays inside [project.optional-dependencies]
so FastAPI declared in multiline optional dependency groups is detected
correctly.

QA17-2: Extend Spring Boot version-catalog detection to bundle aliases
(libs.bundles.*) by resolving bundles back to library aliases that map
to org.springframework.boot artifacts.

Add regression tests for:
- multiline optional FastAPI dependencies
- Spring Boot bundle alias detection
2026-03-22 08:36:40 -04:00
Derek Pearson
30d799e1b9 fix(skills): address QA round 16
QA16-1: In pyproject.toml, treat [project.optional-dependencies]
keys as extra names rather than dependency names by scanning only the
right-hand-side values. Prevents extras named 'fastapi' from emitting
dep:fastapi.

QA16-2: Support FastAPI direct-reference requirements using the @
operator (e.g. fastapi @ https://...).

QA16-3: Extend Spring Boot version-catalog detection to library aliases
(e.g. implementation(libs.backend.web) + module =
org.springframework.boot:spring-boot-starter-web), while keeping alias
correlation strict.

QA16-4: Use a neutral 'java/kotlin' language hint for nested Gradle
Spring Boot services, even when they use build.gradle.kts, to avoid
mislabeling Java codebases as Kotlin.

Add regression tests for optional-dependency extras, direct-reference
FastAPI, Spring Boot library aliases, and nested Gradle language hints.
2026-03-22 08:28:56 -04:00
Derek Pearson
da6f246891 fix(skills): address QA round 15
QA15-1: Extend exact FastAPI dependency detection to support common
PEP 508 specifiers like ~= and !=.

QA15-2: Scope pyproject.toml FastAPI detection to actual dependency
sections ([project] dependencies array, [project.optional-dependencies],
[tool.poetry.dependencies], and [tool.poetry.group.*.dependencies]) so
metadata-only mentions do not emit dep:fastapi.

QA15-3: Remove spring.boot alias-name matching from direct Spring Boot
detection. Direct matches now require org.springframework.boot or
spring-boot(-starter) strings; alias-based detection only succeeds via
alias usage + version-catalog id correlation.

QA15-4: When a nested Gradle Spring Boot service emits dep:spring-boot
and no language was otherwise detected, set primaryLanguage to
java/kotlin so onboarding no longer reports 'unknown project'.

Add regression tests for:
- FastAPI ~= operator
- pyproject metadata-only fastapi mention
- spring-like alias names without Spring Boot id
- nested Spring Boot language hint
2026-03-22 08:25:07 -04:00
Derek Pearson
803913b13d fix(skills): address QA round 14
QA14-1: Strip comments in libs.versions.toml indirectly by moving Spring
Boot version-catalog detection to alias correlation rather than raw
presence matching.

QA14-2: Require actual alias usage in build.gradle(.kts) plus matching
org.springframework.boot alias definition in libs.versions.toml before
emitting dep:spring-boot.

QA14-3: Tighten FastAPI detection to an exact dependency token with
valid package delimiters so fastapi-users / fastapi-cli alone do not
emit dep:fastapi.

Add stronger regression tests for:
- arbitrary Spring Boot alias correlation
- commented Spring Boot aliases
- unused Spring Boot aliases
- fastapi-* packages without fastapi itself
2026-03-22 08:21:03 -04:00
Derek Pearson
73bd5d9331 fix(skills): address QA round 13
QA13-1: Strip inline trailing comments when scanning dependency/build
files so comment-only mentions of fastapi or spring-boot no longer emit
synthetic framework markers.

QA13-2: Detect Spring Boot in Gradle version-catalog alias setups by
including libs.versions.toml in the scan and matching spring.boot /
spring-boot alias patterns as well as org.springframework.boot.

Add regression tests for:
- FastAPI inline comments
- Android inline spring-boot comments
- Spring Boot version-catalog alias detection
2026-03-22 08:16:20 -04:00
Derek Pearson
c297fe2e34 fix(skills): address QA round 12
QA12-1: Replace generic Gradle/POM matching for Java & Spring Boot
with a real framework marker () detected by scanning
pom.xml and Gradle files for Spring Boot plugins/dependencies. This
restores nested Gradle service detection without reintroducing Android
false positives.

QA12-2: Prevent standard Android projects (root build.gradle +
app/build.gradle) from matching the Spring Boot pack. Spring Boot now
requires the synthetic dependency marker, not generic build files.

QA12-3: Harden FastAPI detection:
- strip comments before matching
- scan each dependency file independently
- continue on per-file read errors instead of failing the whole scan

Also add regression tests for comment-only FastAPI mentions, nested
Spring Boot Gradle services, Android non-Spring Gradle projects, and
Spring Boot pack matching via dep:spring-boot.
2026-03-22 08:13:09 -04:00
Derek Pearson
18508c1129 fix(skills): address QA round 11
QA11-1: Expand recursive-scan ignore set to skip common heavyweight
folders (.venv, venv, Pods, bin, obj, .gradle, DerivedData, out)
so the bounded scan is far less likely to exhaust its budget before
reaching relevant nested project files.

QA11-2: Remove the arbitrary 10-file cap from FastAPI dependency reads.
All discovered requirements.txt / pyproject.toml files within the bounded
scan are now checked, eliminating traversal-order dependence in
multi-service repos.

QA11-3: Normalize safe nested project markers from the recursive scan
back into PROJECT_FILES markers (e.g. nested next.config.ts, manage.py,
requirements.txt, prisma/schema.prisma, app/build.gradle) while keeping
noisy root-only markers like package.json and generic build.gradle
root-only. Add regression tests for these nested layouts and Android
root-only exclusion behavior.
2026-03-22 08:08:41 -04:00
Derek Pearson
bc63161593 fix(skills): address QA round 10
QA10-1: Replace root-only synthetic marker detection with a bounded
recursive project scan (max 2000 files, depth 6, ignoring heavy dirs)
so nested .csproj/.fsproj/.sln, SQL, SQLite, Vue, and FastAPI service
layouts are detected correctly.

QA10-2: Split .NET synthetic markers by actual file type:
- *.csproj => primaryLanguage csharp
- *.fsproj => primaryLanguage fsharp
- *.sln => primaryLanguage dotnet

Update .NET Backend Patterns to match generic .NET markers
(*.csproj, *.fsproj, *.sln) while keeping .NET & C# limited to C#.

QA10-3: Add invariant tests validating:
- every SKILL_CATALOG matchFiles entry is backed by detection
- every GREENFIELD_STACKS pack label resolves to SKILL_CATALOG

Also add regression tests for nested SQL, nested .csproj, F#,
nested .vue, and nested FastAPI service requirements detection.
2026-03-22 08:01:31 -04:00
Derek Pearson
d7d5d0e3ad fix(skills): address QA round 8
QA8-1: Add case-insensitivity test for FastAPI detection using PyPI
canonical name 'FastAPI' (mixed case) in pyproject.toml.

QA8-2: False positive — comment matching is acceptable tradeoff;
mentions of 'fastapi' in requirements comments almost always correlate
with actual FastAPI usage or intent.

QA8-3: Empty catch block is trivially correct; skipping test for it.
2026-03-22 07:52:11 -04:00
Derek Pearson
183b54d75e fix(skills): detect FastAPI via dependency scanning
Replace the lazy 'no brownfield detection' approach with proper
dependency-based detection. Scan requirements.txt and pyproject.toml
for the 'fastapi' package name (case-insensitive word-boundary match)
using the existing readBounded() utility (64KB cap).

Adds 'dep:fastapi' synthetic marker to detectedFiles when found,
which the FastAPI skill pack matches via matchFiles: ['dep:fastapi'].
This ensures only actual FastAPI projects get the pack recommended,
not all Python projects.

Tests: 3 new detection tests (requirements.txt, pyproject.toml,
negative Django case) + 1 new catalog test (dep:fastapi matching).
Total: 50 detection + 17 catalog + 5 activation + 12 smoke = 84.
2026-03-22 07:39:16 -04:00
Derek Pearson
064c9ce421 fix(skills): address QA round 6
QA6-1: Add 16 matchPacksForProject unit tests covering language match,
file match, Xcode platform match, matchAlways, and isolation checks
(FastAPI not in generic Python, Spring Boot not via language alone,
Unity/Godot don't cross-contaminate).

QA6-2: Remove FastAPI from brownfield auto-detection entirely — no
matchFiles or matchLanguages. Available via greenfield stack selection
or manual install only, since no FastAPI-specific file marker exists
on disk.

QA6-3: Remove matchLanguages from Java & Spring Boot pack so it only
triggers via matchFiles (pom.xml, build.gradle*). Prevents Android
projects from getting Spring Boot recommended via language match.

QA6-4: False positive — F# gets 'csharp' label cosmetically but the
.NET packs are correct for F# developers.
2026-03-22 07:34:41 -04:00
Derek Pearson
84657d0398 fix(skills): address QA round 5
QA5-1: Remove matchLanguages from FastAPI pack so it only triggers via
file-based detection (matchFiles), not for all Python projects. Aligns
with Django precedent of framework-specific file matching.

QA5-2: Add requirements.txt to pytest verification command check so
requirements.txt-only Python projects get pytest suggested.

QA5-3: Add FastAPI greenfield stack entry (packs: FastAPI + Python +
Python Advanced) for parity with Django.

QA5-4: False positive — Vue src/ scanning is non-recursive by design;
all standard Vue scaffolds place App.vue directly in src/.

QA5-5: Add 11 new detection tests covering Vue .vue scanning, Vue CLI
config, requirements.txt Python detection, Android app/build.gradle,
Unity, Godot, Airflow, Kubernetes Helm, Blockchain Hardhat, CI/CD
.github/workflows, and Tailwind config. Test count: 36 → 47.
2026-03-22 07:26:32 -04:00
Derek Pearson
90b13021f8 fix(skills): address QA round 4
QA4-1: Split Game Development into separate Unity and Godot packs to
avoid cross-contamination between engines.

QA4-2: Add requirements.txt to Python base pack matchFiles so Python
Advanced doesn't trigger without the base pack.

QA4-3: Add Prisma to fullstack-js greenfield stack to differentiate
it from react-web.

QA4-4: Remove Spring Boot from Android greenfield stack — server-side
Java framework is irrelevant for Android development.

QA4-5: Extract FastAPI into its own pack (consistent with Django being
separate) instead of bundling in Python Advanced.

QA4-6: Add airflow.cfg to PROJECT_FILES and Data Engineering matchFiles
so Airflow-only projects also trigger data engineering skills.

QA4-7: Add Tailwind CSS to react-web, fullstack-js, nextjs, and
svelte greenfield stacks.

QA4-8: Add Unity and Godot as separate greenfield stack options.

QA4-9: Fix Vue.js detection for non-Nuxt projects by adding .vue
file extension scanning (scans src/ for *.vue files), vue.config.*
to PROJECT_FILES, and *.vue synthetic marker to Vue.js pack matchFiles.

QA4-10: Add app/build.gradle and app/build.gradle.kts to LANGUAGE_MAP
for Android project language detection.
2026-03-22 07:21:04 -04:00
Derek Pearson
0067ada24e feat(skills): add 19 wshobson/agents packs with 40 curated skills
Add comprehensive coverage from wshobson/agents (654K total installs,
31.9K GitHub stars, all security audits PASS):

Complement existing packs:
- TypeScript & JS Development (4 skills, 41K combined installs)
- React State & Patterns (2 skills, 8.1K)
- React Native Architecture (2 skills, 10K)
- Next.js App Router Patterns (1 skill, 9.5K)
- Angular Migration (1 skill, 3.2K)
- Python Advanced (5 skills, 40K — perf, testing, async, uv, FastAPI)
- Rust Async Patterns (1 skill, 5.9K)
- Go Concurrency Patterns (1 skill, 3.4K)
- .NET Backend Patterns (1 skill, 6K)
- PostgreSQL Design (1 skill, 8.8K)

New domain packs:
- Tailwind CSS (1 skill, 22.8K)
- Android (1 skill, 7K)
- Kubernetes (4 skills — manifests, Helm, GitOps, security)
- CI/CD Automation (3 skills — pipelines, GitHub Actions, secrets)
- Blockchain & Web3 (3 skills — Solidity, DeFi, testing)
- Data Engineering (4 skills — dbt, Airflow, Spark, quality)
- Game Development (2 skills — Unity ECS, Godot GDScript)

Essential (matchAlways):
- Code Review & Quality (2 skills, 15K)
- Git Advanced Workflows (1 skill, 4.6K)

New detection triggers: tailwind.config.*, app/build.gradle*,
Chart.yaml, kustomization.yaml, .github/workflows, hardhat.config.*,
foundry.toml, dbt_project.yml, ProjectSettings/ProjectVersion.txt,
project.godot.

Updated GREENFIELD_STACKS with new complement packs and 4 new
greenfield options (Android, Kubernetes, Blockchain, Data Engineering).
2026-03-22 07:09:46 -04:00
Derek Pearson
3a35eae883 feat(skills): add 11 new skill packs covering major frameworks and languages
New skill packs with auto-detection:
- Java & Spring Boot (github/awesome-copilot, 9.1K installs)
- .NET & C# (github/awesome-copilot, 8.1K installs) — scans for *.csproj/*.sln
- Flutter (flutter/skills, official, 54.6K total)
- Angular (analogjs/angular-skills, official, 33.5K total)
- Vue.js (vuejs-ai/skills, official, 30.7K total) — triggers on nuxt.config.*
- Svelte (sveltejs/ai-tools, official, 3.1K total)
- Next.js (vercel-labs/vercel-plugin, official) — triggers on next.config.*
- Docker (github/awesome-copilot, 8.3K installs)
- Terraform (hashicorp/agent-skills, official, 9.4K total)
- Django (vintasoftware/django-ai-plugins, 2.2K total)
- PHP & Laravel (jeffallan/claude-skills, 10.1K total)

Detection additions:
- PROJECT_FILES: angular.json, next.config.*, nuxt.config.*, svelte.config.*,
  Dockerfile, docker-compose.*, main.tf, manage.py, requirements.txt
- Extension scanning: *.csproj/*.sln/*.fsproj for .NET detection
- LANGUAGE_MAP: manage.py and requirements.txt → python
- GREENFIELD_STACKS: Angular, Vue, Svelte, Next.js, Flutter, Java, .NET,
  PHP, Django entries
- 8 new detection tests (36 total, up from 28)
2026-03-22 06:52:55 -04:00
Derek Pearson
a30b125020 feat(skills): add SQLite/SQL detection, SQL optimization pack, and Redis pack
- Scan project root for *.sqlite/*.sqlite3/*.db files → synthetic *.sqlite marker
- Scan for *.sql files (migrations, schemas, seeds) → synthetic *.sql marker
- Add SQL Optimization & Review pack (github/awesome-copilot): sql-optimization
  (7.8K installs) and sql-code-review (7.6K installs) — covers SQL injection
  prevention, parameterized queries, index strategy, anti-patterns. Triggers on
  *.sql, *.sqlite, or any database ORM config (Prisma, Supabase, Drizzle).
- Add Redis pack (redis/agent-skills): redis-development. Triggers on redis.conf.
- Add redis.conf to PROJECT_FILES.
- 4 new detection tests for SQLite/SQL file scanning.
2026-03-22 06:40:53 -04:00
Derek Pearson
e48538b70d feat(skills): add Prisma and Supabase/Postgres database packs
- Prisma: prisma-database-setup, prisma-client-api, prisma-cli from
  prisma/skills (10.7K installs). Auto-detects via prisma/schema.prisma.
- Supabase & Postgres: supabase-postgres-best-practices from
  supabase/agent-skills (44.3K installs). Auto-detects via
  supabase/config.toml. Covers Postgres patterns (indexing, RLS,
  migrations) through Supabase lens.
- Add drizzle.config.ts/js to PROJECT_FILES for future ORM detection.
2026-03-22 06:29:50 -04:00
Derek Pearson
a4de1d30c5 fix(skills): address QA round 3
- Fix Windows fd leak: close markerFd before unlinkSync in catch block
- Increase pbxproj read limit from 256KB to 1MB (SDKROOT appears after
  file references/build phases in large projects)
- Fix matchPacksForProject docstring: returns catalog order, not sorted
- Add legacy dir to skill telemetry (captureAvailableSkills, detectStaleSkills)
  so pre-migration skills appear in health/telemetry reports
2026-03-22 06:22:23 -04:00
Derek Pearson
b442a55bff fix(skills): address QA round 2
- Add azure-pipelines.yml to PROJECT_FILES and Azure pack matchFiles
- Add serverless.yaml variant to PROJECT_FILES and AWS pack matchFiles
- Fix marker fd leak in migrateSkillsToEcosystemDir: wrap mkdirSync
  inside try/finally, remove marker on failure so migration retries
2026-03-22 06:13:50 -04:00
Derek Pearson
aa0822466e fix(skills): defer greenfield skill selection to post-design phase
Greenfield projects (empty directories) no longer ask users to pick a tech
stack during init. Non-technical users may not know their architecture yet.
Instead, only essential packs (find-skills, skill-creator, agent-browser,
document handling) are installed. Stack-specific skills auto-detect later
via brownfield detection once the LLM creates project files.

GREENFIELD_STACKS retained as a reference for programmatic use by the LLM
and the /gsd skills command.
2026-03-22 06:11:44 -04:00
Derek Pearson
ddeb352143 feat(skills): add cloud platform packs (Firebase, Azure, AWS) and improve detection
- Add Firebase, Azure, and AWS skill packs to curated catalog
- Add cloud config files (firebase.json, cdk.json, samconfig.toml, serverless.yml)
  and React Native markers (metro.config.js/ts, react-native.config.js) to detection
- Fix React Native detection to use matchFiles instead of broad language match
- Add matchAlways flag for essential packs so they are offered to all projects
- Add Firebase/AWS/Azure to greenfield tech stack wizard
- Improve Xcode detection: scan ios/macos/app subdirs, use bounded fd read,
  set primaryLanguage=swift when xcodeproj found, handle SDKROOT=auto via
  SUPPORTED_PLATFORMS fallback
- Fix migration: handle symlinked skill dirs, use atomic wx flag for race safety
2026-03-22 06:03:42 -04:00
Derek Pearson
a0ea8c92bb feat(skills): curate catalog — add top ecosystem skills, drop low-quality bundled ones
Catalog changes:
- Added: find-skills (#1 on skills.sh, 657K installs), shadcn/ui (#5,
  130K), skill-creator (#26, 98K), agent-browser (#23, 120K)
- Removed from React pack: web-design-guidelines (thin wrapper that
  just fetches an external URL; redundant with the Vercel ecosystem
  version and userinterface-wiki)
- The old bundled skills (18 total, 11 web-frontend-focused) are no
  longer force-synced. The catalog now points to the better ecosystem
  versions from Vercel, Anthropic, and shadcn.

Reasoning: The original bundled skills were heavily web-frontend biased
with significant overlap (3 UI polish skills, 4 web audit skills). The
catalog should surface the highest-quality ecosystem skills rather than
force-installing duplicative bundled ones.
2026-03-22 05:47:16 -04:00
Derek Pearson
6889f6666f docs(skills): update all references from ~/.gsd/agent/skills/ to ~/.agents/skills/
Updates docs/skills.md with:
- New skill directories section (global + project-local)
- Migration note for existing users
- Installation via skills.sh CLI
- Curated onboarding catalog with all available packs
- Maintainer guide for adding/editing catalog entries

Also updates:
- docs/configuration.md: skill lookup paths
- docs/what-is-pi/09-the-customization-stack.md: placement paths
- docs/context-and-hooks/07-the-system-prompt-anatomy.md: example path
- src/resource-loader.ts: JSDoc comment (skills no longer synced)
2026-03-22 05:35:14 -04:00
Derek Pearson
e706876114 fix(skills): add migration from ~/.gsd/agent/skills/ to ~/.agents/skills/
Existing GSD users have skills in ~/.gsd/agent/skills/ that would
silently vanish after the directory switch.  This adds:

1. One-time migration in initResources() — copies skill directories
   from ~/.gsd/agent/skills/ to ~/.agents/skills/ (collision-safe,
   writes .migrated-to-agents marker so it runs at most once).

2. Legacy fallback reads in loadSkills() and getSkillSearchDirs() —
   the old directory is scanned as a low-priority fallback so skills
   work immediately, even before the migration runs on next restart.

The old directory is NOT deleted — users can safely downgrade to a
pre-migration GSD version without losing skills.
2026-03-22 05:30:29 -04:00
Derek Pearson
4020828260 feat(skills): parse SDKROOT from pbxproj for platform-aware iOS skill matching
Replace boolean hasXcodeProject with xcodePlatforms array that reads
SDKROOT values from *.xcodeproj/project.pbxproj files. iOS skill packs
now only match when SDKROOT=iphoneos, so macOS / watchOS / visionOS /
tvOS Xcode projects won't get iOS-specific skills.

Also splits the monolithic "Swift / iOS" pack into 8 granular bundles
matching dpearson2699/swift-ios-skills plugin structure:
  - SwiftUI + Swift Core (any Swift project)
  - iOS App Frameworks, Data Frameworks, AI & ML, Engineering,
    Hardware, Platform (iphoneos projects only)

Adds batched installation to minimize npx invocations when multiple
packs share the same repo.
2026-03-22 05:19:05 -04:00
Derek Pearson
aaed0ab796 feat(skills): use ~/.agents/skills/ as primary skills directory with curated catalog
Stop force-syncing bundled skills to ~/.gsd/agent/skills/ on every launch.
Instead, use ~/.agents/skills/ (the industry-standard skills.sh directory)
as the primary global skills location, and .agents/skills/ for project-local
skills.

Changes:
- loadSkills() now scans ~/.agents/skills/ (global) and .agents/skills/ (project)
  instead of ~/.gsd/agent/skills/ and .gsd/skills/
- initResources() no longer syncs src/resources/skills/ → ~/.gsd/agent/skills/
- skill-discovery, skill-telemetry, skill-health, preferences-skills all updated
  to use the ecosystem directory
- New skill-catalog.ts: curated skill packs mapped to tech stacks, with
  brownfield auto-detection and greenfield tech stack selection
- Init wizard gains a skill installation step that presents relevant packs
  and installs via `npx skills add`
- Export ECOSYSTEM_SKILLS_DIR and ECOSYSTEM_PROJECT_SKILLS_DIR from pi-coding-agent

Fixes #2004
2026-03-22 05:03:36 -04:00
Derek Pearson
3c9c6817dc Merge branch 'main' of https://github.com/gsd-build/gsd-2 2026-03-22 04:22:01 -04:00
Tom Boucher
2f73814552 fix(doctor): compare lockfile mtime against install marker, not directory mtime (#1974)
The stale dependency check compared package-lock.json mtime against the
node_modules directory mtime. Directory mtime only updates when entries
are added or removed — not when files inside are updated. This caused a
permanent false-positive warning after `npm install` when dependencies
were already up to date, because npm rewrites the lockfile (advancing
its mtime) without adding/removing directory entries.

Compare against package manager marker files instead:
- npm: node_modules/.package-lock.json
- yarn: node_modules/.yarn-integrity
- pnpm: node_modules/.modules.yaml

Falls back to directory mtime when no marker file exists.

Fixes #1974

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 00:32:25 -04:00
Tom Boucher
b672f44014 fix(doctor): chdir out of orphaned worktree before removal (#1946)
The orphaned_auto_worktree fix skipped removal when process.cwd() was
inside the worktree, creating a deadlock where the doctor repeatedly
detected the orphan but never cleaned it up. Now chdir to basePath
first, matching the existing pattern in removeWorktree().

Fixes #1946

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 23:42:03 -04:00
Tom Boucher
2662c41bf6 fix(roadmap): recognize '## Slice Roadmap' header in extractSlicesSection
The regex in extractSlicesSection matched Slices, Slice Overview, Slice Table,
Slice Summary, and Slice Status but not Slice Roadmap. When a roadmap used the
'## Slice Roadmap' heading, the section extractor returned empty, causing the
parser to fall through to prose headers which lack checkbox state -- marking all
slices as incomplete and trapping auto-mode in a dispatch loop.

Add 'Roadmap' to the alternation and a regression test that verifies checkbox
slices under the '## Slice Roadmap' heading are parsed with correct done state.

Fixes #1940

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 23:30:15 -04:00
Iouri Goussev
642c0f5a9e test: fix Assertion Roulette, Eager Test, and contract test regressions (#1938)
* test: add assertion messages to fix Assertion Roulette in GSD tests

Add descriptive messages to multi-assertion tests where a bare failure
output ("expected true, got false") wouldn't identify which assertion
broke. Affected tests: auto-secrets-gate, search-tavily, search-provider-
command, tavily-helpers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: fix Eager Test smell in captures and worktree-manager tests

- Split captures: loadPendingCaptures test — extracted loadAllCaptures
  assertion into its own focused test
- Refactor worktree-manager: replace monolithic main() script with 11
  isolated test() calls, each with its own repo setup via helpers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: add assertion messages to remaining test files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: fix contract test gate, dynamic roots, and shared fetch helpers

- Fix reject-notice sub-test gated on outcome.kind (actual) instead of
  expectedKind (map value) in web-command-parity-contract.test.ts
- Restore dynamic loop over registered non-gsd passthrough roots with
  an explicit count assertion so new registrations fail loudly
- Extract normalizeHeaders/parseJsonBody to src/tests/fetch-test-helpers.ts
  and import in both search-tavily and llm-context-tavily tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 21:24:15 -06:00
djimenez18
32bbf07d0b Fix command for browser-based web interface (#1932)
Corrected the command for running GSD in the browser from 'pi --web' to 'gsd --web'.
2026-03-21 21:23:45 -06:00
Lex Christopherson
61e473b32c fix: add missing codeFilesChanged to journal integration test mock
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 21:12:38 -06:00
TÂCHES
d40ed851a2 fix(repo-identity): use native realpath on Windows to resolve 8.3 short paths (#1960)
Use realpathSync.native() on Windows in canonicalizeExistingPath to resolve
8.3 short names (RUNNER~1 → runneradmin). Fixes isInheritedRepo path
comparison failures on Windows CI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 21:08:58 -06:00
Tom Boucher
09f3a5f970 fix(doctor): gate roadmap checkbox on summary existing on disk, not issue detection (#1915)
The roadmap-done condition checked whether the missing-summary issue was
detected in the issues array, but at fixLevel="task" the summary is
detected and never fixed (deferred via COMPLETION_TRANSITION_CODES).
This caused the roadmap checkbox to be marked without the summary on
disk, making deriveState() skip the summarizing phase and hard-stop at
validating-milestone.

Replace the issues.some() fallback with an existsSync re-check so the
roadmap is only marked when the summary actually exists — either
pre-existing or created earlier in the same doctor run.

Fixes #1910

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 21:06:53 -06:00
Tom Boucher
53d7350e0d fix: warn when milestone merge contains only metadata and no code (#1906) (#1927)
mergeMilestoneToMain now detects when the squash-merge commit contains
only .gsd/ metadata files and no actual code changes. The worktree
resolver surfaces a clear warning so users know the milestone summary
may describe planned work that was never implemented.

The complete-milestone prompt now requires the LLM to verify code
changes exist on the branch before declaring verification passed.

Fixes #1906

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 21:05:56 -06:00
TÂCHES
79e49aa413 fix(worktree): resolve 8.3 short paths and use shell mode for .bat hooks on Windows (#1956)
Resolve Windows 8.3 short paths (RUNNER~1 → runneradmin) via realpathSync.native()
and use shell mode for .bat/.cmd files in worktree post-create hooks. Fixes
pre-existing windows-portability CI failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 20:52:30 -06:00
Derek Pearson
c81e982c8c Merge branch 'main' of https://github.com/gsd-build/gsd-2 2026-03-21 22:16:41 -04:00