devworkspace 0.1.1 → 0.2.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 +35 -0
- package/README.md +15 -2
- package/dist/agents/claude/content.js +3 -3
- package/dist/agents/claude/content.js.map +1 -1
- package/dist/cli/args.d.ts +19 -0
- package/dist/cli/args.js +6 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/help.js +40 -5
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/render.d.ts +7 -0
- package/dist/cli/render.js +104 -17
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/run.d.ts +6 -0
- package/dist/cli/run.js +65 -3
- package/dist/cli/run.js.map +1 -1
- package/dist/config/schemas.d.ts +7 -1
- package/dist/config/schemas.js +10 -0
- package/dist/config/schemas.js.map +1 -1
- package/dist/core/workspace.js +2 -1
- package/dist/core/workspace.js.map +1 -1
- package/dist/discovery/commands.d.ts +34 -3
- package/dist/discovery/commands.js +95 -33
- package/dist/discovery/commands.js.map +1 -1
- package/dist/discovery/detect.d.ts +17 -0
- package/dist/discovery/detect.js +101 -42
- package/dist/discovery/detect.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/adapters/agent-skills.d.ts +8 -0
- package/dist/integrations/adapters/agent-skills.js +25 -0
- package/dist/integrations/adapters/agent-skills.js.map +1 -0
- package/dist/integrations/adapters/claudePlugin.d.ts +41 -0
- package/dist/integrations/adapters/claudePlugin.js +129 -0
- package/dist/integrations/adapters/claudePlugin.js.map +1 -0
- package/dist/integrations/adapters/graphify.d.ts +2 -0
- package/dist/integrations/adapters/graphify.js +277 -0
- package/dist/integrations/adapters/graphify.js.map +1 -0
- package/dist/integrations/adapters/omniroute.d.ts +6 -0
- package/dist/integrations/adapters/omniroute.js +32 -0
- package/dist/integrations/adapters/omniroute.js.map +1 -0
- package/dist/integrations/adapters/pluginSkill.d.ts +28 -0
- package/dist/integrations/adapters/pluginSkill.js +195 -0
- package/dist/integrations/adapters/pluginSkill.js.map +1 -0
- package/dist/integrations/adapters/ponytail.d.ts +8 -0
- package/dist/integrations/adapters/ponytail.js +33 -0
- package/dist/integrations/adapters/ponytail.js.map +1 -0
- package/dist/integrations/exec.d.ts +26 -0
- package/dist/integrations/exec.js +167 -0
- package/dist/integrations/exec.js.map +1 -0
- package/dist/integrations/index.d.ts +5 -6
- package/dist/integrations/index.js +3 -29
- package/dist/integrations/index.js.map +1 -1
- package/dist/integrations/manager.d.ts +62 -0
- package/dist/integrations/manager.js +261 -0
- package/dist/integrations/manager.js.map +1 -0
- package/dist/integrations/notices.d.ts +13 -0
- package/dist/integrations/notices.js +68 -0
- package/dist/integrations/notices.js.map +1 -0
- package/dist/integrations/persistentPath.d.ts +20 -0
- package/dist/integrations/persistentPath.js +47 -0
- package/dist/integrations/persistentPath.js.map +1 -0
- package/dist/integrations/protect.d.ts +20 -0
- package/dist/integrations/protect.js +131 -0
- package/dist/integrations/protect.js.map +1 -0
- package/dist/integrations/state.d.ts +10 -0
- package/dist/integrations/state.js +81 -0
- package/dist/integrations/state.js.map +1 -0
- package/dist/integrations/types.d.ts +139 -16
- package/dist/integrations/types.js +13 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/prompts/onboarding.d.ts +3 -3
- package/dist/prompts/onboarding.js +9 -8
- package/dist/prompts/onboarding.js.map +1 -1
- package/dist/services/analysis.d.ts +15 -3
- package/dist/services/analysis.js +21 -23
- package/dist/services/analysis.js.map +1 -1
- package/dist/services/common.d.ts +8 -5
- package/dist/services/common.js +2 -5
- package/dist/services/common.js.map +1 -1
- package/dist/services/doctor.d.ts +10 -0
- package/dist/services/doctor.js +87 -19
- package/dist/services/doctor.js.map +1 -1
- package/dist/services/init.d.ts +9 -2
- package/dist/services/init.js +10 -7
- package/dist/services/init.js.map +1 -1
- package/dist/services/integrations.d.ts +26 -0
- package/dist/services/integrations.js +35 -0
- package/dist/services/integrations.js.map +1 -0
- package/dist/services/refresh.js +1 -1
- package/dist/services/refresh.js.map +1 -1
- package/dist/services/status.d.ts +4 -2
- package/dist/services/status.js +4 -4
- package/dist/services/status.js.map +1 -1
- package/dist/utils/lock.d.ts +2 -0
- package/dist/utils/lock.js +2 -2
- package/dist/utils/lock.js.map +1 -1
- package/dist/utils/proc.d.ts +8 -1
- package/dist/utils/proc.js +31 -8
- package/dist/utils/proc.js.map +1 -1
- package/docs/architecture.md +1 -1
- package/docs/claude.md +4 -0
- package/docs/getting-started.md +2 -2
- package/docs/integrations.md +98 -33
- package/docs/security.md +5 -1
- package/docs/testing.md +6 -0
- package/docs/troubleshooting.md +11 -1
- package/package.json +1 -1
- package/dist/integrations/agent-skills.d.ts +0 -10
- package/dist/integrations/agent-skills.js +0 -45
- package/dist/integrations/agent-skills.js.map +0 -1
- package/dist/integrations/graphify.d.ts +0 -7
- package/dist/integrations/graphify.js +0 -54
- package/dist/integrations/graphify.js.map +0 -1
- package/dist/integrations/omniroute.d.ts +0 -7
- package/dist/integrations/omniroute.js +0 -24
- package/dist/integrations/omniroute.js.map +0 -1
- package/dist/integrations/ponytail.d.ts +0 -10
- package/dist/integrations/ponytail.js +0 -58
- package/dist/integrations/ponytail.js.map +0 -1
- package/dist/integrations/probe.d.ts +0 -6
- package/dist/integrations/probe.js +0 -41
- package/dist/integrations/probe.js.map +0 -1
package/dist/utils/lock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/utils/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/utils/lock.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs, unlinkSync } from 'node:fs';\nimport path from 'node:path';\nimport { DevWorkspaceError } from '../errors/index.js';\nimport { ensureDir } from './fs.js';\nimport { onCleanup } from './cleanup.js';\n\nexport interface LockOptions {\n timeoutMs?: number;\n staleMs?: number;\n /** Lock file name under .devworkspace/local/. Long-running operations use their own lock. */\n name?: string;\n}\n\nfunction pidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (e) {\n return (e as NodeJS.ErrnoException).code === 'EPERM';\n }\n}\n\n/** Exclusive advisory lock stored under .devworkspace/local/. Stale locks (dead pid or too old) are broken. */\nexport async function withLock<T>(workspaceDir: string, fn: () => Promise<T>, opts: LockOptions = {}): Promise<T> {\n const timeoutMs = opts.timeoutMs ?? 5000;\n const staleMs = opts.staleMs ?? 60_000;\n const dir = path.join(workspaceDir, 'local');\n const lockPath = path.join(dir, opts.name ?? 'workspace.lock');\n await ensureDir(dir);\n const started = Date.now();\n for (;;) {\n try {\n const fh = await fs.open(lockPath, 'wx');\n await fh.writeFile(JSON.stringify({ pid: process.pid, at: Date.now() }));\n await fh.close();\n break;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code !== 'EEXIST') {\n throw new DevWorkspaceError('IO', 'Could not acquire the workspace lock.', { cause: e });\n }\n let stale: boolean;\n try {\n const info = JSON.parse(await fs.readFile(lockPath, 'utf8')) as { pid?: number; at?: number };\n const age = Date.now() - (info.at ?? 0);\n stale = age > staleMs || (typeof info.pid === 'number' && !pidAlive(info.pid));\n } catch {\n // Unreadable lock: another process may be mid-write, so only break it once it is old.\n try {\n stale = Date.now() - (await fs.stat(lockPath)).mtimeMs > 2000;\n } catch {\n stale = true;\n }\n }\n if (stale) {\n await fs.rm(lockPath, { force: true });\n continue;\n }\n if (Date.now() - started > timeoutMs) {\n throw new DevWorkspaceError('LOCKED', 'Another DevWorkspace process is modifying this workspace.', {\n hint: `Wait for it to finish, or delete ${path.join('.devworkspace', 'local', opts.name ?? 'workspace.lock')} if no process is running.`,\n });\n }\n await new Promise((r) => setTimeout(r, 50));\n }\n }\n const dispose = onCleanup(() => {\n try {\n unlinkSync(lockPath);\n } catch {\n /* already gone */\n }\n });\n try {\n return await fn();\n } finally {\n dispose();\n await fs.rm(lockPath, { force: true }).catch(() => undefined);\n }\n}\n"]}
|
package/dist/utils/proc.d.ts
CHANGED
|
@@ -4,12 +4,19 @@ export interface RunResult {
|
|
|
4
4
|
stdout: string;
|
|
5
5
|
stderr: string;
|
|
6
6
|
timedOut: boolean;
|
|
7
|
+
aborted?: boolean;
|
|
7
8
|
error?: string;
|
|
8
9
|
}
|
|
9
10
|
export interface RunOptions {
|
|
10
11
|
cwd?: string;
|
|
11
12
|
timeoutMs?: number;
|
|
12
13
|
maxBytes?: number;
|
|
14
|
+
/** Extra environment variables merged over process.env (undefined values unset the variable). */
|
|
15
|
+
env?: Record<string, string | undefined>;
|
|
16
|
+
/** Abort (kill) the process when the signal fires. */
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
/** Windows only: pass the argument string through unmodified (used for cmd.exe /c with pre-validated arguments). */
|
|
19
|
+
windowsVerbatimArguments?: boolean;
|
|
13
20
|
}
|
|
14
21
|
/**
|
|
15
22
|
* Run an executable with an argument array. Never uses a shell, so project- or
|
|
@@ -18,5 +25,5 @@ export interface RunOptions {
|
|
|
18
25
|
export declare function run(command: string, args: string[], opts?: RunOptions): Promise<RunResult>;
|
|
19
26
|
/** Locate an executable on PATH (honouring PATHEXT on Windows) without executing anything. */
|
|
20
27
|
export declare function which(name: string, env?: NodeJS.ProcessEnv): Promise<string | null>;
|
|
21
|
-
/** .cmd/.bat shims need a shell on Windows
|
|
28
|
+
/** .cmd/.bat shims need a shell on Windows. They are only run through the validated path in integrations/exec.ts. */
|
|
22
29
|
export declare function isShellShim(file: string): boolean;
|
package/dist/utils/proc.js
CHANGED
|
@@ -12,39 +12,62 @@ export function run(command, args, opts = {}) {
|
|
|
12
12
|
let stdout = '';
|
|
13
13
|
let stderr = '';
|
|
14
14
|
let timedOut = false;
|
|
15
|
+
let aborted = false;
|
|
15
16
|
let settled = false;
|
|
16
17
|
// eslint-disable-next-line prefer-const -- assigned after spawn; finish() may run first if spawn throws
|
|
17
18
|
let timer;
|
|
19
|
+
const onAbort = () => {
|
|
20
|
+
aborted = true;
|
|
21
|
+
child?.kill();
|
|
22
|
+
};
|
|
18
23
|
const finish = (r) => {
|
|
19
24
|
if (settled)
|
|
20
25
|
return;
|
|
21
26
|
settled = true;
|
|
22
27
|
if (timer)
|
|
23
28
|
clearTimeout(timer);
|
|
24
|
-
|
|
29
|
+
opts.signal?.removeEventListener('abort', onAbort);
|
|
30
|
+
resolve(aborted ? { ...r, ok: false, aborted: true } : r);
|
|
25
31
|
};
|
|
26
32
|
let child;
|
|
33
|
+
if (opts.signal?.aborted) {
|
|
34
|
+
finish({ ok: false, code: null, stdout, stderr, timedOut: false, aborted: true, error: 'aborted' });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
27
37
|
try {
|
|
28
|
-
|
|
38
|
+
const env = opts.env ? { ...process.env, ...opts.env } : process.env;
|
|
39
|
+
for (const [k, v] of Object.entries(env))
|
|
40
|
+
if (v === undefined)
|
|
41
|
+
delete env[k];
|
|
42
|
+
child = spawn(command, args, {
|
|
43
|
+
cwd: opts.cwd,
|
|
44
|
+
env,
|
|
45
|
+
shell: false,
|
|
46
|
+
windowsHide: true,
|
|
47
|
+
windowsVerbatimArguments: opts.windowsVerbatimArguments,
|
|
48
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
49
|
+
});
|
|
29
50
|
}
|
|
30
51
|
catch (e) {
|
|
31
52
|
finish({ ok: false, code: null, stdout, stderr, timedOut: false, error: e.message });
|
|
32
53
|
return;
|
|
33
54
|
}
|
|
55
|
+
const c = child;
|
|
34
56
|
timer = setTimeout(() => {
|
|
35
57
|
timedOut = true;
|
|
36
|
-
|
|
58
|
+
c.kill();
|
|
37
59
|
}, timeoutMs);
|
|
38
|
-
|
|
60
|
+
opts.signal?.addEventListener('abort', onAbort, { once: true });
|
|
61
|
+
c.stdout?.on('data', (d) => {
|
|
39
62
|
if (stdout.length < maxBytes)
|
|
40
63
|
stdout += d.toString('utf8');
|
|
41
64
|
});
|
|
42
|
-
|
|
65
|
+
c.stderr?.on('data', (d) => {
|
|
43
66
|
if (stderr.length < maxBytes)
|
|
44
67
|
stderr += d.toString('utf8');
|
|
45
68
|
});
|
|
46
|
-
|
|
47
|
-
|
|
69
|
+
c.on('error', (e) => finish({ ok: false, code: null, stdout, stderr, timedOut, error: e.message }));
|
|
70
|
+
c.on('close', (code) => finish({ ok: code === 0 && !timedOut && !aborted, code, stdout, stderr, timedOut }));
|
|
48
71
|
});
|
|
49
72
|
}
|
|
50
73
|
/** Locate an executable on PATH (honouring PATHEXT on Windows) without executing anything. */
|
|
@@ -67,7 +90,7 @@ export async function which(name, env = process.env) {
|
|
|
67
90
|
}
|
|
68
91
|
return null;
|
|
69
92
|
}
|
|
70
|
-
/** .cmd/.bat shims need a shell on Windows
|
|
93
|
+
/** .cmd/.bat shims need a shell on Windows. They are only run through the validated path in integrations/exec.ts. */
|
|
71
94
|
export function isShellShim(file) {
|
|
72
95
|
return /\.(cmd|bat)$/i.test(file);
|
|
73
96
|
}
|
package/dist/utils/proc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proc.js","sourceRoot":"","sources":["../../src/utils/proc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"proc.js","sourceRoot":"","sources":["../../src/utils/proc.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nexport interface RunResult {\n ok: boolean;\n code: number | null;\n stdout: string;\n stderr: string;\n timedOut: boolean;\n aborted?: boolean;\n error?: string;\n}\n\nexport interface RunOptions {\n cwd?: string;\n timeoutMs?: number;\n maxBytes?: number;\n /** Extra environment variables merged over process.env (undefined values unset the variable). */\n env?: Record<string, string | undefined>;\n /** Abort (kill) the process when the signal fires. */\n signal?: AbortSignal;\n /** Windows only: pass the argument string through unmodified (used for cmd.exe /c with pre-validated arguments). */\n windowsVerbatimArguments?: boolean;\n}\n\n/**\n * Run an executable with an argument array. Never uses a shell, so project- or\n * user-supplied values cannot be interpreted as shell syntax.\n */\nexport function run(command: string, args: string[], opts: RunOptions = {}): Promise<RunResult> {\n const timeoutMs = opts.timeoutMs ?? 15_000;\n const maxBytes = opts.maxBytes ?? 4 * 1024 * 1024;\n return new Promise((resolve) => {\n let stdout = '';\n let stderr = '';\n let timedOut = false;\n let aborted = false;\n let settled = false;\n // eslint-disable-next-line prefer-const -- assigned after spawn; finish() may run first if spawn throws\n let timer: NodeJS.Timeout | undefined;\n const onAbort = (): void => {\n aborted = true;\n child?.kill();\n };\n const finish = (r: RunResult): void => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n opts.signal?.removeEventListener('abort', onAbort);\n resolve(aborted ? { ...r, ok: false, aborted: true } : r);\n };\n let child: ReturnType<typeof spawn> | undefined;\n if (opts.signal?.aborted) {\n finish({ ok: false, code: null, stdout, stderr, timedOut: false, aborted: true, error: 'aborted' });\n return;\n }\n try {\n const env = opts.env ? { ...process.env, ...opts.env } : process.env;\n for (const [k, v] of Object.entries(env)) if (v === undefined) delete env[k];\n child = spawn(command, args, {\n cwd: opts.cwd,\n env,\n shell: false,\n windowsHide: true,\n windowsVerbatimArguments: opts.windowsVerbatimArguments,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n } catch (e) {\n finish({ ok: false, code: null, stdout, stderr, timedOut: false, error: (e as Error).message });\n return;\n }\n const c = child;\n timer = setTimeout(() => {\n timedOut = true;\n c.kill();\n }, timeoutMs);\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n c.stdout?.on('data', (d: Buffer) => {\n if (stdout.length < maxBytes) stdout += d.toString('utf8');\n });\n c.stderr?.on('data', (d: Buffer) => {\n if (stderr.length < maxBytes) stderr += d.toString('utf8');\n });\n c.on('error', (e) => finish({ ok: false, code: null, stdout, stderr, timedOut, error: e.message }));\n c.on('close', (code) => finish({ ok: code === 0 && !timedOut && !aborted, code, stdout, stderr, timedOut }));\n });\n}\n\n/** Locate an executable on PATH (honouring PATHEXT on Windows) without executing anything. */\nexport async function which(name: string, env: NodeJS.ProcessEnv = process.env): Promise<string | null> {\n const isWin = process.platform === 'win32';\n const pathVar = env.PATH ?? env.Path ?? '';\n const exts = isWin ? (env.PATHEXT ?? '.EXE;.CMD;.BAT;.COM').split(';').filter(Boolean) : [''];\n for (const dir of pathVar.split(path.delimiter).filter(Boolean)) {\n for (const ext of isWin ? ['', ...exts] : exts) {\n const candidate = path.join(dir, name + ext);\n try {\n const st = await fs.stat(candidate);\n if (st.isFile()) return candidate;\n } catch {\n /* keep looking */\n }\n }\n }\n return null;\n}\n\n/** .cmd/.bat shims need a shell on Windows. They are only run through the validated path in integrations/exec.ts. */\nexport function isShellShim(file: string): boolean {\n return /\\.(cmd|bat)$/i.test(file);\n}\n"]}
|
package/docs/architecture.md
CHANGED
|
@@ -26,7 +26,7 @@ The CLI contains no business logic. `src/index.ts` exports the services so a fut
|
|
|
26
26
|
| `decisions/`, `sessions/` | Append-only decision records; short session summaries |
|
|
27
27
|
| `security/` | Sensitive-file rules, secret detection/redaction, safe reading |
|
|
28
28
|
| `git/` | Porcelain parsing and state (no mutating Git commands anywhere) |
|
|
29
|
-
| `integrations/` |
|
|
29
|
+
| `integrations/` | Integration manager: one `IntegrationAdapter` per tool (observe, plan, verify), consent levels, file protection, state, runner abstraction (Windows shims, npx) |
|
|
30
30
|
| `agents/` | `AgentAdapter` interface + the Claude adapter (managed `CLAUDE.md` block, skill) |
|
|
31
31
|
| `prompts/` | Onboarding/refresh prompt builders and the behavioural requirement checker |
|
|
32
32
|
| `portability/` | Export bundle format and hostile-input validation |
|
package/docs/claude.md
CHANGED
|
@@ -41,6 +41,10 @@ DevWorkspace records what it manages in `project.json` → `managedFiles` (`owne
|
|
|
41
41
|
- Never claim completion while required checks fail; report `STATUS: BLOCKED` plainly.
|
|
42
42
|
- After meaningful work, record only durable knowledge.
|
|
43
43
|
|
|
44
|
+
## Integrations
|
|
45
|
+
|
|
46
|
+
Onboarding tells Claude to run `devworkspace setup --integrations` (after asking you once) rather than installing tools by hand, so installs are previewed, consent-gated, protected and verified the same way whether you or Claude run them. See [integrations.md](integrations.md).
|
|
47
|
+
|
|
44
48
|
## Keeping Claude-specific code isolated
|
|
45
49
|
|
|
46
50
|
Everything Claude-specific lives in `src/agents/claude/`. Core code talks to the `AgentAdapter` interface (`detectExisting`, `plan`), so a Cursor/Codex/Gemini adapter is a new directory implementing the same interface, not a change to core.
|
package/docs/getting-started.md
CHANGED
|
@@ -41,7 +41,7 @@ Open `.devworkspace/analysis/onboarding-prompt.md` and paste it into Claude Code
|
|
|
41
41
|
3. run `devworkspace agent install` (adds a small managed block to `CLAUDE.md` and installs the `devworkspace` skill, preserving anything you wrote),
|
|
42
42
|
4. write concise knowledge into `.devworkspace/context/`,
|
|
43
43
|
5. check the testing contract and record a baseline,
|
|
44
|
-
6.
|
|
44
|
+
6. run the integration manager (`devworkspace setup --integrations`) after asking you once; it installs and verifies Graphify, Agent Skills and Ponytail and reports precise statuses,
|
|
45
45
|
7. run `devworkspace doctor` and report unknowns and warnings.
|
|
46
46
|
|
|
47
47
|
It is told not to modify application source during onboarding.
|
|
@@ -52,7 +52,7 @@ It is told not to modify application source during onboarding.
|
|
|
52
52
|
npx devworkspace doctor
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
`READY` means the workspace is healthy, instructions are installed and architecture knowledge exists.
|
|
55
|
+
`Core workspace: READY` means the workspace is healthy, instructions are installed and architecture knowledge exists. Integrations are listed separately with their observed status; anything not `VERIFIED` comes with the exact next step and does not fail the command. Run `npx devworkspace setup --integrations --dry-run` to see what setup would do, and `--yes` to do it.
|
|
56
56
|
|
|
57
57
|
## 5. Work normally
|
|
58
58
|
|
package/docs/integrations.md
CHANGED
|
@@ -1,51 +1,116 @@
|
|
|
1
1
|
# Integrations
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
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
|
-
|
|
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
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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 it is not on this process's PATH the status is never a false success, and the advice depends on why: on **Windows**, DevWorkspace reads (never writes) the persistent user and machine PATH from the registry. If the folder is already there, the terminal or VS Code simply started before the change, so the status is `RESTART_REQUIRED` and the fix is to reopen the terminal or restart VS Code (no PATH edit). If it is missing from both, the status is `DEGRADED` with the folder to add. On macOS and Linux, or when the registry cannot be read, the persistent PATH is treated as unknown and the general advice is shown. Quick checks (`devworkspace status`) never query the registry.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
91
|
+
## Protection, idempotency and recovery
|
|
31
92
|
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
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
|
-
##
|
|
100
|
+
## Verified vs. assumed (as of 2026-10-09, Windows 11)
|
|
38
101
|
|
|
39
|
-
|
|
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
|
-
##
|
|
106
|
+
## Limitations
|
|
42
107
|
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
`required` is `yes` (always applies to code changes), `context` (only when relevant to the change) or `no`. Entries you or the agent edit by hand get `origin: "user"` and are never overwritten by later analysis.
|
|
17
17
|
|
|
18
|
+
Every `package.json` in the repository is read (not only the root; manifests in `fixtures/`, `examples/`, `docs/` and `node_modules` are ignored), and each package's commands are recorded **with the directory to run them in** (`cwd`, relative, POSIX), only for scripts that package actually defines. A backend `npm run test:unit` is never mixed up with a frontend `npm test`. Each package uses the package manager its own lockfile indicates. Commands are never executed by DevWorkspace.
|
|
19
|
+
|
|
20
|
+
Re-running `analyze` keeps any command with `origin: "user"` (confirmed by a person or by Claude during onboarding) exactly as written, even when a later analysis finds nothing; a user command with no `cwd` covers its whole check, one with a `cwd` covers only that directory. `discovery.json` always holds the pure detection; `commands.json` holds the merged contract.
|
|
21
|
+
|
|
18
22
|
Sources: `package.json` scripts (matched by common names), plus conventions for Python (pytest/ruff/mypy/black/alembic), Go, Rust, Maven and Gradle. npm's default `"no test specified"` placeholder is ignored.
|
|
19
23
|
|
|
20
24
|
### Commands are untrusted input
|
|
@@ -53,6 +57,8 @@ npm run smoke # pack → install tarball into clean dirs → run the
|
|
|
53
57
|
npm run release:check # the full pre-publish gate; never publishes
|
|
54
58
|
```
|
|
55
59
|
|
|
60
|
+
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.
|
|
61
|
+
|
|
56
62
|
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
63
|
|
|
58
64
|
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`.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -8,8 +8,16 @@ 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 `RESTART_REQUIRED`: "on your user PATH ... started before that was set"** (Windows) | The folder is already on your persistent PATH; this terminal/VS Code started earlier and still has the old one. Close and reopen the terminal, or restart VS Code (and Claude Code). Do not add it again. |
|
|
14
|
+
| **Graphify `DEGRADED`: not on PATH** | Its Claude Code hooks call `graphify` by name and it is on no PATH (on Windows: not in this terminal and not in your persistent user/machine PATH). Add the folder shown in the next step to PATH (or run `uv tool update-shell` / `pipx ensurepath`) and open a new terminal. |
|
|
15
|
+
| **`RESTART_REQUIRED`** | Restart Claude Code (or run `/reload-plugins`), then `devworkspace integrations status --restarted`. |
|
|
16
|
+
| **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. |
|
|
17
|
+
| **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. |
|
|
18
|
+
| **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`. |
|
|
19
|
+
| **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
20
|
| **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
21
|
| **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
22
|
| **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
23
|
| **Stale context** | `devworkspace refresh`, then paste `.devworkspace/analysis/refresh-prompt.md` into Claude. Facts without cited `--file` sources can never be proven stale. |
|
|
@@ -22,6 +30,8 @@ Start with `devworkspace doctor`. Every warning/failure includes a remediation l
|
|
|
22
30
|
| **Windows: `EPERM` on write** | Editors, antivirus or indexers can briefly lock files; writes retry for ~2 s. If it persists, close the program holding the file. |
|
|
23
31
|
| **Windows: PowerShell blocks `devworkspace.ps1`** | `npm` creates `.cmd` and `.ps1` shims. Run via `devworkspace.cmd`, `npx devworkspace`, or relax the execution policy for your user (`Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`). |
|
|
24
32
|
| **`.devworkspace` not appearing in Git** | The root `.gitignore` ignores it. Remove that rule; `.devworkspace/.gitignore` already excludes the machine-local parts. |
|
|
33
|
+
| **`doctor` warns "package manifest(s) the last analysis did not record"** | The analysis predates nested-package detection. Run `devworkspace analyze`; commands you confirmed earlier are kept. |
|
|
34
|
+
| **`doctor` warns "No ecosystem was detected" or "No verification commands"** | The analyzer found no recognised manifest or scripts. Add them, or write the commands in `.devworkspace/context/commands.json` (`"origin": "user"`, optional `"cwd": "backend"`). If the project intentionally has none, set `"acknowledgeNoVerification": true` under `settings` in `.devworkspace/project.json`. |
|
|
25
35
|
| **Analysis seems incomplete** | `status`/`doctor` says "partial" when file or depth limits were hit. Raise `settings.maxFiles` in `project.json` or add `.devworkspaceignore` entries for generated folders. |
|
|
26
36
|
|
|
27
37
|
Add `--debug` to any command for stack traces and debug logs (secrets are still redacted).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devworkspace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
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
|