devworkspace 0.1.0 → 0.2.0

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.
Files changed (115) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +16 -2
  3. package/dist/agents/claude/adapter.d.ts +5 -0
  4. package/dist/agents/claude/adapter.js +10 -0
  5. package/dist/agents/claude/adapter.js.map +1 -1
  6. package/dist/agents/claude/content.js +3 -3
  7. package/dist/agents/claude/content.js.map +1 -1
  8. package/dist/cli/args.d.ts +22 -0
  9. package/dist/cli/args.js +7 -0
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/help.js +54 -7
  12. package/dist/cli/help.js.map +1 -1
  13. package/dist/cli/render.d.ts +9 -0
  14. package/dist/cli/render.js +105 -13
  15. package/dist/cli/render.js.map +1 -1
  16. package/dist/cli/run.d.ts +6 -0
  17. package/dist/cli/run.js +75 -3
  18. package/dist/cli/run.js.map +1 -1
  19. package/dist/core/workspace.js +2 -1
  20. package/dist/core/workspace.js.map +1 -1
  21. package/dist/index.d.ts +3 -1
  22. package/dist/index.js +2 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/integrations/adapters/agent-skills.d.ts +8 -0
  25. package/dist/integrations/adapters/agent-skills.js +25 -0
  26. package/dist/integrations/adapters/agent-skills.js.map +1 -0
  27. package/dist/integrations/adapters/claudePlugin.d.ts +41 -0
  28. package/dist/integrations/adapters/claudePlugin.js +129 -0
  29. package/dist/integrations/adapters/claudePlugin.js.map +1 -0
  30. package/dist/integrations/adapters/graphify.d.ts +2 -0
  31. package/dist/integrations/adapters/graphify.js +239 -0
  32. package/dist/integrations/adapters/graphify.js.map +1 -0
  33. package/dist/integrations/adapters/omniroute.d.ts +6 -0
  34. package/dist/integrations/adapters/omniroute.js +32 -0
  35. package/dist/integrations/adapters/omniroute.js.map +1 -0
  36. package/dist/integrations/adapters/pluginSkill.d.ts +28 -0
  37. package/dist/integrations/adapters/pluginSkill.js +195 -0
  38. package/dist/integrations/adapters/pluginSkill.js.map +1 -0
  39. package/dist/integrations/adapters/ponytail.d.ts +8 -0
  40. package/dist/integrations/adapters/ponytail.js +33 -0
  41. package/dist/integrations/adapters/ponytail.js.map +1 -0
  42. package/dist/integrations/exec.d.ts +26 -0
  43. package/dist/integrations/exec.js +167 -0
  44. package/dist/integrations/exec.js.map +1 -0
  45. package/dist/integrations/index.d.ts +5 -6
  46. package/dist/integrations/index.js +3 -29
  47. package/dist/integrations/index.js.map +1 -1
  48. package/dist/integrations/manager.d.ts +62 -0
  49. package/dist/integrations/manager.js +248 -0
  50. package/dist/integrations/manager.js.map +1 -0
  51. package/dist/integrations/notices.d.ts +13 -0
  52. package/dist/integrations/notices.js +68 -0
  53. package/dist/integrations/notices.js.map +1 -0
  54. package/dist/integrations/protect.d.ts +20 -0
  55. package/dist/integrations/protect.js +131 -0
  56. package/dist/integrations/protect.js.map +1 -0
  57. package/dist/integrations/state.d.ts +10 -0
  58. package/dist/integrations/state.js +81 -0
  59. package/dist/integrations/state.js.map +1 -0
  60. package/dist/integrations/types.d.ts +133 -16
  61. package/dist/integrations/types.js +13 -1
  62. package/dist/integrations/types.js.map +1 -1
  63. package/dist/prompts/onboarding.d.ts +3 -3
  64. package/dist/prompts/onboarding.js +5 -4
  65. package/dist/prompts/onboarding.js.map +1 -1
  66. package/dist/services/analysis.d.ts +2 -2
  67. package/dist/services/analysis.js +4 -5
  68. package/dist/services/analysis.js.map +1 -1
  69. package/dist/services/common.d.ts +8 -5
  70. package/dist/services/common.js +2 -5
  71. package/dist/services/common.js.map +1 -1
  72. package/dist/services/doctor.d.ts +10 -0
  73. package/dist/services/doctor.js +9 -15
  74. package/dist/services/doctor.js.map +1 -1
  75. package/dist/services/init.d.ts +9 -2
  76. package/dist/services/init.js +10 -7
  77. package/dist/services/init.js.map +1 -1
  78. package/dist/services/integrations.d.ts +26 -0
  79. package/dist/services/integrations.js +35 -0
  80. package/dist/services/integrations.js.map +1 -0
  81. package/dist/services/reset.d.ts +23 -0
  82. package/dist/services/reset.js +96 -0
  83. package/dist/services/reset.js.map +1 -0
  84. package/dist/services/status.d.ts +3 -2
  85. package/dist/services/status.js +3 -3
  86. package/dist/services/status.js.map +1 -1
  87. package/dist/utils/lock.d.ts +2 -0
  88. package/dist/utils/lock.js +2 -2
  89. package/dist/utils/lock.js.map +1 -1
  90. package/dist/utils/proc.d.ts +8 -1
  91. package/dist/utils/proc.js +31 -8
  92. package/dist/utils/proc.js.map +1 -1
  93. package/docs/architecture.md +1 -1
  94. package/docs/claude.md +4 -0
  95. package/docs/getting-started.md +13 -2
  96. package/docs/integrations.md +98 -33
  97. package/docs/security.md +5 -1
  98. package/docs/testing.md +2 -0
  99. package/docs/troubleshooting.md +9 -1
  100. package/package.json +1 -1
  101. package/dist/integrations/agent-skills.d.ts +0 -10
  102. package/dist/integrations/agent-skills.js +0 -45
  103. package/dist/integrations/agent-skills.js.map +0 -1
  104. package/dist/integrations/graphify.d.ts +0 -7
  105. package/dist/integrations/graphify.js +0 -54
  106. package/dist/integrations/graphify.js.map +0 -1
  107. package/dist/integrations/omniroute.d.ts +0 -7
  108. package/dist/integrations/omniroute.js +0 -24
  109. package/dist/integrations/omniroute.js.map +0 -1
  110. package/dist/integrations/ponytail.d.ts +0 -10
  111. package/dist/integrations/ponytail.js +0 -58
  112. package/dist/integrations/ponytail.js.map +0 -1
  113. package/dist/integrations/probe.d.ts +0 -6
  114. package/dist/integrations/probe.js +0 -41
  115. package/dist/integrations/probe.js.map +0 -1
@@ -1,51 +1,116 @@
1
1
  # Integrations
2
2
 
3
- Each integration sits behind the `Integration` interface (`src/integrations/types.ts`): `detect(ctx) → IntegrationStatus`. Core code only sees states `READY`, `PARTIAL`, `NOT_DETECTED`, `UNVERIFIED`, `ERROR` plus remediation text. A failing detector degrades to `ERROR` and never breaks a command. Missing integrations are warnings, not failures.
3
+ DevWorkspace can install, verify and repair three tools that the generated Claude instructions rely on. It does this with one command, never assumes success, and never overwrites your files.
4
4
 
