showdar-skills 0.12.0 → 0.12.1

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 CHANGED
@@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.12.1]
10
+
11
+ ### Fixed
12
+
13
+ - Added read-only `showdar guard --mutation local-write --json` to block task writes on integration branches until task branch preparation, with an explicit repository-local direct-work opt-in.
14
+ - Updated native harness guidance and mutating skills to require automatic branch preparation and a passing guard before agent-controlled file writes; Cursor routing rules now apply automatically.
15
+ - Re-adding an existing Showdar-managed skill refreshes its packaged SKILL.md from the upgraded CLI only when its recorded hash matches; user-modified skill files are preserved and cause an explicit error.
16
+ - This is an agent/tool-instruction gate, not a cross-harness filesystem interceptor, and does not grant source/remote mutation authority.
17
+
18
+
9
19
  ## [0.12.0]
10
20
 
11
21
  ### Added
package/README.md CHANGED
@@ -47,6 +47,7 @@ printf '%s\n' 'Implement the approved underwriting form and add tests' | showdar
47
47
  showdar route --prompt "Explain insurance terminology"
48
48
  showdar git-start --dry-run --type feature --name "IDP-123 Add pricing form"
49
49
  showdar git-start --type feature --name "IDP-123 Add pricing form"
50
+ showdar guard --mutation local-write --json
50
51
  ```
51
52
 
52
53
  Prefer `--stdin` for arbitrary or multiline prompts. Supply stdin as literal data;
@@ -91,6 +92,18 @@ The four workflows remain native discoverable/installable skills; `route` does n
91
92
  introduce workflow selection. Profiles remain primitive-only: `full` contains all
92
93
  18 primitives, and the insurance profile remains unchanged.
93
94
 
95
+ Before the first local-write task source edit, the coding agent must run
96
+ `showdar guard --mutation local-write --json` and require `ok=true` and
97
+ `data.allowed=true`. When on develop/main/integration, it must execute
98
+ `showdar git-start` (not only suggest it), confirm the branch, and rerun guard.
99
+ This is an instruction-level agent preflight, **not an OS/filesystem hook**:
100
+ tools that ignore Showdar can still write files. Cursor's generated rule now
101
+ uses `alwaysApply: true` so the Git preflight isn't limited to manually
102
+ activated skill calls. Existing project guidance must be refreshed after the
103
+ package update (for example by running `showdar add git` with the new CLI).
104
+ Re-adding an installed skill refreshes its managed SKILL.md and guidance only
105
+ if the owned copy has not been locally modified; drift refuses to overwrite.
106
+
94
107
  Before the first local-write task source edit on develop/development/dev/main/master
95
108
  or the repository default/integration branch, prepare a task branch. Priority is
96
109
  repository instructions/documented convention, explicit current user instruction,
package/bin/showdar.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import path from 'node:path';
3
3
  import { parseArgs } from 'node:util';
4
4
  import { startTaskBranch, formatGitStart } from '../src/git-start.js';
5
+ import { guardMutation, formatMutationGuard } from '../src/git-guard.js';
5
6
  import { routeRequest, formatRoute } from '../src/runtime-route.js';
6
7
  import { homedir } from 'node:os';
7
8
  import { readFile } from 'node:fs/promises';
@@ -44,6 +45,10 @@ function printHelp(version, command = null) {
44
45
  console.log('Usage: showdar git-start --type <type> --name <task> [--base <branch>] [--dry-run] [--json]');
45
46
  return;
46
47
  }
48
+ if (command === 'guard') {
49
+ console.log('Usage: showdar guard --mutation <read-only|local-write> [--json]');
50
+ return;
51
+ }
47
52
  if (command === 'init') {
48
53
  console.log(`Showdar Skills ${version}\n\nUsage:\n showdar init ${scopeUsage} [--profile <name>] [--ai <universal|codex|opencode|cursor|claude|all>]\n\nDefaults: scope project, profile full, AI target universal.\nProject scope writes native skills, one native instruction surface, and project .showdar.json. Global scope writes verified user skill directories and ~/.showdar/global.json without instruction files. Codex and universal use .agents/skills in project scope and ~/.agents/skills in global scope; cursor uses .cursor/skills in project scope and ~/.cursor/skills in global scope; --ai all writes each shared destination once, generates OpenCode and Claude commands, and writes only the AGENTS.md block.\n\nProfiles: ${Object.keys(PROFILES).join(', ')}\nDeprecated aliases: ${Object.entries(PROFILE_ALIASES).map(([alias, target]) => `${alias} -> ${target}`).join(', ')}\nAI targets: ${AI_TARGETS.join(', ')}`);
49
54
  return;
@@ -56,7 +61,7 @@ function printHelp(version, command = null) {
56
61
  console.log(`Showdar Skills ${version}\n\nUsage:\n showdar add <skill> [--ai <universal|codex|opencode|cursor|claude>] [--scope <project|global>]\n\nExamples:\n showdar add debug\n showdar add showdar-security\n showdar add test --ai cursor\n showdar add review --scope global --ai claude\n\nDefault scope: project. Default AI target: universal, or the configured .showdar.json value when present.`);
57
62
  return;
58
63
  }
59
- console.log(`Showdar Skills ${version}\n\nUsage:\n showdar init ${scopeUsage} [--profile <name>] [--ai <universal|codex|opencode|cursor|claude|all>] [--pack <local-path>]\n showdar add <skill> [--ai <universal|codex|opencode|cursor|claude>] [--scope <project|global>]\n showdar route (--stdin | --prompt <text>) [--json]\n showdar git-start --type <type> --name <task> [--base <branch>] [--dry-run] [--json]\n showdar add-pack <local-path>\n showdar remove-pack <name>\n showdar add-workflow <local-path>\n showdar status ${scopeUsage}\n showdar doctor ${scopeUsage}\n showdar validate\n showdar list [--extensions]\n showdar remove ${scopeUsage}\n showdar create-pack <path> [--vendor <vendor>] [--description <text>] [--with-workflow <id>] [--with-profile <name>]\n showdar validate-pack <local-path> [--json]\n showdar inspect-pack <local-path> [--json] [--checkpoint <file>]\n showdar doctor ${scopeUsage} [--extensions] [--json]\n showdar update-pack <local-path> [--dry-run] [--json]\n showdar validate\n showdar list [--extensions] [--json]\n showdar remove ${scopeUsage}\n\nExtension packs accept local directories/workspace paths only; tarball, URL, Git, and registry sources are rejected.\n\nDefaults: scope project, profile full, AI target universal.\nProfiles: ${Object.keys(PROFILES).join(', ')}\nDeprecated aliases: ${Object.entries(PROFILE_ALIASES).map(([alias, target]) => `${alias} -> ${target}`).join(', ')}\nAI targets: ${AI_TARGETS.join(', ')}`);
64
+ console.log(`Showdar Skills ${version}\n\nUsage:\n showdar init ${scopeUsage} [--profile <name>] [--ai <universal|codex|opencode|cursor|claude|all>] [--pack <local-path>]\n showdar add <skill> [--ai <universal|codex|opencode|cursor|claude>] [--scope <project|global>]\n showdar route (--stdin | --prompt <text>) [--json]\n showdar git-start --type <type> --name <task> [--base <branch>] [--dry-run] [--json]\n showdar guard --mutation <read-only|local-write> [--json]\n showdar add-pack <local-path>\n showdar remove-pack <name>\n showdar add-workflow <local-path>\n showdar status ${scopeUsage}\n showdar doctor ${scopeUsage}\n showdar validate\n showdar list [--extensions]\n showdar remove ${scopeUsage}\n showdar create-pack <path> [--vendor <vendor>] [--description <text>] [--with-workflow <id>] [--with-profile <name>]\n showdar validate-pack <local-path> [--json]\n showdar inspect-pack <local-path> [--json] [--checkpoint <file>]\n showdar doctor ${scopeUsage} [--extensions] [--json]\n showdar update-pack <local-path> [--dry-run] [--json]\n showdar validate\n showdar list [--extensions] [--json]\n showdar remove ${scopeUsage}\n\nExtension packs accept local directories/workspace paths only; tarball, URL, Git, and registry sources are rejected.\n\nDefaults: scope project, profile full, AI target universal.\nProfiles: ${Object.keys(PROFILES).join(', ')}\nDeprecated aliases: ${Object.entries(PROFILE_ALIASES).map(([alias, target]) => `${alias} -> ${target}`).join(', ')}\nAI targets: ${AI_TARGETS.join(', ')}`);
60
65
  }
61
66
 
62
67
  async function main() {
@@ -70,10 +75,22 @@ async function main() {
70
75
  console.log(version);
71
76
  return;
72
77
  }
73
- if (!['route', 'git-start'].includes(command) && (args.includes('--help') || args.includes('-h'))) return printHelp(version, command);
78
+ if (!['route', 'git-start', 'guard'].includes(command) && (args.includes('--help') || args.includes('-h'))) return printHelp(version, command);
74
79
 
75
80
  const scope = ['init', 'status', 'doctor', 'remove', 'add'].includes(command) ? scopeAfter(args) : null;
76
81
 
82
+ if (command === 'guard') {
83
+ const { values } = parseArgs({ args: args.slice(1), options: { mutation: { type: 'string' }, json: { type: 'boolean' }, help: { type: 'boolean', short: 'h' } } });
84
+ if (values.help) return printHelp(version, command);
85
+ const data = guardMutation({ cwd: projectRoot, mutation: values.mutation });
86
+ const errors = data.allowed ? [] : [{ code: data.code, message: 'Task-owned source mutation is blocked until Git preflight passes.' }];
87
+ console.log(values.json
88
+ ? JSON.stringify({ schemaVersion: 1, command, ok: data.allowed, data, warnings: [], errors }, null, 2)
89
+ : formatMutationGuard(data));
90
+ if (!data.allowed) process.exitCode = 1;
91
+ return;
92
+ }
93
+
77
94
  if (command === 'git-start') {
78
95
  const { values } = parseArgs({ args: args.slice(1), options: { type: { type: 'string' }, name: { type: 'string' }, base: { type: 'string' }, 'dry-run': { type: 'boolean' }, json: { type: 'boolean' }, help: { type: 'boolean', short: 'h' } } });
79
96
  if (values.help) return printHelp(version, command);
@@ -377,7 +394,7 @@ async function main() {
377
394
 
378
395
  main().catch((error) => {
379
396
  const command = process.argv[2];
380
- if (['route', 'git-start'].includes(command) && process.argv.slice(3).includes('--json')) {
397
+ if (['route', 'git-start', 'guard'].includes(command) && process.argv.slice(3).includes('--json')) {
381
398
  console.log(JSON.stringify({ schemaVersion: 1, command, ok: false, data: null, warnings: [], errors: [{ code: 'INVALID_REQUEST', message: error.message }] }, null, 2));
382
399
  } else console.error(`showdar: ${error.message}`);
383
400
  process.exitCode = 1;
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "showdar-skills",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Production-grade software engineering lifecycle skills for coding agents.",
5
5
  "type": "module",
6
- "bin": { "showdar": "./bin/showdar.js" },
6
+ "bin": {
7
+ "showdar": "./bin/showdar.js"
8
+ },
7
9
  "scripts": {
8
10
  "test": "node --test",
9
11
  "validate": "node bin/showdar.js validate",
@@ -16,9 +18,38 @@
16
18
  "smoke": "node scripts/package-smoke.mjs",
17
19
  "release:check": "node scripts/check-release-version.mjs"
18
20
  },
19
- "engines": { "node": ">=20" },
20
- "files": ["bin", "src", "config", "skills", "commands", "router", "bundles", "profiles", "engine", "README.md", "LICENSE", "CHANGELOG.md", "MIGRATION.md"],
21
- "keywords": ["agent-skills", "coding-agents", "codex", "opencode", "claude-code", "software-engineering", "developer-tools", "requirements", "qa", "security", "devops", "workflow"],
21
+ "engines": {
22
+ "node": ">=20"
23
+ },
24
+ "files": [
25
+ "bin",
26
+ "src",
27
+ "config",
28
+ "skills",
29
+ "commands",
30
+ "router",
31
+ "bundles",
32
+ "profiles",
33
+ "engine",
34
+ "README.md",
35
+ "LICENSE",
36
+ "CHANGELOG.md",
37
+ "MIGRATION.md"
38
+ ],
39
+ "keywords": [
40
+ "agent-skills",
41
+ "coding-agents",
42
+ "codex",
43
+ "opencode",
44
+ "claude-code",
45
+ "software-engineering",
46
+ "developer-tools",
47
+ "requirements",
48
+ "qa",
49
+ "security",
50
+ "devops",
51
+ "workflow"
52
+ ],
22
53
  "license": "MIT",
23
54
  "repository": {
24
55
  "type": "git",
@@ -5,6 +5,11 @@ description: Use when resolving an observed defect end-to-end, adaptively sequen
5
5
 
6
6
  # Showdar Bugfix
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Resolve an observed defect safely from evidence to verified fix.
@@ -5,6 +5,11 @@ description: Use when implementing or refactoring an agreed application change w
5
5
 
6
6
  # Showdar Build
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Convert an approved requirement/plan into maintainable production code.
@@ -5,6 +5,11 @@ description: Use when observed behavior fails through crashes, regressions, buil
5
5
 
6
6
  # Showdar Debug
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Find and confirm root cause before modifying production behavior.
@@ -5,6 +5,11 @@ description: Use when product UI needs design direction, UX decisions, responsiv
5
5
 
6
6
  # Showdar Design
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Produce product-specific UI direction instead of generic component-library output.
@@ -5,6 +5,11 @@ description: Use when implementing a complete feature end-to-end, adaptively seq
5
5
 
6
6
  # Showdar Feature
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Implement a complete feature end-to-end by sequencing primitive skills.
@@ -48,6 +48,12 @@ This skill owns repository state transitions, not source-code review or GitHub a
48
48
 
49
49
  ## Task branch isolation
50
50
 
51
+ **Mandatory pre-write gate:** Installing `showdar-git` adds project-wide branch guidance. For every task-owned source/config/test/docs change, including tasks executed by another primitive, inspect current Git state, then run `showdar guard --mutation local-write --json` before file-writing tools. Require `ok=true` and `data.allowed=true`; if blocked, STOP without editing.
52
+
53
+ On integration/default branches proactively run `showdar git-start --type <type> --name "<task>"` after repository/user convention inspection, then rerun guard. On an existing task branch, run guard without creating a nested branch. If the CLI is unavailable, use equivalent manual safe Git branch preparation and verify branch before editing. Explicit direct-work policy is a reviewed repo-local opt-in (`showdar.gitDirectWork=true`); never silently set it to bypass the gate.
54
+
55
+ This gate is enforced by agent/tool instructions, not a filesystem interceptor; arbitrary writes outside Showdar remain possible. Neither guard nor git-start authorizes edits, commits, merges, or pushes.
56
+
51
57
  Before the first task-owned source edit for a local-write engineering task, inspect Git state (`git status --short`, current branch, branch history and repository policy). Direct develop/main edits are not the default: on develop, development, dev, main, master or the default/integration branch, prepare a dedicated task branch before source mutation.
52
58
 
53
59
  Priority: repository instructions/documented branching convention; explicit current user instruction; clearly detected existing convention; Showdar safe default. Explicit trunk-based/direct-work policy wins: do not impose GitFlow. Branch preparation does not authorize source mutation.
@@ -5,6 +5,11 @@ description: Use when investigating and recovering from an active operational in
5
5
 
6
6
  # Showdar Incident
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Handle an active operational failure or service-impacting incident.
@@ -5,6 +5,11 @@ description: Use when inspecting or changing CI/CD, containers, environments, de
5
5
 
6
6
  # Showdar Ops
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Analyze and perform tightly scoped operational engineering across CI/CD, containers, environments, runtime configuration, deployment, observability, rollback, and release operations.
@@ -5,6 +5,11 @@ description: Use when agreed behavior needs a bounded implementation plan, chang
5
5
 
6
6
  # Showdar Plan
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Turn an idea, bug requirement, migration, or design decision into executable engineering work.
@@ -5,6 +5,11 @@ description: Use when interrupted or partial engineering work must be reconstruc
5
5
 
6
6
  # Showdar Recover
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Recover context after session interruption, compaction, agent failure, crash, or handoff.
@@ -5,6 +5,11 @@ description: Use when preparing, validating, or executing a release lifecycle, a
5
5
 
6
6
  # Showdar Release
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Prepare and execute a software release through existing primitive boundaries.
@@ -5,6 +5,11 @@ description: Use when product or business input needs explicit behavior, rules,
5
5
 
6
6
  # Showdar Requirements
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Convert tickets, briefs, conversations, API notes, and observed repository behavior into implementation-ready requirements.
@@ -5,6 +5,11 @@ description: Use when choosing or implementing automated tests for behavior, reg
5
5
 
6
6
  # Showdar Test
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Match test level to the boundary/risk being proven.
@@ -5,6 +5,11 @@ description: Use when upgrading dependencies, frameworks, runtimes, or native pl
5
5
 
6
6
  # Showdar Upgrade
7
7
 
8
+ ## Mandatory Git preflight for task-owned writes
9
+
10
+ Before any task-owned source/config/test/docs write, apply `showdar-git` branch policy: on develop/main/integration, inspect repository conventions and EXECUTE `showdar git-start --type <type> --name "<task>"` to prepare the task branch before editing. Then run `showdar guard --mutation local-write --json` and require `ok=true` and `data.allowed=true` before ANY file-writing tool. If blocked, STOP before editing. On an existing task branch run guard without creating a new branch. Recheck when a read-only stage turns into a write. If CLI is missing, manually prepare and verify safe Git branch state; do not silently write on develop/main. Explicit documented direct-work policy wins; never infer stash, reset, commit, merge, or push.
11
+
12
+
8
13
  ## Purpose
9
14
 
10
15
  - Make upgrades controlled engineering changes rather than version-number edits.
@@ -3,7 +3,7 @@ import { ALL_SKILLS } from './catalog.js';
3
3
  const RUNTIME_GUIDANCE = `Automatic Showdar selection: route the current request through \`showdar route --stdin --json\` when the Showdar CLI is available. Supply the prompt as literal stdin data, never as interpolated shell syntax. Honor the canonical lifecycle primary; do not substitute another installed skill when it is missing. Report missing skills and suggest \`showdar add <name>\`; never auto-install. Include installed domain matches only as specialized context overlays; load returned advisors only when installed. Domain discovery does not grant authority or replace the lifecycle route.
4
4
  Explicit named-skill requests may load that installed skill directly without automatic routing. Workflow skills remain native discoverable choices; the router does not select workflows. If the CLI is unavailable, use native skill discovery/static descriptions below. Do not fetch a CLI through npx or install dependencies automatically.
5
5
  Routing does not authorize mutation. Inspect the returned mutation class and current task authority before work. For local-write tasks, before the first task-owned source edit inspect Git state. On develop, development, dev, main, master or the repository default/integration branch, DO NOT begin source edits yet: prepare one branch per coherent task first. Follow repository instructions/documented convention, explicit current user instruction, clearly detected convention, then the Showdar safe default. Explicit trunk/direct-work policy wins.
6
- Use \`showdar git-start --dry-run --type <type> --name <task>\`, then \`showdar git-start --type <type> --name <task>\`, or equivalent repository-specific preparation. Confirm the task branch before mutating skill execution. Reuse that branch across plan/build/test/review; do not nest branches per skill. Dirty ownership or branch collisions require inspection; never infer stash, reset, restore or clean. Git-start does not authorize source mutation, commit, merge or push. Completion defaults to verify and report on the task branch; merge and push require their own explicit authority.`;
6
+ Before ANY task-owned source/config/test/docs write, execute Git preflight even if the router selected build directly. On integration/default branches inspect repository policy and EXECUTE \`showdar git-start --type <type> --name <task>\` (not just --dry-run), or equivalent repository-safe branch preparation. Then EXECUTE \`showdar guard --mutation local-write --json\` and require ok=true AND data.allowed=true BEFORE invoking any file-writing tool. If blocked, STOP before editing. On a matching task branch run guard without creating a new branch. Recheck before each later mutating stage. Do not infer permission from \`showdar route\`. If the CLI is unavailable, manually inspect Git and confirm the appropriate task branch or documented direct-work policy; never silently write on develop/main. Dirty ownership/branch collisions require inspection; never infer stash/reset/restore/clean. Guard and git-start do not authorize source edits, commit, merge or push. Completion means verify and report.`;
7
7
 
