pluidr 0.7.5 → 0.8.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.
- package/LICENSE +20 -20
- package/README.md +408 -364
- package/bin/pluidr.js +3 -3
- package/package.json +1 -1
- package/src/cli/commands/doctor.js +137 -134
- package/src/cli/commands/init.js +134 -47
- package/src/cli/commands/launch.js +101 -50
- package/src/cli/commands/theme.js +67 -0
- package/src/cli/commands/theme.test.js +28 -0
- package/src/cli/commands/uninstall.js +103 -90
- package/src/cli/commands/update.js +9 -9
- package/src/cli/index.js +63 -57
- package/src/cli/wizard/selectModelTier.js +40 -40
- package/src/core/agentPromptWriter.js +45 -32
- package/src/core/agentPromptWriter.test.js +56 -56
- package/src/core/animation.js +83 -0
- package/src/core/animation.test.js +118 -0
- package/src/core/backup.js +46 -46
- package/src/core/commandsWriter.js +26 -0
- package/src/core/commandsWriter.test.js +29 -0
- package/src/core/configBuilder.js +32 -32
- package/src/core/configBuilder.test.js +93 -93
- package/src/core/configWriter.js +10 -10
- package/src/core/configWriter.test.js +1 -1
- package/src/core/identityHeader.js +8 -8
- package/src/core/paths.js +13 -11
- package/src/core/paths.test.js +33 -29
- package/src/core/pluginWriter.js +43 -29
- package/src/core/skillsWriter.js +21 -0
- package/src/core/skillsWriter.test.js +30 -0
- package/src/core/squeezeInstaller.js +158 -158
- package/src/core/squeezeInstaller.test.js +79 -79
- package/src/core/themeWriter.js +18 -4
- package/src/core/themeWriter.test.js +2 -2
- package/src/core/tuiConfigWriter.js +3 -2
- package/src/core/tuiConfigWriter.test.js +4 -4
- package/src/core/version.js +8 -8
- package/src/core/versionCheck.js +44 -44
- package/src/plugins/README.md +57 -68
- package/src/plugins/pluidr-squeeze.js +77 -77
- package/src/templates/agent-prompts/analyze.txt +49 -0
- package/src/templates/agent-prompts/auditor.txt +20 -20
- package/src/templates/agent-prompts/builder.txt +10 -0
- package/src/templates/agent-prompts/coder.txt +87 -87
- package/src/templates/agent-prompts/compose-reporter.txt +55 -55
- package/src/templates/agent-prompts/compose.txt +50 -0
- package/src/templates/agent-prompts/composer.txt +414 -420
- package/src/templates/agent-prompts/debug-reporter.txt +65 -65
- package/src/templates/agent-prompts/debug.txt +49 -0
- package/src/templates/agent-prompts/debugger.txt +149 -144
- package/src/templates/agent-prompts/explorer.txt +10 -0
- package/src/templates/agent-prompts/fixer.txt +66 -66
- package/src/templates/agent-prompts/hierarchy.txt +101 -96
- package/src/templates/agent-prompts/inspector.txt +79 -79
- package/src/templates/agent-prompts/patcher.txt +20 -20
- package/src/templates/agent-prompts/plan-checker.txt +45 -45
- package/src/templates/agent-prompts/plan-writer.txt +57 -57
- package/src/templates/agent-prompts/probe-reporter.txt +62 -62
- package/src/templates/agent-prompts/prober.txt +93 -87
- package/src/templates/agent-prompts/reporter.txt +10 -0
- package/src/templates/agent-prompts/researcher.txt +48 -48
- package/src/templates/agent-prompts/reviewer.txt +57 -57
- package/src/templates/agent-prompts/tester.txt +66 -66
- package/src/templates/agent-prompts/tracer.txt +33 -33
- package/src/templates/agent-prompts/verifier.txt +10 -0
- package/src/templates/commands/squeeze-dashboard.md +5 -0
- package/src/templates/commands/squeeze-health.md +10 -0
- package/src/templates/commands/squeeze-quick.md +10 -0
- package/src/templates/model-defaults.json +59 -73
- package/src/templates/opencode.config.json +243 -572
- package/src/templates/skills/brooks-lint-rca/SKILL.md +48 -0
- package/src/templates/skills/codebase-fact-finding/SKILL.md +39 -0
- package/src/templates/skills/diff-review/SKILL.md +42 -0
- package/src/templates/skills/general-coding/SKILL.md +44 -0
- package/src/templates/skills/minimal-fixing/SKILL.md +25 -0
- package/src/templates/skills/plan-checking/SKILL.md +33 -0
- package/src/templates/skills/ponytail-patching/SKILL.md +20 -0
- package/src/templates/skills/prd-formatting/SKILL.md +45 -0
- package/src/templates/skills/refactoring-patterns/SKILL.md +37 -0
- package/src/templates/skills/security-auditing/SKILL.md +35 -0
- package/src/templates/skills/security-remediation/SKILL.md +37 -0
- package/src/templates/skills/summary-reporting/SKILL.md +83 -0
- package/src/templates/skills/test-assurance/SKILL.md +48 -0
- package/src/templates/skills/test-mocking-strategy/SKILL.md +18 -0
- package/src/templates/skills/ui-design-audit/SKILL.md +23 -0
- package/src/templates/skills/ui-design-system/SKILL.md +37 -0
- package/src/templates/skills/wstg-recon/SKILL.md +33 -0
- package/src/templates/themes/pluidr-colorful.json +241 -0
- package/src/templates/themes/pluidr-dark.json +177 -0
- package/src/templates/themes/pluidr-light.json +241 -0
package/src/core/versionCheck.js
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import { execFileSync, execSync } from "node:child_process"
|
|
2
|
-
import { confirm, isCancel } from "@clack/prompts"
|
|
3
|
-
|
|
4
|
-
export function fetchLatestVersion() {
|
|
5
|
-
try {
|
|
6
|
-
if (process.platform === "win32") {
|
|
7
|
-
return execSync("npm view pluidr version", { stdio: "pipe" })
|
|
8
|
-
.toString()
|
|
9
|
-
.trim()
|
|
10
|
-
}
|
|
11
|
-
return execFileSync("npm", ["view", "pluidr", "version"], { stdio: "pipe" })
|
|
12
|
-
.toString()
|
|
13
|
-
.trim()
|
|
14
|
-
} catch {
|
|
15
|
-
return null
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function checkAndPromptUpdate(currentVersion) {
|
|
20
|
-
process.stdout.write("Checking for updates... ")
|
|
21
|
-
|
|
22
|
-
const latest = fetchLatestVersion()
|
|
23
|
-
if (!latest) {
|
|
24
|
-
console.log("⚠ Could not reach npm registry — skipping")
|
|
25
|
-
return false
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (latest === currentVersion) {
|
|
29
|
-
console.log(`✓ Up to date (${currentVersion})`)
|
|
30
|
-
return false
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
console.log(`⚠ pluidr ${latest} available (you have ${currentVersion})`)
|
|
34
|
-
|
|
35
|
-
const answer = await confirm({ message: "Update now?", initialValue: true })
|
|
36
|
-
if (isCancel(answer) || !answer) return false
|
|
37
|
-
|
|
38
|
-
if (process.platform === "win32") {
|
|
39
|
-
execSync("npm install -g pluidr", { stdio: "inherit" })
|
|
40
|
-
} else {
|
|
41
|
-
execFileSync("npm", ["install", "-g", "pluidr"], { stdio: "inherit" })
|
|
42
|
-
}
|
|
43
|
-
return true
|
|
44
|
-
}
|
|
1
|
+
import { execFileSync, execSync } from "node:child_process"
|
|
2
|
+
import { confirm, isCancel } from "@clack/prompts"
|
|
3
|
+
|
|
4
|
+
export function fetchLatestVersion() {
|
|
5
|
+
try {
|
|
6
|
+
if (process.platform === "win32") {
|
|
7
|
+
return execSync("npm view pluidr version", { stdio: "pipe", timeout: 1500 })
|
|
8
|
+
.toString()
|
|
9
|
+
.trim()
|
|
10
|
+
}
|
|
11
|
+
return execFileSync("npm", ["view", "pluidr", "version"], { stdio: "pipe", timeout: 1500 })
|
|
12
|
+
.toString()
|
|
13
|
+
.trim()
|
|
14
|
+
} catch {
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function checkAndPromptUpdate(currentVersion) {
|
|
20
|
+
process.stdout.write("Checking for updates... ")
|
|
21
|
+
|
|
22
|
+
const latest = fetchLatestVersion()
|
|
23
|
+
if (!latest) {
|
|
24
|
+
console.log("⚠ Could not reach npm registry — skipping")
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (latest === currentVersion) {
|
|
29
|
+
console.log(`✓ Up to date (${currentVersion})`)
|
|
30
|
+
return false
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(`⚠ pluidr ${latest} available (you have ${currentVersion})`)
|
|
34
|
+
|
|
35
|
+
const answer = await confirm({ message: "Update now?", initialValue: true })
|
|
36
|
+
if (isCancel(answer) || !answer) return false
|
|
37
|
+
|
|
38
|
+
if (process.platform === "win32") {
|
|
39
|
+
execSync("npm install -g pluidr", { stdio: "inherit" })
|
|
40
|
+
} else {
|
|
41
|
+
execFileSync("npm", ["install", "-g", "pluidr"], { stdio: "inherit" })
|
|
42
|
+
}
|
|
43
|
+
return true
|
|
44
|
+
}
|
package/src/plugins/README.md
CHANGED
|
@@ -1,68 +1,57 @@
|
|
|
1
|
-
# Bundled plugins
|
|
2
|
-
|
|
3
|
-
This folder holds plugin source files that `pluidr init` copies into the
|
|
4
|
-
user's OpenCode plugin directory (`~/.config/opencode/plugins/`), giving
|
|
5
|
-
subagents cross-session context tools and command output filtering out of
|
|
6
|
-
the box.
|
|
7
|
-
|
|
8
|
-
## `pluidr-flow.js`
|
|
9
|
-
|
|
10
|
-
Implementation of the `SessionFlowPlugin`. Exposes three tools for reading
|
|
11
|
-
conversation history across related sessions (parent, sibling, or batch):
|
|
12
|
-
|
|
13
|
-
- `parent_session_messages`
|
|
14
|
-
- `session_messages(sessionId)`
|
|
15
|
-
- `session_messages_batch(sessionIds)`
|
|
16
|
-
|
|
17
|
-
The output is a structured text dump with numbered messages, agent
|
|
18
|
-
attribution, and one-line tool-invocation summaries, separated by
|
|
19
|
-
`\n\n---\n\n`.
|
|
20
|
-
|
|
21
|
-
## `pluidr-squeeze.js`
|
|
22
|
-
|
|
23
|
-
Implementation of the `PluidrSqueezePlugin
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
## Why
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
agent in its pipeline, so the tool would have no caller — YAGNI.
|
|
59
|
-
|
|
60
|
-
## How they are loaded
|
|
61
|
-
|
|
62
|
-
`pluidr init` copies both plugins into `~/.config/opencode/plugins/` and
|
|
63
|
-
writes a `package.json` declaring `@opencode-ai/plugin: ^1.17.9` as a
|
|
64
|
-
dependency. For `pluidr-squeeze`, it also downloads and extracts the `squeeze`
|
|
65
|
-
engine binary to `~/.config/opencode/bin/`. On OpenCode's first launch, the
|
|
66
|
-
bundled Bun runtime detects the `package.json` and runs `bun install`
|
|
67
|
-
automatically — no user action required. Once installed, both plugins are
|
|
68
|
-
available to every agent that has the appropriate permissions.
|
|
1
|
+
# Bundled plugins
|
|
2
|
+
|
|
3
|
+
This folder holds plugin source files that `pluidr init` copies into the
|
|
4
|
+
user's OpenCode plugin directory (`~/.config/opencode/plugins/`), giving
|
|
5
|
+
subagents cross-session context tools and command output filtering out of
|
|
6
|
+
the box.
|
|
7
|
+
|
|
8
|
+
## `pluidr-flow.js` -- cross-session context
|
|
9
|
+
|
|
10
|
+
Implementation of the `SessionFlowPlugin`. Exposes three tools for reading
|
|
11
|
+
conversation history across related sessions (parent, sibling, or batch):
|
|
12
|
+
|
|
13
|
+
- `parent_session_messages` -- read the parent session's full transcript
|
|
14
|
+
- `session_messages(sessionId)` -- read any session by ID
|
|
15
|
+
- `session_messages_batch(sessionIds)` -- read multiple sessions in one call
|
|
16
|
+
|
|
17
|
+
The output is a structured text dump with numbered messages, agent
|
|
18
|
+
attribution, and one-line tool-invocation summaries, separated by
|
|
19
|
+
`\n\n---\n\n`.
|
|
20
|
+
|
|
21
|
+
## `pluidr-squeeze.js` -- context quality & session continuity
|
|
22
|
+
|
|
23
|
+
Implementation of the `PluidrSqueezePlugin` (rebranded from `token-optimizer-opencode`). Monitors context fill limits and session health, calculates ResourceHealth and SessionEfficiency metrics, alerts on loop/retry patterns, and enables seamless session continuity/restores for same-project tasks.
|
|
24
|
+
|
|
25
|
+
## Why `pluidr-flow` was extracted
|
|
26
|
+
|
|
27
|
+
Subagents (Coder, Tester, Reviewer, Inspector, Fixer, etc.) run in fresh
|
|
28
|
+
child sessions with no access to the parent orchestrator's conversation
|
|
29
|
+
history. When a parent agent dispatches a subagent via the `Task` tool, the
|
|
30
|
+
subagent cannot see what was discussed in the parent -- which means it has
|
|
31
|
+
to ask the user to re-paste context, or guess. `parent_session_messages`
|
|
32
|
+
bridges that gap: the subagent can fetch the parent transcript on demand
|
|
33
|
+
and pick up where the parent left off.
|
|
34
|
+
|
|
35
|
+
## Why the identity plugin was dropped
|
|
36
|
+
|
|
37
|
+
The original `AgentSelfIdentityPlugin` injected agent identity via
|
|
38
|
+
`experimental.chat.*` hooks. Pluidr's 12 agent names are known at install
|
|
39
|
+
time, so we prepend a static identity header (`You are the "<name>" agent.`)
|
|
40
|
+
to every generated prompt file. This is KISS: no hook evaluation per
|
|
41
|
+
request, no dependency on undocumented experimental APIs, single source
|
|
42
|
+
of truth in `src/core/identityHeader.js`.
|
|
43
|
+
|
|
44
|
+
## Why the attribution tool was dropped
|
|
45
|
+
|
|
46
|
+
The original `AgentAttributionToolPlugin` was designed for a Retrospective
|
|
47
|
+
agent that captures post-session observations. Pluidr has no Retrospective
|
|
48
|
+
agent in its pipeline, so the tool would have no caller -- YAGNI.
|
|
49
|
+
|
|
50
|
+
## How they are loaded
|
|
51
|
+
|
|
52
|
+
`pluidr init` copies both plugins into `~/.config/opencode/plugins/` and
|
|
53
|
+
writes a `package.json` declaring `@opencode-ai/plugin: ^1.17.9` as a
|
|
54
|
+
dependency. On OpenCode's first launch, the
|
|
55
|
+
bundled Bun runtime detects the `package.json` and runs `bun install`
|
|
56
|
+
automatically -- no user action required. Once installed, both plugins are
|
|
57
|
+
available to every agent that has the appropriate permissions.
|
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
import { existsSync } from "node:fs"
|
|
2
|
-
import { homedir } from "node:os"
|
|
3
|
-
import { join } from "node:path"
|
|
4
|
-
|
|
5
|
-
const BIN_NAME = process.platform === "win32" ? "squeeze.exe" : "squeeze"
|
|
6
|
-
const SQUEEZE_BIN = join(homedir(), ".config", "opencode", "bin", BIN_NAME)
|
|
7
|
-
|
|
8
|
-
function normalise(p) {
|
|
9
|
-
return p.replace(/\\/g, "/")
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Quote a path if it contains spaces so the shell treats it as one token.
|
|
13
|
-
export function shellQuote(p) {
|
|
14
|
-
return p.includes(" ") ? `"${p}"` : p
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Exported for testing. When binPath is the managed full path (not "squeeze"
|
|
18
|
-
// on PATH), the binary may output "rtk <cmd>" or "squeeze <cmd>" depending on
|
|
19
|
-
// how it resolves its own name. Replace the leading token with the actual
|
|
20
|
-
// binPath (quoted if it contains spaces) so the shell can find it. When
|
|
21
|
-
// squeeze is on PATH, normalise any "rtk" prefix to "squeeze".
|
|
22
|
-
export function resolveRewritten(rewritten, binPath) {
|
|
23
|
-
const m = rewritten.match(/^(rtk|squeeze)(\s|$)/)
|
|
24
|
-
if (!m) return rewritten
|
|
25
|
-
if (binPath === "squeeze") {
|
|
26
|
-
// squeeze is on PATH — normalise any leading binary name to "squeeze"
|
|
27
|
-
return "squeeze" + rewritten.slice(m[1].length)
|
|
28
|
-
}
|
|
29
|
-
// managed path — replace leading binary name with (quoted) full path
|
|
30
|
-
return shellQuote(binPath) + rewritten.slice(m[1].length)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function findBinary($) {
|
|
34
|
-
try {
|
|
35
|
-
if (process.platform === "win32") {
|
|
36
|
-
await $`where squeeze`.quiet()
|
|
37
|
-
} else {
|
|
38
|
-
await $`which squeeze`.quiet()
|
|
39
|
-
}
|
|
40
|
-
return "squeeze"
|
|
41
|
-
} catch {
|
|
42
|
-
if (existsSync(SQUEEZE_BIN)) {
|
|
43
|
-
return normalise(SQUEEZE_BIN)
|
|
44
|
-
}
|
|
45
|
-
return null
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const PluidrSqueezePlugin = async ({ $ }) => {
|
|
50
|
-
const binPath = await findBinary($)
|
|
51
|
-
if (!binPath) {
|
|
52
|
-
console.warn("[squeeze] squeeze binary not found — plugin disabled")
|
|
53
|
-
return {}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return {
|
|
57
|
-
"tool.execute.before": async (input, output) => {
|
|
58
|
-
const tool = String(input?.tool ?? "").toLowerCase()
|
|
59
|
-
if (tool !== "bash" && tool !== "shell") return
|
|
60
|
-
const args = output?.args
|
|
61
|
-
if (!args || typeof args !== "object") return
|
|
62
|
-
|
|
63
|
-
const command = args.command
|
|
64
|
-
if (typeof command !== "string" || !command) return
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
const result = await $`${binPath} rewrite ${command}`.quiet().nothrow()
|
|
68
|
-
const rewritten = String(result.stdout).trim()
|
|
69
|
-
if (rewritten && rewritten !== command) {
|
|
70
|
-
args.command = resolveRewritten(rewritten, binPath)
|
|
71
|
-
}
|
|
72
|
-
} catch {
|
|
73
|
-
// rewrite failed — pass through unchanged
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
}
|
|
77
|
-
}
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { homedir } from "node:os"
|
|
3
|
+
import { join } from "node:path"
|
|
4
|
+
|
|
5
|
+
const BIN_NAME = process.platform === "win32" ? "squeeze.exe" : "squeeze"
|
|
6
|
+
const SQUEEZE_BIN = join(homedir(), ".config", "opencode", "bin", BIN_NAME)
|
|
7
|
+
|
|
8
|
+
function normalise(p) {
|
|
9
|
+
return p.replace(/\\/g, "/")
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Quote a path if it contains spaces so the shell treats it as one token.
|
|
13
|
+
export function shellQuote(p) {
|
|
14
|
+
return p.includes(" ") ? `"${p}"` : p
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Exported for testing. When binPath is the managed full path (not "squeeze"
|
|
18
|
+
// on PATH), the binary may output "rtk <cmd>" or "squeeze <cmd>" depending on
|
|
19
|
+
// how it resolves its own name. Replace the leading token with the actual
|
|
20
|
+
// binPath (quoted if it contains spaces) so the shell can find it. When
|
|
21
|
+
// squeeze is on PATH, normalise any "rtk" prefix to "squeeze".
|
|
22
|
+
export function resolveRewritten(rewritten, binPath) {
|
|
23
|
+
const m = rewritten.match(/^(rtk|squeeze)(\s|$)/)
|
|
24
|
+
if (!m) return rewritten
|
|
25
|
+
if (binPath === "squeeze") {
|
|
26
|
+
// squeeze is on PATH — normalise any leading binary name to "squeeze"
|
|
27
|
+
return "squeeze" + rewritten.slice(m[1].length)
|
|
28
|
+
}
|
|
29
|
+
// managed path — replace leading binary name with (quoted) full path
|
|
30
|
+
return shellQuote(binPath) + rewritten.slice(m[1].length)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function findBinary($) {
|
|
34
|
+
try {
|
|
35
|
+
if (process.platform === "win32") {
|
|
36
|
+
await $`where squeeze`.quiet()
|
|
37
|
+
} else {
|
|
38
|
+
await $`which squeeze`.quiet()
|
|
39
|
+
}
|
|
40
|
+
return "squeeze"
|
|
41
|
+
} catch {
|
|
42
|
+
if (existsSync(SQUEEZE_BIN)) {
|
|
43
|
+
return normalise(SQUEEZE_BIN)
|
|
44
|
+
}
|
|
45
|
+
return null
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const PluidrSqueezePlugin = async ({ $ }) => {
|
|
50
|
+
const binPath = await findBinary($)
|
|
51
|
+
if (!binPath) {
|
|
52
|
+
console.warn("[squeeze] squeeze binary not found — plugin disabled")
|
|
53
|
+
return {}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
"tool.execute.before": async (input, output) => {
|
|
58
|
+
const tool = String(input?.tool ?? "").toLowerCase()
|
|
59
|
+
if (tool !== "bash" && tool !== "shell") return
|
|
60
|
+
const args = output?.args
|
|
61
|
+
if (!args || typeof args !== "object") return
|
|
62
|
+
|
|
63
|
+
const command = args.command
|
|
64
|
+
if (typeof command !== "string" || !command) return
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const result = await $`${binPath} rewrite ${command}`.quiet().nothrow()
|
|
68
|
+
const rewritten = String(result.stdout).trim()
|
|
69
|
+
if (rewritten && rewritten !== command) {
|
|
70
|
+
args.command = resolveRewritten(rewritten, binPath)
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
// rewrite failed — pass through unchanged
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Role: Analyze Agent
|
|
2
|
+
|
|
3
|
+
You are the **Analyze** agent. You orchestrate threat modeling, secure code scans, and security patch verification in a strict 4-phase, one-directional workflow: **EXPLORE ➔ PLAN ➔ BUILD ➔ REVIEW**.
|
|
4
|
+
|
|
5
|
+
You have no direct file, codebase, web, or bash access. Your role is pure orchestration: delegate tasks, consume findings, decide next steps, and ask the user.
|
|
6
|
+
|
|
7
|
+
## Phase State Machine
|
|
8
|
+
|
|
9
|
+
### 1. EXPLORE Phase
|
|
10
|
+
- **Goal**: Scan the directory structure, identify entry points, and trace vulnerability data-flows from sources to sinks.
|
|
11
|
+
- **Delegation**: Delegate to the `explorer` subagent recommending the `wstg-recon` skill (and optionally the `ui-design-system` skill if the patch changes UI screens/dialogs).
|
|
12
|
+
- **Analysis**: Check the attack surface, identifying confirmed vulnerabilities, suspected vulnerabilities, and adjacent decay risks.
|
|
13
|
+
- **Gate 1 (Transition)**: Ask the user to proceed to the PLAN phase to outline the security patches.
|
|
14
|
+
|
|
15
|
+
### 2. PLAN Phase
|
|
16
|
+
- **Goal**: Draft and verify target security patch specifications and trust boundaries.
|
|
17
|
+
- **Task 1**: Delegate to the `reporter` subagent recommending the `prd-formatting` skill to write the patching plan to `docs/plans/`.
|
|
18
|
+
- **Task 2**: Delegate to the `verifier` subagent recommending the `plan-checking` skill to verify the patch requirements cover all entry points and sinks.
|
|
19
|
+
- **Loop**: If verifier fails, re-delegate to `reporter` to resolve gaps (max 5 loops).
|
|
20
|
+
- **Gate 2 (Transition)**: Ask the user "Build from this PRD?" to transition to the BUILD phase.
|
|
21
|
+
|
|
22
|
+
### 3. BUILD Phase
|
|
23
|
+
- **Goal**: Implement minimal secure patches and verify correctness with tests.
|
|
24
|
+
- **Task 1**: Delegate to the `builder` subagent recommending the `ponytail-patching` skill (and optionally the `security-remediation` skill) to apply the patches and write/update proper security/functional tests targeting the patch.
|
|
25
|
+
- **Task 2**: Delegate to the `verifier` subagent recommending the `test-assurance` skill to run security and functional tests, and ensure the tests are fully updated and aligned with the security specs (flagging and rejecting outdated/recycled tests).
|
|
26
|
+
- **Loop**: If tests fail or have alignment/recycled test gaps, re-delegate to `builder` to fix/add tests (max 5 loops).
|
|
27
|
+
|
|
28
|
+
### 4. REVIEW Phase
|
|
29
|
+
- **Goal**: Run regression checks and audit implemented patches for over-engineering.
|
|
30
|
+
- **Task 1**: Delegate to the `verifier` subagent recommending the `security-auditing` skill (and optionally the `ui-design-audit` skill for UI changes) to inspect modified files and ensure no new vulnerability pathways or bloat were introduced (DoD, security regression, and BLOAT check).
|
|
31
|
+
- **Loop**: If verifier flags active vulnerabilities, new regressions, or bloat, loop back to `builder` in BUILD phase.
|
|
32
|
+
- **Task 2**: Delegate to the `reporter` subagent recommending the `summary-reporting` skill (Format C: Security & Quality Audit Report) to write the final audit report under `docs/reports/`.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Post-Completion Behavior
|
|
37
|
+
After presenting the final report, reset your state to EXPLORE and ask the user if they are finished or need further iteration.
|
|
38
|
+
|
|
39
|
+
## Delegation Rules
|
|
40
|
+
- EXPLORE: Allow `explorer` only.
|
|
41
|
+
- PLAN: Allow `reporter` and `verifier` only.
|
|
42
|
+
- BUILD: Allow `builder` and `verifier` only.
|
|
43
|
+
- REVIEW: Allow `verifier` and `reporter` only.
|
|
44
|
+
|
|
45
|
+
## Clarification & Questioning Rules
|
|
46
|
+
- **Only Ask on Critical Decisions**: Avoid querying the user for minor details or minor design/styling choices. Make safe, standard engineering assumptions and proceed. Only prompt the user if there is a critical blocking decision or high-risk design path.
|
|
47
|
+
- **Strict Option Limit**: When using the `question` tool to prompt the user, you must provide a maximum of **2 selectable options** (plus the default custom write-in option, making a total of 3 choices).
|
|
48
|
+
- **Recommended Option First**: Always list your recommended option first, prefixed with `(Recommended)`.
|
|
49
|
+
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
# Role: Auditor Subagent
|
|
2
|
-
|
|
3
|
-
You are the **Auditor** subagent for the **Prober** agent. You act as a strict validation gate checking if security patches have resolved the vulnerabilities and ensuring no over-engineering was introduced.
|
|
4
|
-
|
|
5
|
-
## Auditor MUST NOT
|
|
6
|
-
- Propose remedies, suggest code adjustments, or edit code.
|
|
7
|
-
|
|
8
|
-
## Auditor MAY ONLY
|
|
9
|
-
- Inspect modified codebase files and run test commands to verify vulnerability elimination.
|
|
10
|
-
- Perform a security regression review: ensure the applied patches did not introduce new vulnerability pathways (e.g., input bypasses or insecure error handling).
|
|
11
|
-
- Perform an over-engineering review (Ponytail audit lens).
|
|
12
|
-
|
|
13
|
-
## Ponytail Audit Lens (Bloat Analysis)
|
|
14
|
-
Analyze changes for cognitive overload, accidental complexity, or redundant logic. Compile a list of unrequested abstractions, boilerplate, or excessive lines.
|
|
15
|
-
|
|
16
|
-
## Output Format
|
|
17
|
-
Your output must consist ONLY of:
|
|
18
|
-
- **Verdict**: PASS or FAIL
|
|
19
|
-
- **Gap List**: Specific files/lines where vulnerabilities are still active or regression was detected (FAIL cases only).
|
|
20
|
-
- **BLOAT List**: List of over-engineered constructs found in the patches.
|
|
1
|
+
# Role: Auditor Subagent
|
|
2
|
+
|
|
3
|
+
You are the **Auditor** subagent for the **Prober** agent. You act as a strict validation gate checking if security patches have resolved the vulnerabilities and ensuring no over-engineering was introduced.
|
|
4
|
+
|
|
5
|
+
## Auditor MUST NOT
|
|
6
|
+
- Propose remedies, suggest code adjustments, or edit code.
|
|
7
|
+
|
|
8
|
+
## Auditor MAY ONLY
|
|
9
|
+
- Inspect modified codebase files and run test commands to verify vulnerability elimination.
|
|
10
|
+
- Perform a security regression review: ensure the applied patches did not introduce new vulnerability pathways (e.g., input bypasses or insecure error handling).
|
|
11
|
+
- Perform an over-engineering review (Ponytail audit lens).
|
|
12
|
+
|
|
13
|
+
## Ponytail Audit Lens (Bloat Analysis)
|
|
14
|
+
Analyze changes for cognitive overload, accidental complexity, or redundant logic. Compile a list of unrequested abstractions, boilerplate, or excessive lines.
|
|
15
|
+
|
|
16
|
+
## Output Format
|
|
17
|
+
Your output must consist ONLY of:
|
|
18
|
+
- **Verdict**: PASS or FAIL
|
|
19
|
+
- **Gap List**: Specific files/lines where vulnerabilities are still active or regression was detected (FAIL cases only).
|
|
20
|
+
- **BLOAT List**: List of over-engineered constructs found in the patches.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Role: Builder Subagent
|
|
2
|
+
|
|
3
|
+
You are the **Builder** subagent. You implement new features, apply bug fixes, write tests, and write security patches.
|
|
4
|
+
|
|
5
|
+
Your identity is **Builder** -- this is fixed. You have read, edit, write, and command execution permissions.
|
|
6
|
+
|
|
7
|
+
## Guidelines
|
|
8
|
+
- Check the task instructions for any recommended **Skills** (e.g. general-coding, minimal-fixing, ponytail-patching, or refactoring-patterns) and follow them.
|
|
9
|
+
- Focus strictly on the assigned task -- do not refactor unrelated code or add unrequested abstractions.
|
|
10
|
+
- Abide by the 10-line limit for patches/fixes: if a fix exceeds 10 lines of changes, stop and report this complexity back to the primary agent.
|