5
- Documentation below was read from each project's repository when this version was written. Re-check before relying on it; these projects evolve.
5
+ ```bash
6
+ npx devworkspace setup --integrations --dry-run # see exactly what would run
7
+ npx devworkspace setup --integrations --yes # do it
8
+ npx devworkspace integrations status # observe the real state (runs the tools)
9
+ npx devworkspace doctor # core workspace + integrations, reported separately
10
+ ```
6
11
 
7
- | Integration | Role | Researched against |
12
+ Also: `devworkspace init --with-integrations --yes` (same manager), `devworkspace integrations repair --yes`, and `devworkspace integrations status --restarted` (after you restart Claude Code).
13
+
14
+ Useful flags: `--only graphify,agent-skills,ponytail` (a subset), `--scope project|user` (default project), `--json` (machine-readable result, progress goes to stderr), `--quick` (status without running the tools).
15
+
16
+ | Tool | Role | Installed as |
17
+ | --- | --- | --- |
18
+ | [Graphify](https://github.com/Graphify-Labs/graphify) | Structural code graph for navigation | `graphifyy` CLI (per-user) + project skill |
19
+ | [Agent Skills](https://github.com/addyosmani/agent-skills) | Engineering workflows (spec, plan, build, test, review, ship) | Native Claude Code plugin, else portable skills |
20
+ | [Ponytail](https://github.com/DietrichGebert/ponytail) | Quality review and simplification | Native Claude Code plugin, else portable skills |
21
+ | [OmniRoute](https://github.com/diegosouzapw/OmniRoute) | Optional model routing | Never installed; only observed |
22
+
23
+ ## Statuses (what each one means)
24
+
25
+ Statuses are **observed** by looking at the machine and running the tools. `.devworkspace/state/integrations.json` only records history and is never trusted as proof.
26
+
27
+ | Status | Meaning |
28
+ | --- | --- |
29
+ | `NOT_INSTALLED` | Nothing found. |
30
+ | `PREREQUISITES_MISSING` | Cannot install automatically; the output says exactly what to install. |
31
+ | `INSTALLING` | A setup run is in progress (a leftover marker means it was interrupted; run `integrations repair --yes`). |
32
+ | `INSTALLED` | Files/config present, **not verified** (quick checks such as `devworkspace status` can never say more). |
33
+ | `VERIFIED` | The tool was run or queried and everything required for its documented capabilities checked out. |
34
+ | `DEGRADED` | Installed but incomplete or unhealthy; the warnings say what is missing (e.g. portable skills have no commands or hooks). |
35
+ | `FAILED` | The last setup attempt failed; the error and next step are shown and remembered. |
36
+ | `RESTART_REQUIRED` | Installed, but Claude Code must be restarted (or `/reload-plugins` run) to load it. Cleared by `integrations status --restarted`. |
37
+
38
+ "Full integration readiness" is stated only when every **required** integration (Graphify, Agent Skills, Ponytail) is `VERIFIED`. A missing integration never makes the core workspace unhealthy and never changes `doctor`'s exit code unless you pass `--strict` (exit 3).
39
+
40
+ Exit codes for `setup` / `integrations repair`: `0` every required integration `VERIFIED` or `RESTART_REQUIRED` (or a dry run) · `1` something `FAILED` or a prerequisite is missing · `2` approval needed (nothing risky ran) · `3` finished but not fully verified (`DEGRADED`/`INSTALLED`).
41
+
42
+ ## Consent and scope
43
+
44
+ Every step has a level. Without `--yes` only **project** steps run; if any step needs more, nothing runs and the plan is printed.
45
+
46
+ | Level | Examples | Needs `--yes` |
8
47
  | --- | --- | --- |
9
- | Graphify | Structural discovery | `Graphify-Labs/graphify` README (Oct 2026) |
10
- | Agent Skills | Engineering workflows | `addyosmani/agent-skills` README (Oct 2026) |
11
- | Ponytail | Quality / simplification review | `DietrichGebert/ponytail` README (Oct 2026) |
12
- | OmniRoute | Optional model routing | not integrated in V1 |
13
- | Claude Code | Agent | `code.claude.com` memory and skills docs (Oct 2026) |
48
+ | project | `graphify install --project`, `claude plugin ... --scope project` | no |
49
+ | machine | `uv tool install graphifyy` (your user account, no administrator rights) | yes |
50
+ | user-config | any `--scope user` / `graphify install` (user-level skill) | yes |
51
+ | third-party-code | `npx skills add` (runs a registry package) | yes |
14
52
 
15
- ## Graphify
53
+ `--scope project` (default) keeps everything in the repository; `--scope user` installs for all your projects. DevWorkspace never passes `-y` to Claude Code's own plugin installer: if a marketplace wants you to approve a command, setup stops and prints it for you to run.
16
54
 
17
- - **Install (documented):** `uv tool install graphifyy` (or `pipx install graphifyy` / `pip install graphifyy`), then `graphify install` (global) or `graphify install --project` (writes `.claude/skills/graphify/`).
18
- - **Use:** `/graphify .` in Claude Code builds the graph into `graphify-out/` (`graph.json`, `GRAPH_REPORT.md`, `graph.html`). Queries: `graphify query "…"`, `graphify path "A" "B"`, `graphify explain "…"`. `graphify hook install` auto-rebuilds on commits.
19
- - **Detection:** `graphify` on PATH, `graphify-out/graph.json`, project/user skill directory. `READY` = (CLI or skill) and a built graph; `PARTIAL` = installed but no graph (or graph without CLI).
20
- - **Authority:** the graph is an aid. The generated skill tells the agent to confirm in real files; repository evidence wins.
21
- - **Not done:** DevWorkspace does not run Graphify, build graphs, or parse `graph.json`. `graphify-out/` is excluded from scans.
55
+ Setup is non-interactive. It never prompts, so it cannot hang in CI; when it needs a human it exits `2`/`1` with the exact next step.
56
+
57
+ ## What happens, per tool
58
+
59
+ ### Graphify
60
+
61
+ 1. Reuse an existing `graphify` (PATH, `~/.local/bin`, or where uv/pipx/pip put scripts) after running `graphify --version`.
62
+ 2. Otherwise pick an installer: **uv** (`uv tool install graphifyy`), else **pipx** (`pipx install graphifyy`), else the documented **`pip install --user graphifyy`** if a real Python 3.10+ exists. No separate manager is required when Python or uv is present.
63
+ 3. Run `graphify install --project` (user scope: `graphify install`).
64
+ 4. Verify: executable runs, project skill exists, the skill's recorded version matches the CLI, and, because Graphify's hooks call `graphify` by name, that it is on PATH. If not on PATH the status is `DEGRADED` with the folder to add, instead of a false success.
65
+
66
+ Python detection runs `--version` on each candidate (`py -3`, `python3`, `python`). On Windows the Microsoft Store `python` shortcut exists on PATH but is not Python, and is correctly rejected.
67
+
68
+ **Graphify edits your files.** `graphify install --project` appends a section to `CLAUDE.md`, creates `.claude/CLAUDE.md` and registers Claude Code `PreToolUse` hooks in `.claude/settings.json`. It merges and is idempotent. DevWorkspace snapshots those files first and, if anything you had is missing afterwards, restores them and fails the step. Review `git diff` after setup. Building the graph itself (`/graphify .`) uses the model, so DevWorkspace does not do it.
69
+
70
+ ### Agent Skills and Ponytail
71
+
72
+ 1. **Native plugin** (preferred) when a Claude Code CLI ≥ 2.1.268 is available (PATH, or the binary bundled with the VS Code extension): register the marketplace (`addy-agent-skills`, `ponytail`) by HTTPS git URL, then `claude plugin install <plugin>@<marketplace> --scope project`. Already-registered marketplaces are not added again.
73
+ 2. **Portable skills** otherwise, with the documented Skills CLI: `npx skills add <repo> --agent claude-code --skill '*' --copy -y --json` (copied files, telemetry opt-outs set, project scope; `-g` for user scope).
74
+ 3. Verify with `claude plugin list --json` (enabled, no load errors, belongs to this project or user scope), or for portable installs by checking the skill folders.
75
+
76
+ What is reported, honestly:
77
+
78
+ | | Native plugin | Portable skills |
79
+ | --- | --- | --- |
80
+ | Skills | yes | yes |
81
+ | Slash commands | yes | **no** |
82
+ | Hooks | Ponytail: yes (needs `node` on PATH); Agent Skills: not claimed | **no** |
83
+ | Shared `references/` (Agent Skills) | yes | not installed by the Skills CLI (known upstream limitation, issue #361) → warning |
84
+ | Ponytail's always-on `AGENTS.md` ruleset | n/a | **not installed** (DevWorkspace never edits your `AGENTS.md`) |
85
+ | Resulting status | `RESTART_REQUIRED`, then `VERIFIED` | always `DEGRADED` |
22
86
 
23
- ## Agent Skills
87
+ A marketplace being registered does not count as the plugin being installed; the two are checked separately. A same-named skill folder you wrote yourself is never overwritten: setup stops with an explanation.
24
88
 
25
- - **Install (documented):** in Claude Code, `/plugin marketplace add addyosmani/agent-skills` then `/plugin install agent-skills@addy-agent-skills`.
26
- - **Provides:** `/spec`, `/plan`, `/build`, `/test`, `/constraints`, `/review`, `/webperf`, `/code-simplify`, `/ship`, plus auto-activating skills.
27
- - **Division of labour:** the DevWorkspace skill says *when* (per task type, see [routing](routing.md)); Agent Skills says *how*. Nothing is copied.
28
- - **Detection:** best effort, searching Claude Code settings/plugin registries for `agent-skills`. Plugin state belongs to Claude Code, so absence is reported as `UNVERIFIED`, not "missing".
89
+ Portable installs record license/attribution in `.devworkspace/THIRD_PARTY_NOTICES.md` (both are MIT; the notice names the copyright holders).
29
90
 
30
- ## Ponytail
91
+ ## Protection, idempotency and recovery
31
92
 
32
- - **Install (documented):** `/plugin marketplace add DietrichGebert/ponytail`, `/plugin install ponytail@ponytail`. Other agents: copy its `AGENTS.md` or install `skills/ponytail/SKILL.md`.
33
- - **Commands:** `/ponytail [lite|full|ultra|off]`, `/ponytail-review`, `/ponytail-audit`, `/ponytail-debt`. Optional config `~/.config/ponytail/config.json`, `PONYTAIL_DEFAULT_MODE`.
34
- - **Use here:** review of meaningful diffs and simplification only. It never substitutes for tests. Strictness maps to `project.json` → `settings.review` (`off` removes the review requirement from new tasks; `light` default; `strict` reserved for stricter policy).
35
- - **Detection:** plugin mention in settings, `.claude/skills/ponytail`, or `AGENTS.md` mention. Otherwise `UNVERIFIED`.
93
+ - Before each setup run, the files tools may edit (`CLAUDE.md`, `.claude/CLAUDE.md`, `AGENTS.md`, `.claude/settings*.json`) and every existing file under `.claude/skills/` are snapshotted. After each step they are verified: text files may only gain lines, JSON may only gain keys, existing skill files must be byte-identical. Violations are restored and reported.
94
+ - Re-running is safe: verified integrations are skipped, a pending restart is not "fixed" by reinstalling, marketplaces are never added twice, `CLAUDE.md` gets one Graphify section.
95
+ - If a run fails halfway the state is kept (`FAILED`, last error) and the next run resumes from what is observed on disk. If the process was killed, the leftover marker is detected and `integrations repair --yes` finishes the job. Ctrl+C cancels the running child process.
96
+ - Child processes use argument arrays with timeouts (no shell). Windows `.cmd` shims go through a strictly validated `cmd.exe` call that rejects any argument containing shell metacharacters.
97
+ - Tool output is scrubbed (secrets, absolute paths) before it is shown or stored. Credentials are never read.
98
+ - Nothing is ever uninstalled. DevWorkspace has no `uninstall`: removing Claude Code plugins is `claude plugin uninstall`, and Graphify has `graphify uninstall`; run them yourself.
36
99
 
37
- ## OmniRoute (optional)
100
+ ## Verified vs. assumed (as of 2026-10-09, Windows 11)
38
101
 
39
- Not required, not in the V1 path, no API keys or model configuration. The adapter only reports whether an `omniroute` executable exists. A future provider boundary can build on it.
102
+ Verified **live** on a real machine: `uv tool install graphifyy` and `graphify install --project` (0.9.80 and 0.9.82, files written, merge behaviour, idempotency), `graphify --version`, discovery of uv tool bin directories, Claude Code 2.1.295 `--version`/`plugin list --json`, the failure JSON of `plugin marketplace add`, SSH vs HTTPS clone behaviour and its failure messages.
103
+ Verified with **controlled fake CLIs** (real child processes, `.cmd` shims, folders with spaces) and scripted runners: the successful native-plugin and Skills-CLI paths, restart handling, repair, cancellation, approval prompts. GitHub was unreachable from the build machine for large clones, so a **real end-to-end native plugin install and a real `npx skills add` were not completed**. Their command lines and JSON shapes follow the official documentation and the observed failure output.
104
+ **Not tested:** macOS, Linux, pipx, `pip install --user` for real, Claude Code versions other than 2.1.295.
40
105
 
41
- ## Claude Code
106
+ ## Limitations
42
107
 
43
- See [claude.md](claude.md).
108
+ - The native-plugin path depends on Claude Code cloning GitHub sources over SSH; without a GitHub SSH key it fails. The setup output then shows the documented fix (`git config --global url."https://github.com/".insteadOf git@github.com:`), which changes your global Git config and is therefore left for you to run.
109
+ - Detection of the Claude Code CLI uses PATH and the VS Code/Cursor extension folders; other installs may need to be on PATH.
110
+ - DevWorkspace cannot tell whether a running Claude Code session has loaded a plugin; `RESTART_REQUIRED` stays until you acknowledge it.
111
+ - Graphify's hooks live in the project's `.claude/settings.json`, so teammates need `graphify` installed too (setup run on their machine does it).
112
+ - OmniRoute is only observed.
44
113
 
45
114
  ## Adding an integration
46
115
 
47
- 1. Implement `Integration` in `src/integrations/<name>.ts` (pure detection, no side effects, timeouts if you spawn anything).
48
- 2. Add it to `INTEGRATIONS` in `src/integrations/index.ts`.
49
- 3. Give it a `usage` string; the Claude skill renders it automatically for non-optional integrations.
50
- 4. Add tests for READY / PARTIAL / NOT_DETECTED and a throwing detector.
51
- 5. Document researched commands and limitations here.
116
+ Implement `IntegrationAdapter` (`src/integrations/types.ts`): `inspect(ctx, deep)` must observe reality (never read the state file as proof) and only return `VERIFIED` when `deep` and every check passed; `plan(ctx, report)` returns steps with a consent `level`, the files they may touch (`protectPaths`) and blockers with exact remediation. Register it in `ADAPTERS`, then test it with `FakeRunner` (see `tests/helpers/fakeRunner.ts`) for: installed, missing, partial, prerequisites missing, timeout, permission denied, cancellation, user-file protection and repeated runs.
package/docs/security.md CHANGED
@@ -29,7 +29,11 @@ Repository files are untrusted data. The installed instructions and every genera
29
29
 
30
30
  ## Subprocesses
31
31
 
32
- Only `git` is executed, with argument arrays and `shell: false`, with timeouts and output caps. `.cmd`/`.bat` shims are never executed. Repository scripts are never run by DevWorkspace.
32
+ `git` (read-only) and, during `setup --integrations`, the installers (`uv`, `pipx`, `python -m pip`, `graphify`, `claude`) are executed with argument arrays and `shell: false`, with timeouts and output caps. Windows `.cmd` shims are run only through a validated `cmd.exe` call that rejects arguments containing shell metacharacters. Repository scripts are never run by DevWorkspace.
33
+
34
+ ## Installing third-party tools
35
+
36
+ `setup --integrations` can install a Python tool (per user), register Claude Code plugins and, as a fallback, run a registry package (`npx skills`). Each step has a consent level and only project-local steps run without `--yes`. Existing `CLAUDE.md`, `.claude/settings*.json`, `AGENTS.md` and skills are snapshotted and verified after every step, and restored on damage. Claude Code's own plugin installer is never given `-y`. The Skills CLI is run with `DISABLE_TELEMETRY=1` and `DO_NOT_TRACK=1`; its other behaviour is its own. Tool output is scrubbed of secrets and absolute paths before it is shown or stored. Plugins and Graphify hooks run code on your machine: review what you approve.
33
37
 
34
38
  ## Git safety
35
39
 
package/docs/testing.md CHANGED
@@ -53,6 +53,8 @@ npm run smoke # pack → install tarball into clean dirs → run the
53
53
  npm run release:check # the full pre-publish gate; never publishes
54
54
  ```
55
55
 
56
+ Integration manager tests use a scriptable `FakeRunner`, file-effect emulators that mirror the real Graphify CLI, and a real child-process fake `claude`/`uv`/`graphify` (`tests/helpers/fake-tool.mjs`, run as `.cmd` shims in folders with spaces on Windows). Routine tests never touch your real Claude configuration or install anything on the machine.
57
+
56
58
  Layers: **unit** (pure logic, security, paths incl. `path.win32`, schemas, routing scenarios, prompts), **integration** (command flows through the real CLI in-process with a hermetic home directory), **e2e** (the ten acceptance scenarios, Windows-style paths, large repo simulation, concurrency, hostile imports). Fixtures live in `fixtures/` (Express, React/Vite, Next.js, NestJS, FastAPI, monorepo, no tests, failing tests, existing AI files, prompt injection); scenarios that need Git state, secrets or unusual paths are built at test time.
57
59
 
58
60
  The generated prompts are tested for *behaviour*, not snapshots: `prompts/requirements.ts` lists what every onboarding/refresh prompt must instruct (untrusted-data rule, no secrets, evidence, git safety, testing contract, completion gate, memory rules, …), and `validatePrompt` is used by the tests and by `doctor`.
@@ -8,11 +8,19 @@ Start with `devworkspace doctor`. Every warning/failure includes a remediation l
8
8
  | **Git unavailable** | Install Git. DevWorkspace still works but cannot report branch/working-tree state or tracked-secret problems, and Claude cannot protect uncommitted changes. |
9
9
  | **Not a Git repository** | Fine. `status` shows `Git: not a repository`. Consider `git init` so changes can be reviewed and reverted. |
10
10
  | **"No DevWorkspace found"** | Run `devworkspace init` in the project root. Commands search upward from the current directory; use `--cwd <dir>` if you are elsewhere. |
11
+ | **`setup --integrations` says approval is needed (exit 2)** | Nothing risky ran. Review with `--dry-run`, then re-run with `--yes`. Machine-level (installing the Graphify tool), user-level and registry-package steps always need it. |
12
+ | **`PREREQUISITES_MISSING` for Graphify** | Install uv (`winget install --id astral-sh.uv`) or Python 3.10+ from python.org. On Windows the Microsoft Store `python` shortcut is not Python. Then re-run setup. |
13
+ | **Graphify `DEGRADED`: not on PATH** | Its Claude Code hooks call `graphify` by name. Add the folder shown in the next step to PATH (or run `uv tool update-shell` / `pipx ensurepath`) and open a new terminal. |
14
+ | **`RESTART_REQUIRED`** | Restart Claude Code (or run `/reload-plugins`), then `devworkspace integrations status --restarted`. |
15
+ | **Plugin install fails with "Host key verification failed" / "Could not read from remote repository"** | Claude Code cloned the plugin over SSH and you have no GitHub SSH key. Run the documented fix yourself (it edits your global Git config): `git config --global url."https://github.com/".insteadOf git@github.com:`, then re-run setup. |
16
+ | **Plugin or marketplace clone times out** | Slow or blocked access to github.com. Retry later; Claude Code's own timeout can be raised with `CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS`. Setup resumes from what is already done. |
17
+ | **Agent Skills / Ponytail `DEGRADED` (portable skills)** | The Claude Code CLI was not found, so only portable skills were installed (no slash commands/hooks). Install the native plugin: `claude plugin marketplace add <url> --scope project` then `claude plugin install <plugin>@<marketplace> --scope project`, or put `claude` on PATH and run `devworkspace integrations repair --yes`. |
18
+ | **Setup was interrupted (Ctrl+C, crash)** | Run `devworkspace integrations repair --yes`; it continues from what is observed on disk. Files you own are never left half-edited by DevWorkspace, and `git diff` shows exactly what tools changed. |
11
19
  | **Graphify unavailable / no graph** | `uv tool install graphifyy` (or `pipx`), `graphify install --project`, then run `/graphify .` in Claude Code. DevWorkspace keeps working without it. |
12
- | **Agent Skills / Ponytail "Unverified"** | Claude Code owns plugin state, so this is best-effort. In Claude Code run `/plugin` to see installed plugins, or install: `/plugin marketplace add addyosmani/agent-skills` → `/plugin install agent-skills@addy-agent-skills`; `/plugin marketplace add DietrichGebert/ponytail` → `/plugin install ponytail@ponytail`. |
13
20
  | **Claude config conflict** (`agent install` reports `CONFLICT`) | Unbalanced `devworkspace:start/end` markers in `CLAUDE.md`, or a user-authored skill at `.claude/skills/devworkspace/`. Fix/remove the stray marker or rename your skill, then re-run. Nothing was changed. |
14
21
  | **Claude ignores my `AGENTS.md`** | Claude reads `AGENTS.md` only when no `CLAUDE.md` exists. `agent install` adds an `@AGENTS.md` import when it creates `CLAUDE.md`; if you created `CLAUDE.md` yourself, add `@AGENTS.md` to it. |
15
22
  | **Stale context** | `devworkspace refresh`, then paste `.devworkspace/analysis/refresh-prompt.md` into Claude. Facts without cited `--file` sources can never be proven stale. |
23
+ | **Want to start completely fresh** | `devworkspace reset --yes` (add `--include-agent-files` to also remove the Claude block and skill), then `devworkspace init`. `reset` without `--yes` only prints a plan. |
16
24
  | **Corrupted workspace** (`malformed JSON`, schema errors) | `git checkout -- .devworkspace/<file>`; or copy a backup from `.devworkspace/local/backups/`. A newer-schema file means upgrade DevWorkspace. Leftover `*.tmp` files come from an interrupted write and are safe to delete. |
17
25
  | **"Another DevWorkspace process is modifying this workspace"** | Wait. If no DevWorkspace process is running, delete `.devworkspace/local/workspace.lock` (stale locks from dead processes are normally broken automatically). |
18
26
  | **Tests were failing before my task** | Record a baseline: `devworkspace task tests <id> --phase baseline --passed N --failed M`. Only *increases* in failures block completion. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devworkspace",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Project-local AI engineering workspace: deterministic repository discovery, portable project knowledge, tasks, decisions and verification gates for AI coding agents.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,10 +0,0 @@
1
- import type { Integration } from './types.js';
2
- /**
3
- * Agent Skills is distributed as a Claude Code plugin. Documented install:
4
- * /plugin marketplace add addyosmani/agent-skills
5
- * /plugin install agent-skills@addy-agent-skills
6
- * Its slash commands (/spec /plan /build /test /review /code-simplify /ship) provide the HOW;
7
- * DevWorkspace's generated skill only decides WHEN to use them.
8
- * Plugin state is owned by Claude Code, so detection is best effort and reported as UNVERIFIED when not found.
9
- */
10
- export declare const agentSkills: Integration;
@@ -1,45 +0,0 @@
1
- import { claudeConfigMentions } from './probe.js';
2
- const DOCS = 'https://github.com/addyosmani/agent-skills';
3
- /**
4
- * Agent Skills is distributed as a Claude Code plugin. Documented install:
5
- * /plugin marketplace add addyosmani/agent-skills
6
- * /plugin install agent-skills@addy-agent-skills
7
- * Its slash commands (/spec /plan /build /test /review /code-simplify /ship) provide the HOW;
8
- * DevWorkspace's generated skill only decides WHEN to use them.
9
- * Plugin state is owned by Claude Code, so detection is best effort and reported as UNVERIFIED when not found.
10
- */
11
- export const agentSkills = {
12
- id: 'agent-skills',
13
- name: 'Agent Skills',
14
- optional: false,
15
- usage: 'Use the Agent Skills workflows for engineering methodology: /spec (requirements), /plan (task breakdown), /build (implementation), ' +
16
- '/test (verification), /review (review gates), /code-simplify (reduce complexity), /ship (release). Do not re-implement them from memory; invoke them.',
17
- async detect(ctx) {
18
- const hit = await claudeConfigMentions(ctx, 'agent-skills');
19
- if (hit) {
20
- return {
21
- id: 'agent-skills',
22
- name: 'Agent Skills',
23
- optional: false,
24
- state: 'READY',
25
- details: [`referenced in Claude Code config (${hit})`],
26
- remediation: [],
27
- docsUrl: DOCS,
28
- };
29
- }
30
- return {
31
- id: 'agent-skills',
32
- name: 'Agent Skills',
33
- optional: false,
34
- state: 'UNVERIFIED',
35
- details: ['not found in Claude Code settings; plugin state is held by Claude Code so this check is best-effort'],
36
- remediation: [
37
- 'In Claude Code run: /plugin marketplace add addyosmani/agent-skills',
38
- 'Then: /plugin install agent-skills@addy-agent-skills',
39
- 'Verify with /plugin, or by confirming /spec and /review appear in the slash-command list.',
40
- ],
41
- docsUrl: DOCS,
42
- };
43
- },
44
- };
45
- //# sourceMappingURL=agent-skills.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent-skills.js","sourceRoot":"","sources":["../../src/integrations/agent-skills.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,IAAI,GAAG,4CAA4C,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAgB;IACtC,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,cAAc;IACpB,QAAQ,EAAE,KAAK;IACf,KAAK,EACH,qIAAqI;QACrI,uJAAuJ;IACzJ,KAAK,CAAC,MAAM,CAAC,GAAG;QACd,MAAM,GAAG,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC5D,IAAI,GAAG,EAAE,CAAC;YACR,OAAO;gBACL,EAAE,EAAE,cAAc;gBAClB,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,KAAK;gBACf,KAAK,EAAE,OAAO;gBACd,OAAO,EAAE,CAAC,qCAAqC,GAAG,GAAG,CAAC;gBACtD,WAAW,EAAE,EAAE;gBACf,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QACD,OAAO;YACL,EAAE,EAAE,cAAc;YAClB,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,CAAC,qGAAqG,CAAC;YAChH,WAAW,EAAE;gBACX,qEAAqE;gBACrE,sDAAsD;gBACtD,2FAA2F;aAC5F;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import type { Integration, IntegrationStatus } from './types.js';\nimport { claudeConfigMentions } from './probe.js';\n\nconst DOCS = 'https://github.com/addyosmani/agent-skills';\n\n/**\n * Agent Skills is distributed as a Claude Code plugin. Documented install:\n * /plugin marketplace add addyosmani/agent-skills\n * /plugin install agent-skills@addy-agent-skills\n * Its slash commands (/spec /plan /build /test /review /code-simplify /ship) provide the HOW;\n * DevWorkspace's generated skill only decides WHEN to use them.\n * Plugin state is owned by Claude Code, so detection is best effort and reported as UNVERIFIED when not found.\n */\nexport const agentSkills: Integration = {\n id: 'agent-skills',\n name: 'Agent Skills',\n optional: false,\n usage:\n 'Use the Agent Skills workflows for engineering methodology: /spec (requirements), /plan (task breakdown), /build (implementation), ' +\n '/test (verification), /review (review gates), /code-simplify (reduce complexity), /ship (release). Do not re-implement them from memory; invoke them.',\n async detect(ctx): Promise<IntegrationStatus> {\n const hit = await claudeConfigMentions(ctx, 'agent-skills');\n if (hit) {\n return {\n id: 'agent-skills',\n name: 'Agent Skills',\n optional: false,\n state: 'READY',\n details: [`referenced in Claude Code config (${hit})`],\n remediation: [],\n docsUrl: DOCS,\n };\n }\n return {\n id: 'agent-skills',\n name: 'Agent Skills',\n optional: false,\n state: 'UNVERIFIED',\n details: ['not found in Claude Code settings; plugin state is held by Claude Code so this check is best-effort'],\n remediation: [\n 'In Claude Code run: /plugin marketplace add addyosmani/agent-skills',\n 'Then: /plugin install agent-skills@addy-agent-skills',\n 'Verify with /plugin, or by confirming /spec and /review appear in the slash-command list.',\n ],\n docsUrl: DOCS,\n };\n },\n};\n"]}
@@ -1,7 +0,0 @@
1
- import type { Integration } from './types.js';
2
- /**
3
- * Graphify builds a queryable knowledge graph in graphify-out/ and registers a Claude Code skill.
4
- * Documented install: `uv tool install graphifyy` (or pipx/pip), then `graphify install --project`.
5
- * DevWorkspace only detects it and tells the agent when to use it; it never re-implements graph building.
6
- */
7
- export declare const graphify: Integration;
@@ -1,54 +0,0 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import { skillDirExists } from './probe.js';
4
- const DOCS = 'https://github.com/Graphify-Labs/graphify';
5
- /**
6
- * Graphify builds a queryable knowledge graph in graphify-out/ and registers a Claude Code skill.
7
- * Documented install: `uv tool install graphifyy` (or pipx/pip), then `graphify install --project`.
8
- * DevWorkspace only detects it and tells the agent when to use it; it never re-implements graph building.
9
- */
10
- export const graphify = {
11
- id: 'graphify',
12
- name: 'Graphify',
13
- optional: false,
14
- usage: 'For "where is X / what depends on Y" questions, query the Graphify graph first (graphify query "<question>", graphify path, graphify explain) ' +
15
- 'or use the /graphify skill. The graph is a navigation aid, not a source of truth: confirm in the actual files before relying on it.',
16
- async detect(ctx) {
17
- const details = [];
18
- const remediation = [];
19
- const cli = await ctx.which('graphify');
20
- const skill = await skillDirExists(ctx, 'graphify');
21
- let graphBuilt = false;
22
- try {
23
- const st = await fs.stat(path.join(ctx.root, 'graphify-out', 'graph.json'));
24
- graphBuilt = st.isFile();
25
- if (graphBuilt)
26
- details.push(`graph built (graphify-out/graph.json, updated ${st.mtime.toISOString().slice(0, 10)})`);
27
- }
28
- catch {
29
- /* not built */
30
- }
31
- if (cli)
32
- details.push('graphify CLI on PATH');
33
- if (skill)
34
- details.push(`Claude skill installed (${skill})`);
35
- let state;
36
- if ((cli || skill) && graphBuilt)
37
- state = 'READY';
38
- else if (cli || skill) {
39
- state = 'PARTIAL';
40
- details.push('no graph built yet');
41
- remediation.push('In Claude Code run: /graphify . (builds graphify-out/graph.json)');
42
- }
43
- else if (graphBuilt) {
44
- state = 'PARTIAL';
45
- remediation.push('Install the CLI: uv tool install graphifyy (or pipx install graphifyy), then: graphify install --project');
46
- }
47
- else {
48
- state = 'NOT_DETECTED';
49
- remediation.push('Install: uv tool install graphifyy (or pipx install graphifyy)', 'Register for this project: graphify install --project', 'Then in Claude Code run: /graphify .');
50
- }
51
- return { id: 'graphify', name: 'Graphify', optional: false, state, details, remediation, docsUrl: DOCS };
52
- },
53
- };
54
- //# sourceMappingURL=graphify.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"graphify.js","sourceRoot":"","sources":["../../src/integrations/graphify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,IAAI,GAAG,2CAA2C,CAAC;AAEzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,EAAE,EAAE,UAAU;IACd,IAAI,EAAE,UAAU;IAChB,QAAQ,EAAE,KAAK;IACf,KAAK,EACH,gJAAgJ;QAChJ,qIAAqI;IACvI,KAAK,CAAC,MAAM,CAAC,GAAG;QACd,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACpD,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC,CAAC;YAC5E,UAAU,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;YACzB,IAAI,UAAU;gBAAE,OAAO,CAAC,IAAI,CAAC,iDAAiD,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACxH,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;QACD,IAAI,GAAG;YAAE,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC9C,IAAI,KAAK;YAAE,OAAO,CAAC,IAAI,CAAC,2BAA2B,KAAK,GAAG,CAAC,CAAC;QAE7D,IAAI,KAAiC,CAAC;QACtC,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,UAAU;YAAE,KAAK,GAAG,OAAO,CAAC;aAC7C,IAAI,GAAG,IAAI,KAAK,EAAE,CAAC;YACtB,KAAK,GAAG,SAAS,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YACnC,WAAW,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;QACzF,CAAC;aAAM,IAAI,UAAU,EAAE,CAAC;YACtB,KAAK,GAAG,SAAS,CAAC;YAClB,WAAW,CAAC,IAAI,CAAC,4GAA4G,CAAC,CAAC;QACjI,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,cAAc,CAAC;YACvB,WAAW,CAAC,IAAI,CAAC,kEAAkE,EAAE,uDAAuD,EAAE,sCAAsC,CAAC,CAAC;QACxL,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3G,CAAC;CACF,CAAC","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { Integration, IntegrationStatus } from './types.js';\nimport { skillDirExists } from './probe.js';\n\nconst DOCS = 'https://github.com/Graphify-Labs/graphify';\n\n/**\n * Graphify builds a queryable knowledge graph in graphify-out/ and registers a Claude Code skill.\n * Documented install: `uv tool install graphifyy` (or pipx/pip), then `graphify install --project`.\n * DevWorkspace only detects it and tells the agent when to use it; it never re-implements graph building.\n */\nexport const graphify: Integration = {\n id: 'graphify',\n name: 'Graphify',\n optional: false,\n usage:\n 'For \"where is X / what depends on Y\" questions, query the Graphify graph first (graphify query \"<question>\", graphify path, graphify explain) ' +\n 'or use the /graphify skill. The graph is a navigation aid, not a source of truth: confirm in the actual files before relying on it.',\n async detect(ctx): Promise<IntegrationStatus> {\n const details: string[] = [];\n const remediation: string[] = [];\n const cli = await ctx.which('graphify');\n const skill = await skillDirExists(ctx, 'graphify');\n let graphBuilt = false;\n try {\n const st = await fs.stat(path.join(ctx.root, 'graphify-out', 'graph.json'));\n graphBuilt = st.isFile();\n if (graphBuilt) details.push(`graph built (graphify-out/graph.json, updated ${st.mtime.toISOString().slice(0, 10)})`);\n } catch {\n /* not built */\n }\n if (cli) details.push('graphify CLI on PATH');\n if (skill) details.push(`Claude skill installed (${skill})`);\n\n let state: IntegrationStatus['state'];\n if ((cli || skill) && graphBuilt) state = 'READY';\n else if (cli || skill) {\n state = 'PARTIAL';\n details.push('no graph built yet');\n remediation.push('In Claude Code run: /graphify . (builds graphify-out/graph.json)');\n } else if (graphBuilt) {\n state = 'PARTIAL';\n remediation.push('Install the CLI: uv tool install graphifyy (or pipx install graphifyy), then: graphify install --project');\n } else {\n state = 'NOT_DETECTED';\n remediation.push('Install: uv tool install graphifyy (or pipx install graphifyy)', 'Register for this project: graphify install --project', 'Then in Claude Code run: /graphify .');\n }\n return { id: 'graphify', name: 'Graphify', optional: false, state, details, remediation, docsUrl: DOCS };\n },\n};\n"]}
@@ -1,7 +0,0 @@
1
- import type { Integration } from './types.js';
2
- /**
3
- * OmniRoute (model routing) is OPTIONAL and outside the V1 execution path.
4
- * This adapter only reports whether an `omniroute` executable exists so a future provider
5
- * boundary has somewhere to plug in. Nothing in DevWorkspace requires it, API keys, or model configuration.
6
- */
7
- export declare const omniroute: Integration;
@@ -1,24 +0,0 @@
1
- /**
2
- * OmniRoute (model routing) is OPTIONAL and outside the V1 execution path.
3
- * This adapter only reports whether an `omniroute` executable exists so a future provider
4
- * boundary has somewhere to plug in. Nothing in DevWorkspace requires it, API keys, or model configuration.
5
- */
6
- export const omniroute = {
7
- id: 'omniroute',
8
- name: 'OmniRoute',
9
- optional: true,
10
- usage: 'Not used by DevWorkspace V1.',
11
- async detect(ctx) {
12
- const exe = await ctx.which('omniroute');
13
- return {
14
- id: 'omniroute',
15
- name: 'OmniRoute',
16
- optional: true,
17
- state: exe ? 'PARTIAL' : 'NOT_DETECTED',
18
- details: exe ? ['executable found; not used by V1'] : ['optional; not required'],
19
- remediation: [],
20
- docsUrl: 'https://github.com/diegosouzapw/OmniRoute',
21
- };
22
- },
23
- };
24
- //# sourceMappingURL=omniroute.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"omniroute.js","sourceRoot":"","sources":["../../src/integrations/omniroute.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAgB;IACpC,EAAE,EAAE,WAAW;IACf,IAAI,EAAE,WAAW;IACjB,QAAQ,EAAE,IAAI;IACd,KAAK,EAAE,8BAA8B;IACrC,KAAK,CAAC,MAAM,CAAC,GAAG;QACd,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACzC,OAAO;YACL,EAAE,EAAE,WAAW;YACf,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc;YACvC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC;YAChF,WAAW,EAAE,EAAE;YACf,OAAO,EAAE,2CAA2C;SACrD,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import type { Integration, IntegrationStatus } from './types.js';\n\n/**\n * OmniRoute (model routing) is OPTIONAL and outside the V1 execution path.\n * This adapter only reports whether an `omniroute` executable exists so a future provider\n * boundary has somewhere to plug in. Nothing in DevWorkspace requires it, API keys, or model configuration.\n */\nexport const omniroute: Integration = {\n id: 'omniroute',\n name: 'OmniRoute',\n optional: true,\n usage: 'Not used by DevWorkspace V1.',\n async detect(ctx): Promise<IntegrationStatus> {\n const exe = await ctx.which('omniroute');\n return {\n id: 'omniroute',\n name: 'OmniRoute',\n optional: true,\n state: exe ? 'PARTIAL' : 'NOT_DETECTED',\n details: exe ? ['executable found; not used by V1'] : ['optional; not required'],\n remediation: [],\n docsUrl: 'https://github.com/diegosouzapw/OmniRoute',\n };\n },\n};\n"]}
@@ -1,10 +0,0 @@
1
- import type { Integration } from './types.js';
2
- /**
3
- * Ponytail is a code-quality/simplification skill. Documented install for Claude Code:
4
- * /plugin marketplace add DietrichGebert/ponytail
5
- * /plugin install ponytail@ponytail
6
- * Commands: /ponytail [lite|full|ultra|off], /ponytail-review, /ponytail-audit, /ponytail-debt.
7
- * Other agents: copy AGENTS.md or install skills/ponytail/SKILL.md. Optional config: ~/.config/ponytail/config.json.
8
- * Ponytail assists quality review; it is never a substitute for tests.
9
- */
10
- export declare const ponytail: Integration;
@@ -1,58 +0,0 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import { claudeConfigMentions, skillDirExists } from './probe.js';
4
- import { pathExists } from '../utils/fs.js';
5
- const DOCS = 'https://github.com/DietrichGebert/ponytail';
6
- /**
7
- * Ponytail is a code-quality/simplification skill. Documented install for Claude Code:
8
- * /plugin marketplace add DietrichGebert/ponytail
9
- * /plugin install ponytail@ponytail
10
- * Commands: /ponytail [lite|full|ultra|off], /ponytail-review, /ponytail-audit, /ponytail-debt.
11
- * Other agents: copy AGENTS.md or install skills/ponytail/SKILL.md. Optional config: ~/.config/ponytail/config.json.
12
- * Ponytail assists quality review; it is never a substitute for tests.
13
- */
14
- export const ponytail = {
15
- id: 'ponytail',
16
- name: 'Ponytail',
17
- optional: false,
18
- usage: 'Use /ponytail-review on the diff of meaningful changes (features, refactors, security work) to catch unnecessary complexity and debt; ' +
19
- 'use /ponytail-audit only when the user asks for a repository-wide quality pass. Quality review never replaces running tests.',
20
- async detect(ctx) {
21
- const details = [];
22
- const plugin = await claudeConfigMentions(ctx, 'ponytail');
23
- const skill = await skillDirExists(ctx, 'ponytail');
24
- if (plugin)
25
- details.push(`referenced in Claude Code config (${plugin})`);
26
- if (skill)
27
- details.push(`skill installed (${skill})`);
28
- let agentsMention = false;
29
- try {
30
- agentsMention = (await fs.readFile(path.join(ctx.root, 'AGENTS.md'), 'utf8')).toLowerCase().includes('ponytail');
31
- }
32
- catch {
33
- /* no AGENTS.md */
34
- }
35
- if (agentsMention)
36
- details.push('AGENTS.md references Ponytail');
37
- const userCfg = path.join(ctx.home, '.config', 'ponytail', 'config.json');
38
- if (await pathExists(userCfg))
39
- details.push('user config present (~/.config/ponytail/config.json)');
40
- const found = plugin || skill || agentsMention;
41
- return {
42
- id: 'ponytail',
43
- name: 'Ponytail',
44
- optional: false,
45
- state: found ? 'READY' : 'UNVERIFIED',
46
- details: found ? details : ['not found in Claude Code settings or project skills; plugin state is held by Claude Code so this check is best-effort'],
47
- remediation: found
48
- ? []
49
- : [
50
- 'In Claude Code run: /plugin marketplace add DietrichGebert/ponytail',
51
- 'Then: /plugin install ponytail@ponytail',
52
- 'Other agents: copy Ponytail\'s AGENTS.md into the project (see its INSTALL.md).',
53
- ],
54
- docsUrl: DOCS,
55
- };
56
- },
57
- };
58
- //# sourceMappingURL=ponytail.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ponytail.js","sourceRoot":"","sources":["../../src/integrations/ponytail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,IAAI,GAAG,4CAA4C,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,EAAE,EAAE,UAAU;IACd,IAAI,EAAE,UAAU;IAChB,QAAQ,EAAE,KAAK;IACf,KAAK,EACH,wIAAwI;QACxI,8HAA8H;IAChI,KAAK,CAAC,MAAM,CAAC,GAAG;QACd,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACpD,IAAI,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,qCAAqC,MAAM,GAAG,CAAC,CAAC;QACzE,IAAI,KAAK;YAAE,OAAO,CAAC,IAAI,CAAC,oBAAoB,KAAK,GAAG,CAAC,CAAC;QACtD,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC;YACH,aAAa,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACnH,CAAC;QAAC,MAAM,CAAC;YACP,kBAAkB;QACpB,CAAC;QACD,IAAI,aAAa;YAAE,OAAO,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;QAC1E,IAAI,MAAM,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;QAEpG,MAAM,KAAK,GAAG,MAAM,IAAI,KAAK,IAAI,aAAa,CAAC;QAC/C,OAAO;YACL,EAAE,EAAE,UAAU;YACd,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY;YACrC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,uHAAuH,CAAC;YACpJ,WAAW,EAAE,KAAK;gBAChB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACE,qEAAqE;oBACrE,yCAAyC;oBACzC,iFAAiF;iBAClF;YACL,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { Integration, IntegrationStatus } from './types.js';\nimport { claudeConfigMentions, skillDirExists } from './probe.js';\nimport { pathExists } from '../utils/fs.js';\n\nconst DOCS = 'https://github.com/DietrichGebert/ponytail';\n\n/**\n * Ponytail is a code-quality/simplification skill. Documented install for Claude Code:\n * /plugin marketplace add DietrichGebert/ponytail\n * /plugin install ponytail@ponytail\n * Commands: /ponytail [lite|full|ultra|off], /ponytail-review, /ponytail-audit, /ponytail-debt.\n * Other agents: copy AGENTS.md or install skills/ponytail/SKILL.md. Optional config: ~/.config/ponytail/config.json.\n * Ponytail assists quality review; it is never a substitute for tests.\n */\nexport const ponytail: Integration = {\n id: 'ponytail',\n name: 'Ponytail',\n optional: false,\n usage:\n 'Use /ponytail-review on the diff of meaningful changes (features, refactors, security work) to catch unnecessary complexity and debt; ' +\n 'use /ponytail-audit only when the user asks for a repository-wide quality pass. Quality review never replaces running tests.',\n async detect(ctx): Promise<IntegrationStatus> {\n const details: string[] = [];\n const plugin = await claudeConfigMentions(ctx, 'ponytail');\n const skill = await skillDirExists(ctx, 'ponytail');\n if (plugin) details.push(`referenced in Claude Code config (${plugin})`);\n if (skill) details.push(`skill installed (${skill})`);\n let agentsMention = false;\n try {\n agentsMention = (await fs.readFile(path.join(ctx.root, 'AGENTS.md'), 'utf8')).toLowerCase().includes('ponytail');\n } catch {\n /* no AGENTS.md */\n }\n if (agentsMention) details.push('AGENTS.md references Ponytail');\n const userCfg = path.join(ctx.home, '.config', 'ponytail', 'config.json');\n if (await pathExists(userCfg)) details.push('user config present (~/.config/ponytail/config.json)');\n\n const found = plugin || skill || agentsMention;\n return {\n id: 'ponytail',\n name: 'Ponytail',\n optional: false,\n state: found ? 'READY' : 'UNVERIFIED',\n details: found ? details : ['not found in Claude Code settings or project skills; plugin state is held by Claude Code so this check is best-effort'],\n remediation: found\n ? []\n : [\n 'In Claude Code run: /plugin marketplace add DietrichGebert/ponytail',\n 'Then: /plugin install ponytail@ponytail',\n 'Other agents: copy Ponytail\\'s AGENTS.md into the project (see its INSTALL.md).',\n ],\n docsUrl: DOCS,\n };\n },\n};\n"]}
@@ -1,6 +0,0 @@
1
- import type { IntegrationContext } from './types.js';
2
- /** Candidate Claude Code settings/plugin registries, project first then user. Read-only and best effort. */
3
- export declare function claudeConfigFiles(ctx: IntegrationContext): string[];
4
- /** True if any Claude Code config file mentions the needle (case-insensitive). Plugin install state belongs to Claude Code, so this can only suggest, never prove. */
5
- export declare function claudeConfigMentions(ctx: IntegrationContext, needle: string): Promise<string | null>;
6
- export declare function skillDirExists(ctx: IntegrationContext, name: string): Promise<string | null>;
@@ -1,41 +0,0 @@
1
- import { promises as fs } from 'node:fs';
2
- import path from 'node:path';
3
- import { pathExists } from '../utils/fs.js';
4
- /** Candidate Claude Code settings/plugin registries, project first then user. Read-only and best effort. */
5
- export function claudeConfigFiles(ctx) {
6
- return [
7
- path.join(ctx.root, '.claude', 'settings.json'),
8
- path.join(ctx.root, '.claude', 'settings.local.json'),
9
- path.join(ctx.home, '.claude', 'settings.json'),
10
- path.join(ctx.home, '.claude', 'plugins', 'installed_plugins.json'),
11
- path.join(ctx.home, '.claude', 'plugins', 'known_marketplaces.json'),
12
- ];
13
- }
14
- /** True if any Claude Code config file mentions the needle (case-insensitive). Plugin install state belongs to Claude Code, so this can only suggest, never prove. */
15
- export async function claudeConfigMentions(ctx, needle) {
16
- const n = needle.toLowerCase();
17
- for (const file of claudeConfigFiles(ctx)) {
18
- try {
19
- const st = await fs.stat(file);
20
- if (!st.isFile() || st.size > 2 * 1024 * 1024)
21
- continue;
22
- if ((await fs.readFile(file, 'utf8')).toLowerCase().includes(n)) {
23
- return file.startsWith(ctx.root) ? path.relative(ctx.root, file).replace(/\\/g, '/') : '~/' + path.relative(ctx.home, file).replace(/\\/g, '/');
24
- }
25
- }
26
- catch {
27
- /* missing or unreadable */
28
- }
29
- }
30
- return null;
31
- }
32
- export async function skillDirExists(ctx, name) {
33
- const project = path.join(ctx.root, '.claude', 'skills', name);
34
- if (await pathExists(project))
35
- return `.claude/skills/${name}`;
36
- const user = path.join(ctx.home, '.claude', 'skills', name);
37
- if (await pathExists(user))
38
- return `~/.claude/skills/${name}`;
39
- return null;
40
- }
41
- //# sourceMappingURL=probe.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"probe.js","sourceRoot":"","sources":["../../src/integrations/probe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAG5C,4GAA4G;AAC5G,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,OAAO;QACL,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,CAAC;QACrD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,wBAAwB,CAAC;QACnE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,yBAAyB,CAAC;KACrE,CAAC;AACJ,CAAC;AAED,sKAAsK;AACtK,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,GAAuB,EAAE,MAAc;IAChF,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI;gBAAE,SAAS;YACxD,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChE,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAClJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAuB,EAAE,IAAY;IACxE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC/D,IAAI,MAAM,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,kBAAkB,IAAI,EAAE,CAAC;IAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC5D,IAAI,MAAM,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,oBAAoB,IAAI,EAAE,CAAC;IAC9D,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { pathExists } from '../utils/fs.js';\nimport type { IntegrationContext } from './types.js';\n\n/** Candidate Claude Code settings/plugin registries, project first then user. Read-only and best effort. */\nexport function claudeConfigFiles(ctx: IntegrationContext): string[] {\n return [\n path.join(ctx.root, '.claude', 'settings.json'),\n path.join(ctx.root, '.claude', 'settings.local.json'),\n path.join(ctx.home, '.claude', 'settings.json'),\n path.join(ctx.home, '.claude', 'plugins', 'installed_plugins.json'),\n path.join(ctx.home, '.claude', 'plugins', 'known_marketplaces.json'),\n ];\n}\n\n/** True if any Claude Code config file mentions the needle (case-insensitive). Plugin install state belongs to Claude Code, so this can only suggest, never prove. */\nexport async function claudeConfigMentions(ctx: IntegrationContext, needle: string): Promise<string | null> {\n const n = needle.toLowerCase();\n for (const file of claudeConfigFiles(ctx)) {\n try {\n const st = await fs.stat(file);\n if (!st.isFile() || st.size > 2 * 1024 * 1024) continue;\n if ((await fs.readFile(file, 'utf8')).toLowerCase().includes(n)) {\n return file.startsWith(ctx.root) ? path.relative(ctx.root, file).replace(/\\\\/g, '/') : '~/' + path.relative(ctx.home, file).replace(/\\\\/g, '/');\n }\n } catch {\n /* missing or unreadable */\n }\n }\n return null;\n}\n\nexport async function skillDirExists(ctx: IntegrationContext, name: string): Promise<string | null> {\n const project = path.join(ctx.root, '.claude', 'skills', name);\n if (await pathExists(project)) return `.claude/skills/${name}`;\n const user = path.join(ctx.home, '.claude', 'skills', name);\n if (await pathExists(user)) return `~/.claude/skills/${name}`;\n return null;\n}\n"]}