8
8
  const CANONICAL_ROUTE_ORDER = [
9
9
  ['map repository architecture, dependencies, or impact', 'showdar-understand'],
@@ -76,7 +76,7 @@ export function renderCursorRuleBody(skillIds) {
76
76
  const body = renderShowdarInstruction(skillIds).trimEnd();
77
77
  return `---
78
78
  description: Showdar skill and workflow routing guidance for software-engineering tasks
79
- alwaysApply: false
79
+ alwaysApply: true
80
80
  ---
81
81
 
82
82
  ${body}
@@ -0,0 +1,62 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ function git(cwd, args, optional = false) {
6
+ try {
7
+ return execFileSync('git', ['--no-optional-locks', ...args], {
8
+ cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 10000,
9
+ }).trim();
10
+ } catch (error) {
11
+ if (optional && error.status === 1) return null;
12
+ throw new Error(`Git inspection failed (${args[0]}): ${error.stderr?.toString().trim() || error.message}`);
13
+ }
14
+ }
15
+
16
+ /**
17
+ * Read-only agent preflight. This reports whether a local-write task has
18
+ * branch isolation; it cannot intercept file writes made by other tools.
19
+ */
20
+ export function guardMutation({ cwd, mutation }) {
21
+ if (!['read-only', 'local-write'].includes(mutation)) {
22
+ throw new Error('guard --mutation must be read-only or local-write.');
23
+ }
24
+ if (mutation === 'read-only') {
25
+ return { allowed: true, code: 'read-only', mutation, currentBranch: null, integrationBranch: null, directWork: false };
26
+ }
27
+
28
+ const root = git(cwd, ['rev-parse', '--show-toplevel']);
29
+ const currentBranch = git(root, ['symbolic-ref', '--quiet', '--short', 'HEAD'], true);
30
+ const config = key => git(root, ['config', '--local', '--get', key], true);
31
+ const directWork = config('showdar.gitDirectWork');
32
+ if (directWork !== null && !['true', 'false'].includes(directWork)) {
33
+ throw new Error('showdar.gitDirectWork must be true or false.');
34
+ }
35
+ const configuredBase = config('showdar.gitBase');
36
+ const defaultRef = git(root, ['symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD'], true)?.replace(/^origin\//, '') ?? null;
37
+ const integrationNames = new Set(['develop', 'development', 'dev', 'main', 'master', configuredBase, defaultRef].filter(Boolean));
38
+ const context = {
39
+ mutation, currentBranch, integrationBranch: configuredBase ?? defaultRef,
40
+ directWork: directWork === 'true',
41
+ };
42
+
43
+ for (const marker of ['MERGE_HEAD', 'CHERRY_PICK_HEAD', 'REVERT_HEAD', 'rebase-merge', 'rebase-apply', 'BISECT_LOG', 'sequencer']) {
44
+ const location = git(root, ['rev-parse', '--git-path', marker]);
45
+ if (existsSync(path.resolve(root, location))) {
46
+ return { allowed: false, code: 'git-operation-active', ...context };
47
+ }
48
+ }
49
+ if (!currentBranch) return { allowed: false, code: 'detached-head', ...context };
50
+
51
+ const isIntegration = integrationNames.has(currentBranch);
52
+ const allowed = !isIntegration || directWork === 'true';
53
+ const code = !allowed ? 'task-branch-required'
54
+ : isIntegration ? 'direct-work-configured' : 'task-branch-ready';
55
+ return { allowed, code, ...context };
56
+ }
57
+
58
+ export function formatMutationGuard(data) {
59
+ return `${data.allowed ? 'ALLOWED' : 'BLOCKED'}: ${data.code}
60
+ Mutation: ${data.mutation}
61
+ Branch: ${data.currentBranch ?? '(detached or not inspected)'}${data.allowed ? '' : '\nPrepare a safe task branch with showdar git-start, then rerun guard. Do not write source while blocked.'}`;
62
+ }
package/src/project.js CHANGED
@@ -590,6 +590,32 @@ export async function addSkill({ cwd, skill, ai = null, scope = null, home = hom
590
590
  if (existingManifest?.skills?.includes(skillId)) {
591
591
  const refreshedFiles = [];
592
592
  const priorOwned = ownedPathSet(existingManifest);
593
+ const source = path.join(packageRoot, 'skills', skillId);
594
+ if (!(await exists(path.join(source, 'SKILL.md')))) throw new Error(`Packaged skill source missing: ${skillId}`);
595
+
596
+ // Refresh all still-managed native copies, not only generated instructions.
597
+ // Preflight every destination before changing any of them.
598
+ const roots = [...new Set((existingManifest.targets ?? [effectiveAi]).map(target =>
599
+ effectiveScope === 'global'
600
+ ? globalSkillRootFor(target, { homeRoot: home })
601
+ : skillRootFor(target, cwd)))];
602
+ const destinations = [];
603
+ for (const root of roots) {
604
+ const destination = path.join(root, skillId);
605
+ const relative = manifestPathFor(baseRoot, destination);
606
+ const recorded = (existingManifest.files ?? []).find(file => file.path === relative);
607
+ if (!recorded) continue; // A skill satisfied by global does not own a project copy.
608
+ await assertSafeManagedPath(baseRoot, destination);
609
+ if (!(await exists(destination))) throw new Error(`Managed skill missing; refusing partial refresh: ${relative}`);
610
+ if (await hashTree(destination) !== recorded.hash) {
611
+ throw new Error(`Modified Showdar-owned skill; refusing to overwrite user changes: ${relative}`);
612
+ }
613
+ destinations.push(destination);
614
+ }
615
+
616
+ for (const destination of destinations) {
617
+ await copyOwned({ baseRoot, source, destination, priorOwned, newFiles: refreshedFiles });
618
+ }
593
619
  for (const target of existingManifest.commandHarness ?? []) {
594
620
  const commandRoot = effectiveScope === 'global' ? globalCommandRootForTarget(target, { homeRoot: home }) : commandRootFor(target, cwd);
595
621
  if (commandRoot) await generateCommandFiles({ baseRoot, skillIds: existingManifest.skills, target, commandRoot, priorOwned, newFiles: refreshedFiles });
@@ -600,11 +626,10 @@ export async function addSkill({ cwd, skill, ai = null, scope = null, home = hom
600
626
  if (instruction.kind === 'block') await writeManagedBlock(file, existingManifest.skills);
601
627
  else if (instruction.kind === 'file') await writeCursorRule(file, existingManifest.skills);
602
628
  }
603
- if (refreshedFiles.length) {
604
- const files = new Map(existingManifest.files.map(f => [f.path, f]));
605
- for (const f of refreshedFiles) files.set(f.path, f);
606
- await writeJsonAtomic(effectiveScope === 'global' ? globalManifestPath(home) : path.join(cwd, PROJECT_MANIFEST), { ...existingManifest, files: [...files.values()] });
607
- }
629
+ const files = new Map((existingManifest.files ?? []).map(f => [f.path, f]));
630
+ for (const f of refreshedFiles) files.set(f.path, f);
631
+ await writeJsonAtomic(effectiveScope === 'global' ? globalManifestPath(home) : path.join(cwd, PROJECT_MANIFEST),
632
+ { ...existingManifest, packageVersion, files: [...files.values()] });
608
633
  return { skill: skillId, root: '', destination: '', added: false, scope: effectiveScope, ai: effectiveAi, profile: existingManifest.profile };
609
634
  }
610
635
 
package/src/validate.js CHANGED
@@ -455,8 +455,8 @@ export async function validateRepository(packageRoot) {
455
455
  if (!claudeBlock.includes('showdar-skills:start') || !claudeBlock.includes('showdar-skills:end')) {
456
456
  errors.push('CLAUDE managed block is missing markers');
457
457
  }
458
- if (!cursorRule.includes('alwaysApply: false')) errors.push('Cursor rule must use Apply Intelligently metadata');
459
- if (cursorRule.includes('alwaysApply: true')) errors.push('Cursor rule must not use alwaysApply:true');
458
+ if (!cursorRule.includes('alwaysApply: true')) errors.push('Cursor rule must always apply for Git pre-write safety guidance');
459
+ if (!cursorRule.includes('showdar guard --mutation local-write --json')) errors.push('Cursor rule must include Git pre-write guard');
460
460
 
461
461
  const commandDir = path.join(packageRoot, 'commands', 'opencode', 'showdar');
462
462
  if (await exists(commandDir)) {