Files
msd-core/sdk
Tom Boucher 037a49c9c2 test(3593): CLI negative-matrix harness + config family + universal sweep (#3627)
Adds the shared adversarial-input harness described in TEST-EXAMPLES.md
§"CLI Negative Matrix" and applies it across two layers:

  1. tests/helpers/cli-negative.cjs — runCli() wraps spawnSync of
     get-shit-done/bin/gsd-tools.cjs, prepends --json-errors by default,
     and returns a typed IR { status, ok, reason, message,
     hasStackTrace, ... } so adversarial-case tests assert on
     reason codes — never on stderr prose.

  2. tests/feat-3593-cli-negative-config.test.cjs — full 12-category
     matrix for the config command family (the highest-risk read/write
     surface): missing/empty/whitespace args, duplicate --cwd,
     unknown subcommand, value-looks-like-a-flag, corrupt config.json,
     50KB key, Unicode/emoji keys and values, and 9 distinct shell-
     metacharacter payloads asserted as NOT-executed via per-test
     sentinel-file probes.

  3. tests/feat-3593-cli-negative-universal.test.cjs — narrower
     cross-family sweep (phase, roadmap, state, config, workstream,
     init, validate). Pins the three universal invariants every
     family must satisfy: bare invocation does not crash with a V8
     stack trace, unknown subcommand emits a typed reason, and shell
     payloads as argv values are not executed.

  4. tests/feat-3593-cli-negative-harness.test.cjs — meta-test that
     pins the harness IR contract so a future regression in the
     parser (stack-trace detection, JSON shape extraction, hostile
     stderr handling) surfaces before it cascades through every
     matrix file.

Bug fix surfaced by the new tests:

  get-shit-done/bin/lib/config.cjs cmdConfigSet — invoking
  `config-set <key>` with no value silently returned exit 0 and
  emitted { updated: true } even though the value parameter was
  undefined. JSON.stringify dropped the key during the write or
  persisted a corrupt entry. Now rejected with typed ERROR_REASON.USAGE
  before any write. Matching guard added to SDK configSet for parity.

Harness coverage delivered: 58 new tests (9 meta + 26 config + 23
universal sweep). Pre-existing config suites (101 tests) all pass.
lint-no-source-grep clean.

Refs #3593

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 23:57:38 -04:00
..

@gsd-build/sdk

TypeScript SDK for Get Shit Done: deterministic query/mutation handlers, plan execution, and event-stream telemetry so agents focus on judgment, not shell plumbing.

Install

npm install @gsd-build/sdk

Quickstart — programmatic

import { GSD, createRegistry } from '@gsd-build/sdk';

const gsd = new GSD({ projectDir: process.cwd(), sessionId: 'my-run' });
const tools = gsd.createTools();

const registry = createRegistry(gsd.eventStream, 'my-run');
const { data } = await registry.dispatch('state.json', [], process.cwd());

Quickstart — CLI

From a project that depends on this package, invoke the CLI with Node (recommended in CI and local dev):

node ./node_modules/@gsd-build/sdk/dist/cli.js query state.json
node ./node_modules/@gsd-build/sdk/dist/cli.js query roadmap.analyze

If no native handler is registered for a command, the CLI can transparently shell out to get-shit-done/bin/gsd-tools.cjs (see stderr warning), unless GSD_QUERY_FALLBACK=off.

What ships

Area Entry
Query registry createRegistry() in src/query/index.ts — same handlers as gsd-sdk query
Tools bridge GSDTools — native dispatch with optional CJS subprocess fallback
Orchestrators PhaseRunner, InitRunner, GSD
CLI gsd-sdk — query, run, init, auto

Guides

  • Handler registry & contracts: src/query/QUERY-HANDLERS.md
  • Repository docs (when present): docs/ARCHITECTURE.md, docs/CLI-TOOLS.md at repo root

Environment

Variable Purpose
GSD_QUERY_FALLBACK off / never disables CLI fallback to gsd-tools.cjs for unknown commands
GSD_AGENTS_DIR Override directory scanned for installed GSD agents (~/.claude/agents by default)