@cluesmith/codev 3.0.0-rc.1 → 3.0.0-rc.10
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 +201 -0
- package/bin/af.js +2 -2
- package/bin/afx.js +8 -0
- package/bin/consult.js +2 -1
- package/bin/team.js +2 -1
- package/{dashboard/dist/assets/index-nr0cXxtf.css → dashboard-dist/assets/index-Bs8I7N2s.css} +1 -1
- package/dashboard-dist/assets/index-CkNo2z6t.js +195 -0
- package/dashboard-dist/assets/index-CkNo2z6t.js.map +1 -0
- package/dashboard-dist/dist/assets/index-Bs8I7N2s.css +32 -0
- package/dashboard-dist/dist/assets/index-CkNo2z6t.js +195 -0
- package/dashboard-dist/dist/assets/index-CkNo2z6t.js.map +1 -0
- package/{dashboard → dashboard-dist}/dist/index.html +2 -2
- package/dashboard-dist/index.html +14 -0
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +17 -14
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/architect.d.ts +4 -4
- package/dist/agent-farm/commands/architect.d.ts.map +1 -1
- package/dist/agent-farm/commands/architect.js +23 -12
- package/dist/agent-farm/commands/architect.js.map +1 -1
- package/dist/agent-farm/commands/attach.js +8 -8
- package/dist/agent-farm/commands/attach.js.map +1 -1
- package/dist/agent-farm/commands/bench.d.ts +1 -1
- package/dist/agent-farm/commands/bench.js +1 -1
- package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
- package/dist/agent-farm/commands/cleanup.js +10 -5
- package/dist/agent-farm/commands/cleanup.js.map +1 -1
- package/dist/agent-farm/commands/cron.js +1 -1
- package/dist/agent-farm/commands/cron.js.map +1 -1
- package/dist/agent-farm/commands/db.d.ts +3 -3
- package/dist/agent-farm/commands/db.js +4 -4
- package/dist/agent-farm/commands/db.js.map +1 -1
- package/dist/agent-farm/commands/open.js +2 -2
- package/dist/agent-farm/commands/open.js.map +1 -1
- package/dist/agent-farm/commands/rename.js +1 -1
- package/dist/agent-farm/commands/rename.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts +4 -1
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +8 -5
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/shell.js +3 -3
- package/dist/agent-farm/commands/shell.js.map +1 -1
- package/dist/agent-farm/commands/spawn-roles.d.ts +2 -1
- package/dist/agent-farm/commands/spawn-roles.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-roles.js +1 -1
- package/dist/agent-farm/commands/spawn-roles.js.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.d.ts +49 -10
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js +356 -51
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
- package/dist/agent-farm/commands/spawn.d.ts +6 -6
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn.js +182 -74
- package/dist/agent-farm/commands/spawn.js.map +1 -1
- package/dist/agent-farm/commands/status.d.ts.map +1 -1
- package/dist/agent-farm/commands/status.js +48 -3
- package/dist/agent-farm/commands/status.js.map +1 -1
- package/dist/agent-farm/commands/team-update.d.ts +1 -1
- package/dist/agent-farm/commands/team-update.d.ts.map +1 -1
- package/dist/agent-farm/commands/team-update.js +8 -5
- package/dist/agent-farm/commands/team-update.js.map +1 -1
- package/dist/agent-farm/commands/team.d.ts +1 -1
- package/dist/agent-farm/commands/team.d.ts.map +1 -1
- package/dist/agent-farm/commands/team.js +7 -3
- package/dist/agent-farm/commands/team.js.map +1 -1
- package/dist/agent-farm/commands/tower-cloud.d.ts +2 -2
- package/dist/agent-farm/commands/tower-cloud.js +3 -3
- package/dist/agent-farm/commands/tower-cloud.js.map +1 -1
- package/dist/agent-farm/commands/tower.js +2 -2
- package/dist/agent-farm/commands/tower.js.map +1 -1
- package/dist/agent-farm/lib/cloud-config.js +2 -2
- package/dist/agent-farm/lib/cloud-config.js.map +1 -1
- package/dist/agent-farm/lib/tower-client.d.ts +6 -230
- package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tower-client.js +6 -293
- package/dist/agent-farm/lib/tower-client.js.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.js +1 -1
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
- package/dist/agent-farm/servers/message-write.d.ts +24 -0
- package/dist/agent-farm/servers/message-write.d.ts.map +1 -0
- package/dist/agent-farm/servers/message-write.js +63 -0
- package/dist/agent-farm/servers/message-write.js.map +1 -0
- package/dist/agent-farm/servers/overview.d.ts +10 -8
- package/dist/agent-farm/servers/overview.d.ts.map +1 -1
- package/dist/agent-farm/servers/overview.js +78 -38
- package/dist/agent-farm/servers/overview.js.map +1 -1
- package/dist/agent-farm/servers/send-buffer.d.ts +4 -3
- package/dist/agent-farm/servers/send-buffer.d.ts.map +1 -1
- package/dist/agent-farm/servers/send-buffer.js +7 -4
- package/dist/agent-farm/servers/send-buffer.js.map +1 -1
- package/dist/agent-farm/servers/tower-cron-parser.js +1 -1
- package/dist/agent-farm/servers/tower-cron-parser.js.map +1 -1
- package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-cron.js +4 -5
- package/dist/agent-farm/servers/tower-cron.js.map +1 -1
- package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-instances.js +15 -13
- package/dist/agent-farm/servers/tower-instances.js.map +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +9 -16
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts +2 -2
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +64 -36
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-tunnel.js +2 -2
- package/dist/agent-farm/servers/tower-tunnel.js.map +1 -1
- package/dist/agent-farm/servers/tower-utils.d.ts +9 -6
- package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-utils.js +13 -7
- package/dist/agent-farm/servers/tower-utils.js.map +1 -1
- package/dist/agent-farm/types.d.ts +13 -0
- package/dist/agent-farm/types.d.ts.map +1 -1
- package/dist/agent-farm/utils/config.d.ts +11 -0
- package/dist/agent-farm/utils/config.d.ts.map +1 -1
- package/dist/agent-farm/utils/config.js +39 -17
- package/dist/agent-farm/utils/config.js.map +1 -1
- package/dist/agent-farm/utils/harness.d.ts +85 -0
- package/dist/agent-farm/utils/harness.d.ts.map +1 -0
- package/dist/agent-farm/utils/harness.js +212 -0
- package/dist/agent-farm/utils/harness.js.map +1 -0
- package/dist/agent-farm/utils/roles.d.ts +11 -4
- package/dist/agent-farm/utils/roles.d.ts.map +1 -1
- package/dist/agent-farm/utils/roles.js +21 -6
- package/dist/agent-farm/utils/roles.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +40 -5
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt.d.ts.map +1 -1
- package/dist/commands/adopt.js +16 -45
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/consult/index.d.ts +6 -2
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +231 -183
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +121 -31
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +13 -43
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/porch/artifacts.d.ts +69 -0
- package/dist/commands/porch/artifacts.d.ts.map +1 -0
- package/dist/commands/porch/artifacts.js +368 -0
- package/dist/commands/porch/artifacts.js.map +1 -0
- package/dist/commands/porch/checks.d.ts +14 -3
- package/dist/commands/porch/checks.d.ts.map +1 -1
- package/dist/commands/porch/checks.js +150 -4
- package/dist/commands/porch/checks.js.map +1 -1
- package/dist/commands/porch/config.d.ts +6 -9
- package/dist/commands/porch/config.d.ts.map +1 -1
- package/dist/commands/porch/config.js +12 -37
- package/dist/commands/porch/config.js.map +1 -1
- package/dist/commands/porch/index.d.ts +12 -7
- package/dist/commands/porch/index.d.ts.map +1 -1
- package/dist/commands/porch/index.js +273 -82
- package/dist/commands/porch/index.js.map +1 -1
- package/dist/commands/porch/next.d.ts.map +1 -1
- package/dist/commands/porch/next.js +142 -75
- package/dist/commands/porch/next.js.map +1 -1
- package/dist/commands/porch/notify.d.ts +2 -2
- package/dist/commands/porch/notify.js +5 -5
- package/dist/commands/porch/notify.js.map +1 -1
- package/dist/commands/porch/prompts.d.ts +2 -1
- package/dist/commands/porch/prompts.d.ts.map +1 -1
- package/dist/commands/porch/prompts.js +34 -38
- package/dist/commands/porch/prompts.js.map +1 -1
- package/dist/commands/porch/protocol.d.ts +4 -3
- package/dist/commands/porch/protocol.d.ts.map +1 -1
- package/dist/commands/porch/protocol.js +21 -21
- package/dist/commands/porch/protocol.js.map +1 -1
- package/dist/commands/porch/state.d.ts +27 -2
- package/dist/commands/porch/state.d.ts.map +1 -1
- package/dist/commands/porch/state.js +100 -9
- package/dist/commands/porch/state.js.map +1 -1
- package/dist/commands/porch/types.d.ts +10 -2
- package/dist/commands/porch/types.d.ts.map +1 -1
- package/dist/commands/sync.d.ts +26 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +207 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/update.d.ts +15 -2
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +159 -202
- package/dist/commands/update.js.map +1 -1
- package/dist/lib/config.d.ts +96 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +165 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/forge-contracts.d.ts +100 -0
- package/dist/lib/forge-contracts.d.ts.map +1 -0
- package/dist/lib/forge-contracts.js +35 -0
- package/dist/lib/forge-contracts.js.map +1 -0
- package/dist/lib/forge.d.ts +102 -0
- package/dist/lib/forge.d.ts.map +1 -0
- package/dist/lib/forge.js +376 -0
- package/dist/lib/forge.js.map +1 -0
- package/dist/lib/github.d.ts +68 -60
- package/dist/lib/github.d.ts.map +1 -1
- package/dist/lib/github.js +160 -169
- package/dist/lib/github.js.map +1 -1
- package/dist/lib/skeleton.d.ts +15 -5
- package/dist/lib/skeleton.d.ts.map +1 -1
- package/dist/lib/skeleton.js +82 -7
- package/dist/lib/skeleton.js.map +1 -1
- package/dist/lib/team-github.d.ts +7 -3
- package/dist/lib/team-github.d.ts.map +1 -1
- package/dist/lib/team-github.js +29 -19
- package/dist/lib/team-github.js.map +1 -1
- package/dist/terminal/pty-manager.d.ts.map +1 -1
- package/dist/terminal/pty-manager.js +2 -0
- package/dist/terminal/pty-manager.js.map +1 -1
- package/dist/terminal/ws-protocol.d.ts +10 -8
- package/dist/terminal/ws-protocol.d.ts.map +1 -1
- package/dist/terminal/ws-protocol.js +3 -0
- package/dist/terminal/ws-protocol.js.map +1 -1
- package/package.json +27 -24
- package/scripts/forge/gitea/auth-status.sh +3 -0
- package/scripts/forge/gitea/issue-comment.sh +3 -0
- package/scripts/forge/gitea/issue-list.sh +3 -0
- package/scripts/forge/gitea/issue-view.sh +3 -0
- package/scripts/forge/gitea/pr-exists.sh +6 -0
- package/scripts/forge/gitea/pr-list.sh +3 -0
- package/scripts/forge/gitea/pr-merge.sh +3 -0
- package/scripts/forge/gitea/pr-view.sh +3 -0
- package/scripts/forge/gitea/recently-closed.sh +3 -0
- package/scripts/forge/gitea/recently-merged.sh +3 -0
- package/scripts/forge/gitea/repo-archive.sh +11 -0
- package/scripts/forge/gitea/user-identity.sh +3 -0
- package/scripts/forge/github/auth-status.sh +4 -0
- package/scripts/forge/github/issue-comment.sh +5 -0
- package/scripts/forge/github/issue-list.sh +4 -0
- package/scripts/forge/github/issue-view.sh +5 -0
- package/scripts/forge/github/on-it-timestamps.sh +8 -0
- package/scripts/forge/github/pr-diff.sh +10 -0
- package/scripts/forge/github/pr-exists.sh +7 -0
- package/scripts/forge/github/pr-list.sh +4 -0
- package/scripts/forge/github/pr-merge.sh +5 -0
- package/scripts/forge/github/pr-search.sh +5 -0
- package/scripts/forge/github/pr-view.sh +11 -0
- package/scripts/forge/github/recently-closed.sh +15 -0
- package/scripts/forge/github/recently-merged.sh +15 -0
- package/scripts/forge/github/repo-archive.sh +10 -0
- package/scripts/forge/github/team-activity.sh +5 -0
- package/scripts/forge/github/user-identity.sh +4 -0
- package/scripts/forge/gitlab/auth-status.sh +3 -0
- package/scripts/forge/gitlab/issue-comment.sh +3 -0
- package/scripts/forge/gitlab/issue-list.sh +3 -0
- package/scripts/forge/gitlab/issue-view.sh +3 -0
- package/scripts/forge/gitlab/pr-diff.sh +3 -0
- package/scripts/forge/gitlab/pr-exists.sh +5 -0
- package/scripts/forge/gitlab/pr-list.sh +3 -0
- package/scripts/forge/gitlab/pr-merge.sh +3 -0
- package/scripts/forge/gitlab/pr-search.sh +3 -0
- package/scripts/forge/gitlab/pr-view.sh +3 -0
- package/scripts/forge/gitlab/recently-closed.sh +3 -0
- package/scripts/forge/gitlab/recently-merged.sh +3 -0
- package/scripts/forge/gitlab/repo-archive.sh +12 -0
- package/scripts/forge/gitlab/user-identity.sh +3 -0
- package/skeleton/.claude/skills/afx/SKILL.md +144 -0
- package/skeleton/.claude/skills/codev/SKILL.md +3 -3
- package/skeleton/.claude/skills/consult/SKILL.md +1 -1
- package/skeleton/.claude/skills/porch/SKILL.md +2 -2
- package/skeleton/DEPENDENCIES.md +1 -1
- package/skeleton/builders.md +4 -4
- package/skeleton/protocol-schema.json +2 -2
- package/skeleton/protocols/air/builder-prompt.md +6 -6
- package/skeleton/protocols/air/prompts/pr.md +2 -2
- package/skeleton/protocols/air/protocol.md +1 -2
- package/skeleton/protocols/aspir/builder-prompt.md +28 -6
- package/skeleton/protocols/aspir/protocol.json +9 -1
- package/skeleton/protocols/aspir/protocol.md +1 -1
- package/skeleton/protocols/aspir/templates/plan.md +0 -20
- package/skeleton/protocols/aspir/templates/spec.md +0 -28
- package/skeleton/protocols/bugfix/builder-prompt.md +6 -6
- package/skeleton/protocols/bugfix/prompts/pr.md +1 -1
- package/skeleton/protocols/experiment/protocol.md +1 -6
- package/skeleton/protocols/maintain/builder-prompt.md +12 -11
- package/skeleton/protocols/maintain/prompts/maintain.md +88 -0
- package/skeleton/protocols/maintain/prompts/review.md +72 -0
- package/skeleton/protocols/maintain/protocol.json +14 -68
- package/skeleton/protocols/maintain/protocol.md +111 -409
- package/skeleton/protocols/maintain/templates/maintenance-run.md +18 -49
- package/skeleton/protocols/protocol-schema.json +1 -1
- package/skeleton/protocols/spike/builder-prompt.md +1 -1
- package/skeleton/protocols/spike/protocol.md +4 -4
- package/skeleton/protocols/spir/builder-prompt.md +28 -5
- package/skeleton/protocols/spir/protocol.json +9 -1
- package/skeleton/protocols/spir/protocol.md +2 -2
- package/skeleton/protocols/spir/templates/plan.md +0 -20
- package/skeleton/protocols/spir/templates/spec.md +0 -28
- package/skeleton/resources/commands/agent-farm.md +84 -84
- package/skeleton/resources/commands/codev.md +1 -1
- package/skeleton/resources/commands/consult.md +16 -7
- package/skeleton/resources/commands/overview.md +14 -15
- package/skeleton/resources/risk-triage.md +1 -1
- package/skeleton/resources/workflow-reference.md +14 -14
- package/skeleton/roles/architect.md +55 -43
- package/skeleton/roles/builder.md +22 -14
- package/skeleton/templates/AGENTS.md +4 -3
- package/skeleton/templates/CLAUDE.md +4 -3
- package/skeleton/templates/cheatsheet.md +11 -12
- package/templates/3d-viewer.html +16 -18
- package/templates/tower.html +1 -1
- package/dashboard/dist/assets/index-CiIBsixF.js +0 -194
- package/dashboard/dist/assets/index-CiIBsixF.js.map +0 -1
- package/skeleton/.claude/skills/af/SKILL.md +0 -146
- package/skeleton/porch/prompts/understand.md +0 -61
- package/skeleton/porch/prompts/verify.md +0 -58
- package/skeleton/protocols/maintain/prompts/audit.md +0 -111
- package/skeleton/protocols/maintain/prompts/clean.md +0 -91
- package/skeleton/protocols/maintain/prompts/sync.md +0 -113
- package/skeleton/protocols/maintain/prompts/verify.md +0 -110
- package/skeleton/protocols/tick/builder-prompt.md +0 -65
- package/skeleton/protocols/tick/consult-types/impl-review.md +0 -72
- package/skeleton/protocols/tick/consult-types/plan-review.md +0 -59
- package/skeleton/protocols/tick/consult-types/pr-review.md +0 -72
- package/skeleton/protocols/tick/consult-types/spec-review.md +0 -55
- package/skeleton/protocols/tick/protocol.json +0 -151
- package/skeleton/protocols/tick/protocol.md +0 -277
- package/skeleton/protocols/tick/templates/plan.md +0 -67
- package/skeleton/protocols/tick/templates/review.md +0 -89
- package/skeleton/protocols/tick/templates/spec.md +0 -61
|
@@ -14,13 +14,19 @@ import chalk from 'chalk';
|
|
|
14
14
|
import { query as claudeQuery } from '@anthropic-ai/claude-agent-sdk';
|
|
15
15
|
import { Codex } from '@openai/codex-sdk';
|
|
16
16
|
import { readCodevFile, findWorkspaceRoot } from '../../lib/skeleton.js';
|
|
17
|
+
import { getResolver } from '../porch/artifacts.js';
|
|
17
18
|
import { MetricsDB } from './metrics.js';
|
|
18
19
|
import { extractUsage, extractReviewText } from './usage-extractor.js';
|
|
20
|
+
import { executeForgeCommandSync } from '../../lib/forge.js';
|
|
19
21
|
const MODEL_CONFIGS = {
|
|
20
22
|
gemini: { cli: 'gemini', args: ['--model', 'gemini-3-pro-preview'], envVar: 'GEMINI_SYSTEM_MD' },
|
|
23
|
+
hermes: { cli: 'hermes', args: ['chat', '-q'], envVar: null },
|
|
21
24
|
};
|
|
22
25
|
// Models that use an Agent SDK instead of CLI subprocess
|
|
23
26
|
const SDK_MODELS = ['claude', 'codex'];
|
|
27
|
+
// Prevent E2BIG when passing very large prompts to CLI backends.
|
|
28
|
+
// Large payloads are written to a temp file and referenced in the query.
|
|
29
|
+
const CLI_PROMPT_INLINE_MAX_CHARS = 100_000;
|
|
24
30
|
// Claude Agent SDK turn limit. Claude explores the codebase with Read/Glob/Grep
|
|
25
31
|
// tools before producing its verdict, so it needs a generous turn budget.
|
|
26
32
|
const CLAUDE_MAX_TURNS = 200;
|
|
@@ -129,46 +135,28 @@ function loadDotenv(workspaceRoot) {
|
|
|
129
135
|
}
|
|
130
136
|
}
|
|
131
137
|
/**
|
|
132
|
-
* Find
|
|
133
|
-
*
|
|
138
|
+
* Find spec content by project ID using the artifact resolver.
|
|
139
|
+
* Returns a ContentRef with content and label, or null if not found.
|
|
134
140
|
*/
|
|
135
|
-
function
|
|
136
|
-
const
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (matches.length > 1) {
|
|
143
|
-
const list = matches.map(f => ` - codev/specs/${f}`).join('\n');
|
|
144
|
-
throw new Error(`Multiple spec files match '${unpadded}' or '${padded}':\n${list}`);
|
|
145
|
-
}
|
|
146
|
-
if (matches.length === 1) {
|
|
147
|
-
return path.join(specsDir, matches[0]);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return null;
|
|
141
|
+
function findSpecContent(workspaceRoot, id) {
|
|
142
|
+
const resolver = getResolver(workspaceRoot);
|
|
143
|
+
const content = resolver.getSpecContent(id, '');
|
|
144
|
+
if (!content)
|
|
145
|
+
return null;
|
|
146
|
+
const label = resolver.findSpecBaseName(id, '') ?? id;
|
|
147
|
+
return { content, label };
|
|
151
148
|
}
|
|
152
149
|
/**
|
|
153
|
-
* Find
|
|
154
|
-
*
|
|
150
|
+
* Find plan content by project ID using the artifact resolver.
|
|
151
|
+
* Returns a ContentRef with content and label, or null if not found.
|
|
155
152
|
*/
|
|
156
|
-
function
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (matches.length > 1) {
|
|
164
|
-
const list = matches.map(f => ` - codev/plans/${f}`).join('\n');
|
|
165
|
-
throw new Error(`Multiple plan files match '${unpadded}' or '${padded}':\n${list}`);
|
|
166
|
-
}
|
|
167
|
-
if (matches.length === 1) {
|
|
168
|
-
return path.join(plansDir, matches[0]);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return null;
|
|
153
|
+
function findPlanContent(workspaceRoot, id) {
|
|
154
|
+
const resolver = getResolver(workspaceRoot);
|
|
155
|
+
const content = resolver.getPlanContent(id, '');
|
|
156
|
+
if (!content)
|
|
157
|
+
return null;
|
|
158
|
+
const baseName = resolver.findSpecBaseName(id, '') ?? id;
|
|
159
|
+
return { content, label: baseName };
|
|
172
160
|
}
|
|
173
161
|
/**
|
|
174
162
|
* Check if running in a builder worktree
|
|
@@ -309,11 +297,11 @@ export async function runCodexConsultation(queryText, role, workspaceRoot, outpu
|
|
|
309
297
|
try {
|
|
310
298
|
const codex = new Codex({
|
|
311
299
|
config: {
|
|
312
|
-
|
|
300
|
+
model_instructions_file: tempFile,
|
|
313
301
|
},
|
|
314
302
|
});
|
|
315
303
|
const thread = codex.startThread({
|
|
316
|
-
model: 'gpt-5.
|
|
304
|
+
model: 'gpt-5.4',
|
|
317
305
|
sandboxMode: 'read-only',
|
|
318
306
|
modelReasoningEffort: 'medium',
|
|
319
307
|
workingDirectory: workspaceRoot,
|
|
@@ -508,28 +496,72 @@ async function runConsultation(model, query, workspaceRoot, role, outputPath, me
|
|
|
508
496
|
let tempFile = null;
|
|
509
497
|
const env = {};
|
|
510
498
|
let cmd;
|
|
499
|
+
// When true, the query is written to the child's stdin instead of argv.
|
|
500
|
+
// Used for gemini to avoid V8 heap exhaustion on large prompts (#680).
|
|
501
|
+
let stdinPayload = null;
|
|
511
502
|
if (model === 'gemini') {
|
|
512
503
|
// Gemini uses GEMINI_SYSTEM_MD env var for role
|
|
513
504
|
tempFile = path.join(tmpdir(), `codev-role-${Date.now()}.md`);
|
|
514
505
|
fs.writeFileSync(tempFile, role);
|
|
515
506
|
env['GEMINI_SYSTEM_MD'] = tempFile;
|
|
507
|
+
// Bugfix #680: gemini-cli v0.37.x crashes on large PR diffs (>500KB) due to
|
|
508
|
+
// V8 old-space exhaustion in the spawned subprocess. Mitigations:
|
|
509
|
+
// 1. Bump heap via NODE_OPTIONS (survives gemini-cli's internal relaunch).
|
|
510
|
+
// 2. Pipe the prompt via stdin instead of argv — avoids ARG_MAX and keeps
|
|
511
|
+
// V8 from holding the full prompt buffer twice.
|
|
512
|
+
env['NODE_OPTIONS'] = [process.env.NODE_OPTIONS ?? '', '--max-old-space-size=8192']
|
|
513
|
+
.join(' ')
|
|
514
|
+
.trim();
|
|
515
|
+
stdinPayload = query;
|
|
516
516
|
// Use --output-format json to capture token usage/cost in structured output.
|
|
517
517
|
// Never use --yolo — it allows Gemini to write files (#370).
|
|
518
|
-
|
|
518
|
+
// No positional query arg: prompt arrives on stdin (triggers non-interactive mode).
|
|
519
|
+
cmd = [config.cli, '--output-format', 'json', ...config.args];
|
|
520
|
+
}
|
|
521
|
+
else if (model === 'hermes') {
|
|
522
|
+
// Hermes does not have a dedicated system prompt flag for single-shot mode.
|
|
523
|
+
// Include role context at the top of the prompt.
|
|
524
|
+
const hermesPrompt = `${role}\n\n---\n\n${query}`;
|
|
525
|
+
// Large inline CLI args can exceed OS ARG_MAX and fail with E2BIG.
|
|
526
|
+
// For very large prompts, write the full prompt to a temp file and pass
|
|
527
|
+
// an instruction that points Hermes at that file.
|
|
528
|
+
if (hermesPrompt.length > CLI_PROMPT_INLINE_MAX_CHARS) {
|
|
529
|
+
tempFile = path.join(tmpdir(), `codev-consult-prompt-${Date.now()}.md`);
|
|
530
|
+
fs.writeFileSync(tempFile, hermesPrompt);
|
|
531
|
+
const instruction = [
|
|
532
|
+
`Read the full consultation prompt from this file: ${tempFile}`,
|
|
533
|
+
'You have file access. Read files directly from disk to review code.',
|
|
534
|
+
].join('\n\n');
|
|
535
|
+
cmd = [config.cli, ...config.args, instruction];
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
cmd = [config.cli, ...config.args, hermesPrompt];
|
|
539
|
+
}
|
|
519
540
|
}
|
|
520
541
|
else {
|
|
521
542
|
throw new Error(`Unknown model: ${model}`);
|
|
522
543
|
}
|
|
523
|
-
// Execute with passthrough stdio
|
|
524
|
-
// Use 'ignore' for stdin
|
|
544
|
+
// Execute with passthrough stdio.
|
|
545
|
+
// Use 'ignore' for stdin when no payload — prevents blocking when spawned as subprocess.
|
|
546
|
+
// Use 'pipe' when we need to stream the prompt in (e.g. gemini, see #680).
|
|
525
547
|
const fullEnv = { ...process.env, ...env };
|
|
526
548
|
const startTime = Date.now();
|
|
549
|
+
const stdinMode = stdinPayload !== null ? 'pipe' : 'ignore';
|
|
527
550
|
return new Promise((resolve, reject) => {
|
|
528
551
|
const proc = spawn(cmd[0], cmd.slice(1), {
|
|
529
552
|
cwd: workspaceRoot,
|
|
530
553
|
env: fullEnv,
|
|
531
|
-
stdio: [
|
|
554
|
+
stdio: [stdinMode, 'pipe', 'inherit'],
|
|
532
555
|
});
|
|
556
|
+
if (stdinPayload !== null && proc.stdin) {
|
|
557
|
+
proc.stdin.on('error', (err) => {
|
|
558
|
+
// EPIPE can happen if the child exits before reading all input — not fatal.
|
|
559
|
+
if (err.code !== 'EPIPE') {
|
|
560
|
+
reject(err);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
proc.stdin.end(stdinPayload, 'utf-8');
|
|
564
|
+
}
|
|
533
565
|
const chunks = [];
|
|
534
566
|
if (proc.stdout) {
|
|
535
567
|
proc.stdout.on('data', (chunk) => {
|
|
@@ -609,17 +641,31 @@ function getDiffStat(workspaceRoot, ref) {
|
|
|
609
641
|
return { stat, files };
|
|
610
642
|
}
|
|
611
643
|
/**
|
|
612
|
-
* Fetch PR metadata (no diff — that's fetched separately)
|
|
644
|
+
* Fetch PR metadata via forge concept commands (no diff — that's fetched separately).
|
|
613
645
|
*/
|
|
614
|
-
function fetchPRData(
|
|
615
|
-
console.error(`Fetching PR #${
|
|
646
|
+
function fetchPRData(prId) {
|
|
647
|
+
console.error(`Fetching PR #${prId} data...`);
|
|
616
648
|
try {
|
|
617
|
-
const
|
|
618
|
-
|
|
649
|
+
const prView = executeForgeCommandSync('pr-view', {
|
|
650
|
+
CODEV_PR_NUMBER: prId,
|
|
651
|
+
});
|
|
652
|
+
const info = typeof prView === 'string' ? prView : JSON.stringify(prView);
|
|
653
|
+
const diffResult = executeForgeCommandSync('pr-diff', {
|
|
654
|
+
CODEV_PR_NUMBER: prId,
|
|
655
|
+
CODEV_DIFF_NAME_ONLY: '1',
|
|
656
|
+
}, { raw: true });
|
|
657
|
+
const nameOnly = typeof diffResult === 'string' ? diffResult : '';
|
|
619
658
|
const changedFiles = nameOnly.trim().split('\n').filter(Boolean);
|
|
620
659
|
let comments = '(No comments)';
|
|
621
660
|
try {
|
|
622
|
-
comments
|
|
661
|
+
// Fetch PR comments via pr-view concept with CODEV_INCLUDE_COMMENTS flag
|
|
662
|
+
const commentsResult = executeForgeCommandSync('pr-view', {
|
|
663
|
+
CODEV_PR_NUMBER: prId,
|
|
664
|
+
CODEV_INCLUDE_COMMENTS: '1',
|
|
665
|
+
}, { raw: true });
|
|
666
|
+
if (commentsResult && typeof commentsResult === 'string' && commentsResult.trim()) {
|
|
667
|
+
comments = commentsResult;
|
|
668
|
+
}
|
|
623
669
|
}
|
|
624
670
|
catch {
|
|
625
671
|
// No comments or error fetching
|
|
@@ -631,25 +677,28 @@ function fetchPRData(prNumber) {
|
|
|
631
677
|
}
|
|
632
678
|
}
|
|
633
679
|
/**
|
|
634
|
-
* Fetch the full PR diff via
|
|
680
|
+
* Fetch the full PR diff via the pr-diff forge concept command.
|
|
635
681
|
*/
|
|
636
|
-
function fetchPRDiff(
|
|
682
|
+
function fetchPRDiff(prId) {
|
|
637
683
|
try {
|
|
638
|
-
|
|
684
|
+
const result = executeForgeCommandSync('pr-diff', {
|
|
685
|
+
CODEV_PR_NUMBER: prId,
|
|
686
|
+
}, { raw: true });
|
|
687
|
+
return typeof result === 'string' ? result : '';
|
|
639
688
|
}
|
|
640
689
|
catch (err) {
|
|
641
|
-
throw new Error(`Failed to fetch PR diff for #${
|
|
690
|
+
throw new Error(`Failed to fetch PR diff for #${prId}: ${err}`);
|
|
642
691
|
}
|
|
643
692
|
}
|
|
644
693
|
/**
|
|
645
694
|
* Build query for PR review.
|
|
646
695
|
* Includes full PR diff + file list; model reads surrounding context from disk.
|
|
647
696
|
*/
|
|
648
|
-
function buildPRQuery(
|
|
649
|
-
const prData = fetchPRData(
|
|
650
|
-
const diff = fetchPRDiff(
|
|
697
|
+
function buildPRQuery(prId) {
|
|
698
|
+
const prData = fetchPRData(prId);
|
|
699
|
+
const diff = fetchPRDiff(prId);
|
|
651
700
|
const fileList = prData.changedFiles.map(f => `- ${f}`).join('\n');
|
|
652
|
-
return `Review Pull Request #${
|
|
701
|
+
return `Review Pull Request #${prId}
|
|
653
702
|
|
|
654
703
|
## PR Info
|
|
655
704
|
\`\`\`json
|
|
@@ -693,22 +742,22 @@ KEY_ISSUES: [List of critical issues if any, or "None"]`;
|
|
|
693
742
|
/**
|
|
694
743
|
* Build query for spec review
|
|
695
744
|
*/
|
|
696
|
-
function buildSpecQuery(
|
|
697
|
-
let query = `Review Specification: ${
|
|
745
|
+
function buildSpecQuery(spec, plan) {
|
|
746
|
+
let query = `Review Specification: ${spec.label}
|
|
747
|
+
|
|
748
|
+
## Specification
|
|
749
|
+
|
|
750
|
+
${spec.content}
|
|
698
751
|
|
|
699
|
-
Please read and review this specification:
|
|
700
|
-
- Spec file: ${specPath}
|
|
701
752
|
`;
|
|
702
|
-
if (
|
|
703
|
-
query +=
|
|
704
|
-
}
|
|
705
|
-
query += `
|
|
706
|
-
## How to Review
|
|
707
|
-
**Read the files listed above directly from disk.** You have full filesystem access.
|
|
708
|
-
Do NOT rely on \`git diff\` or \`git log\` to review content — diffs may be truncated or miss uncommitted work.
|
|
709
|
-
Open the spec file, read it in full, and evaluate it directly.
|
|
753
|
+
if (plan) {
|
|
754
|
+
query += `## Plan
|
|
710
755
|
|
|
711
|
-
|
|
756
|
+
${plan.content}
|
|
757
|
+
|
|
758
|
+
`;
|
|
759
|
+
}
|
|
760
|
+
query += `Please review:
|
|
712
761
|
1. Clarity and completeness of requirements
|
|
713
762
|
2. Technical feasibility
|
|
714
763
|
3. Edge cases and error scenarios
|
|
@@ -731,7 +780,7 @@ KEY_ISSUES: [List of critical issues if any, or "None"]`;
|
|
|
731
780
|
* Build query for implementation review.
|
|
732
781
|
* Accepts spec/plan paths and optional diff reference override.
|
|
733
782
|
*/
|
|
734
|
-
function buildImplQuery(workspaceRoot,
|
|
783
|
+
function buildImplQuery(workspaceRoot, spec, plan, planPhase, diffRef) {
|
|
735
784
|
// Get compact diff summary
|
|
736
785
|
let diffStat = '';
|
|
737
786
|
let changedFiles = [];
|
|
@@ -748,15 +797,15 @@ function buildImplQuery(workspaceRoot, specPath, planPath, planPhase, diffRef) {
|
|
|
748
797
|
if (planPhase) {
|
|
749
798
|
query += ` — Phase: ${planPhase}`;
|
|
750
799
|
}
|
|
751
|
-
query +=
|
|
752
|
-
if (
|
|
753
|
-
query +=
|
|
800
|
+
query += '\n\n';
|
|
801
|
+
if (spec) {
|
|
802
|
+
query += `## Specification\n\n${spec.content}\n\n`;
|
|
754
803
|
}
|
|
755
|
-
if (
|
|
756
|
-
query +=
|
|
804
|
+
if (plan) {
|
|
805
|
+
query += `## Plan\n\n${plan.content}\n\n`;
|
|
757
806
|
}
|
|
758
807
|
if (planPhase) {
|
|
759
|
-
query +=
|
|
808
|
+
query += `## REVIEW SCOPE — CURRENT PLAN PHASE ONLY\n`;
|
|
760
809
|
query += `You are reviewing **plan phase "${planPhase}" ONLY**.\n`;
|
|
761
810
|
query += `Read the plan, find the section for "${planPhase}", and scope your review to ONLY the work described in that phase.\n\n`;
|
|
762
811
|
query += `**DO NOT** request changes for work that belongs to other plan phases.\n`;
|
|
@@ -774,7 +823,7 @@ function buildImplQuery(workspaceRoot, specPath, planPath, planPhase, diffRef) {
|
|
|
774
823
|
query += `Do NOT rely on git diffs to determine the current state of code — diffs miss uncommitted changes in worktrees.\n`;
|
|
775
824
|
}
|
|
776
825
|
else {
|
|
777
|
-
query += `\n## Instructions\n\
|
|
826
|
+
query += `\n## Instructions\n\nExplore the filesystem to find and review the implementation changes.\n`;
|
|
778
827
|
}
|
|
779
828
|
query += `
|
|
780
829
|
Please review:
|
|
@@ -798,22 +847,22 @@ KEY_ISSUES: [List of critical issues if any, or "None"]`;
|
|
|
798
847
|
/**
|
|
799
848
|
* Build query for plan review
|
|
800
849
|
*/
|
|
801
|
-
function buildPlanQuery(
|
|
802
|
-
let query = `Review Implementation Plan: ${
|
|
850
|
+
function buildPlanQuery(plan, spec) {
|
|
851
|
+
let query = `Review Implementation Plan: ${plan.label}
|
|
852
|
+
|
|
853
|
+
## Plan
|
|
854
|
+
|
|
855
|
+
${plan.content}
|
|
803
856
|
|
|
804
|
-
Please read and review this implementation plan:
|
|
805
|
-
- Plan file: ${planPath}
|
|
806
857
|
`;
|
|
807
|
-
if (
|
|
808
|
-
query +=
|
|
809
|
-
}
|
|
810
|
-
query += `
|
|
811
|
-
## How to Review
|
|
812
|
-
**Read the files listed above directly from disk.** You have full filesystem access.
|
|
813
|
-
Do NOT rely on \`git diff\` or \`git log\` to review content — diffs may be truncated or miss uncommitted work.
|
|
814
|
-
Open the plan file (and spec if provided), read them in full, and evaluate the plan directly.
|
|
858
|
+
if (spec) {
|
|
859
|
+
query += `## Specification (for context)
|
|
815
860
|
|
|
816
|
-
|
|
861
|
+
${spec.content}
|
|
862
|
+
|
|
863
|
+
`;
|
|
864
|
+
}
|
|
865
|
+
query += `Please review:
|
|
817
866
|
1. Alignment with specification requirements
|
|
818
867
|
2. Implementation approach and architecture
|
|
819
868
|
3. Task breakdown and ordering
|
|
@@ -836,7 +885,7 @@ KEY_ISSUES: [List of critical issues if any, or "None"]`;
|
|
|
836
885
|
* Build query for phase-scoped review.
|
|
837
886
|
* Uses git show HEAD for the phase's atomic commit diff.
|
|
838
887
|
*/
|
|
839
|
-
function buildPhaseQuery(workspaceRoot, planPhase,
|
|
888
|
+
function buildPhaseQuery(workspaceRoot, planPhase, spec, plan) {
|
|
840
889
|
let phaseDiff = '';
|
|
841
890
|
try {
|
|
842
891
|
phaseDiff = execSync('git show HEAD', { cwd: workspaceRoot, encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });
|
|
@@ -844,11 +893,11 @@ function buildPhaseQuery(workspaceRoot, planPhase, specPath, planPath) {
|
|
|
844
893
|
catch {
|
|
845
894
|
// If git show fails, reviewer explores filesystem
|
|
846
895
|
}
|
|
847
|
-
let query = `Review Phase Implementation: "${planPhase}"\n\n
|
|
848
|
-
if (
|
|
849
|
-
query +=
|
|
850
|
-
if (
|
|
851
|
-
query +=
|
|
896
|
+
let query = `Review Phase Implementation: "${planPhase}"\n\n`;
|
|
897
|
+
if (spec)
|
|
898
|
+
query += `## Specification\n\n${spec.content}\n\n`;
|
|
899
|
+
if (plan)
|
|
900
|
+
query += `## Plan\n\n${plan.content}\n\n`;
|
|
852
901
|
query += `
|
|
853
902
|
## REVIEW SCOPE — CURRENT PLAN PHASE ONLY
|
|
854
903
|
You are reviewing **plan phase "${planPhase}" ONLY**.
|
|
@@ -885,92 +934,94 @@ KEY_ISSUES: [List of critical issues if any, or "None"]`;
|
|
|
885
934
|
return query;
|
|
886
935
|
}
|
|
887
936
|
/**
|
|
888
|
-
* Find PR number for the current branch
|
|
937
|
+
* Find PR number for the current branch via pr-search forge concept.
|
|
889
938
|
*/
|
|
890
939
|
function findPRForCurrentBranch(workspaceRoot) {
|
|
891
940
|
const branchName = execSync('git branch --show-current', { cwd: workspaceRoot, encoding: 'utf-8' }).trim();
|
|
892
|
-
const
|
|
893
|
-
|
|
941
|
+
const result = executeForgeCommandSync('pr-search', {
|
|
942
|
+
CODEV_SEARCH_QUERY: `head:${branchName}`,
|
|
943
|
+
}, { cwd: workspaceRoot });
|
|
944
|
+
const prs = Array.isArray(result) ? result : [];
|
|
945
|
+
if (prs.length === 0 || !prs[0]?.number) {
|
|
894
946
|
throw new Error(`No PR found for branch: ${branchName}`);
|
|
895
947
|
}
|
|
896
|
-
|
|
897
|
-
if (isNaN(prNumber)) {
|
|
898
|
-
throw new Error(`No PR found for branch: ${branchName}`);
|
|
899
|
-
}
|
|
900
|
-
return prNumber;
|
|
948
|
+
return String(prs[0].number);
|
|
901
949
|
}
|
|
902
950
|
/**
|
|
903
|
-
* Find PR number for a given issue number (architect mode)
|
|
951
|
+
* Find PR number for a given issue number (architect mode) via pr-search forge concept.
|
|
904
952
|
*/
|
|
905
|
-
function findPRForIssue(workspaceRoot,
|
|
906
|
-
const
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
953
|
+
function findPRForIssue(workspaceRoot, issueId) {
|
|
954
|
+
const result = executeForgeCommandSync('pr-search', {
|
|
955
|
+
CODEV_SEARCH_QUERY: issueId,
|
|
956
|
+
}, { cwd: workspaceRoot });
|
|
957
|
+
const prs = Array.isArray(result) ? result : [];
|
|
958
|
+
if (prs.length === 0 || !prs[0]?.number) {
|
|
959
|
+
throw new Error(`No PR found for issue #${issueId}`);
|
|
960
|
+
}
|
|
961
|
+
return prs[0];
|
|
911
962
|
}
|
|
912
963
|
/**
|
|
913
964
|
* Resolve query for builder context (auto-detected from porch state)
|
|
914
965
|
*/
|
|
915
966
|
function resolveBuilderQuery(workspaceRoot, type, options) {
|
|
916
967
|
const projectState = getBuilderProjectState(workspaceRoot, options.projectId);
|
|
917
|
-
const
|
|
968
|
+
const projectId = projectState.id;
|
|
918
969
|
switch (type) {
|
|
919
970
|
case 'spec': {
|
|
920
|
-
const
|
|
921
|
-
if (!
|
|
922
|
-
throw new Error(`Spec ${
|
|
923
|
-
const
|
|
924
|
-
console.error(`Spec: ${
|
|
925
|
-
if (
|
|
926
|
-
console.error(`Plan: ${
|
|
927
|
-
return buildSpecQuery(
|
|
971
|
+
const spec = findSpecContent(workspaceRoot, projectId);
|
|
972
|
+
if (!spec)
|
|
973
|
+
throw new Error(`Spec ${projectId} not found`);
|
|
974
|
+
const plan = findPlanContent(workspaceRoot, projectId);
|
|
975
|
+
console.error(`Spec: ${spec.label}`);
|
|
976
|
+
if (plan)
|
|
977
|
+
console.error(`Plan: ${plan.label}`);
|
|
978
|
+
return buildSpecQuery(spec, plan);
|
|
928
979
|
}
|
|
929
980
|
case 'plan': {
|
|
930
|
-
const
|
|
931
|
-
if (!
|
|
932
|
-
throw new Error(`Plan ${
|
|
933
|
-
const
|
|
934
|
-
console.error(`Plan: ${
|
|
935
|
-
if (
|
|
936
|
-
console.error(`Spec: ${
|
|
937
|
-
return buildPlanQuery(
|
|
981
|
+
const plan = findPlanContent(workspaceRoot, projectId);
|
|
982
|
+
if (!plan)
|
|
983
|
+
throw new Error(`Plan ${projectId} not found`);
|
|
984
|
+
const spec = findSpecContent(workspaceRoot, projectId);
|
|
985
|
+
console.error(`Plan: ${plan.label}`);
|
|
986
|
+
if (spec)
|
|
987
|
+
console.error(`Spec: ${spec.label}`);
|
|
988
|
+
return buildPlanQuery(plan, spec);
|
|
938
989
|
}
|
|
939
990
|
case 'impl': {
|
|
940
|
-
const
|
|
941
|
-
const
|
|
942
|
-
console.error(`Project: ${
|
|
943
|
-
if (
|
|
944
|
-
console.error(`Spec: ${
|
|
945
|
-
if (
|
|
946
|
-
console.error(`Plan: ${
|
|
991
|
+
const spec = findSpecContent(workspaceRoot, projectId);
|
|
992
|
+
const plan = findPlanContent(workspaceRoot, projectId);
|
|
993
|
+
console.error(`Project: ${projectId}`);
|
|
994
|
+
if (spec)
|
|
995
|
+
console.error(`Spec: ${spec.label}`);
|
|
996
|
+
if (plan)
|
|
997
|
+
console.error(`Plan: ${plan.label}`);
|
|
947
998
|
if (options.planPhase)
|
|
948
999
|
console.error(`Plan phase: ${options.planPhase}`);
|
|
949
|
-
return buildImplQuery(workspaceRoot,
|
|
1000
|
+
return buildImplQuery(workspaceRoot, spec, plan, options.planPhase);
|
|
950
1001
|
}
|
|
951
1002
|
case 'pr': {
|
|
952
|
-
const
|
|
953
|
-
console.error(`PR: #${
|
|
954
|
-
return buildPRQuery(
|
|
1003
|
+
const prId = findPRForCurrentBranch(workspaceRoot);
|
|
1004
|
+
console.error(`PR: #${prId}`);
|
|
1005
|
+
return buildPRQuery(prId);
|
|
955
1006
|
}
|
|
956
1007
|
case 'phase': {
|
|
957
1008
|
const currentPhase = options.planPhase ?? projectState.currentPlanPhase;
|
|
958
1009
|
if (!currentPhase) {
|
|
959
1010
|
throw new Error('No current plan phase detected. Use --plan-phase to specify.');
|
|
960
1011
|
}
|
|
961
|
-
const
|
|
962
|
-
const
|
|
1012
|
+
const spec = findSpecContent(workspaceRoot, projectId);
|
|
1013
|
+
const plan = findPlanContent(workspaceRoot, projectId);
|
|
963
1014
|
console.error(`Phase: ${currentPhase}`);
|
|
964
|
-
if (
|
|
965
|
-
console.error(`Spec: ${
|
|
966
|
-
if (
|
|
967
|
-
console.error(`Plan: ${
|
|
968
|
-
return buildPhaseQuery(workspaceRoot, currentPhase,
|
|
1015
|
+
if (spec)
|
|
1016
|
+
console.error(`Spec: ${spec.label}`);
|
|
1017
|
+
if (plan)
|
|
1018
|
+
console.error(`Plan: ${plan.label}`);
|
|
1019
|
+
return buildPhaseQuery(workspaceRoot, currentPhase, spec, plan);
|
|
969
1020
|
}
|
|
970
1021
|
case 'integration': {
|
|
971
|
-
const
|
|
972
|
-
console.error(`PR: #${
|
|
973
|
-
return buildPRQuery(
|
|
1022
|
+
const prId = findPRForCurrentBranch(workspaceRoot);
|
|
1023
|
+
console.error(`PR: #${prId} (integration review)`);
|
|
1024
|
+
return buildPRQuery(prId);
|
|
974
1025
|
}
|
|
975
1026
|
default:
|
|
976
1027
|
throw new Error(`Unknown review type: ${type}\nValid types: spec, plan, impl, pr, phase, integration`);
|
|
@@ -987,33 +1038,30 @@ function resolveArchitectQuery(workspaceRoot, type, options) {
|
|
|
987
1038
|
throw new Error(`--issue is required from architect context for --type ${type}.\n` +
|
|
988
1039
|
`Example: consult -m gemini --protocol spir --type ${type} --issue 42`);
|
|
989
1040
|
}
|
|
990
|
-
const
|
|
991
|
-
if (isNaN(issueNumber)) {
|
|
992
|
-
throw new Error(`Invalid issue number: ${options.issue}`);
|
|
993
|
-
}
|
|
1041
|
+
const issueId = options.issue;
|
|
994
1042
|
switch (type) {
|
|
995
1043
|
case 'spec': {
|
|
996
|
-
const
|
|
997
|
-
if (!
|
|
998
|
-
throw new Error(`Spec ${
|
|
999
|
-
const
|
|
1000
|
-
console.error(`Spec: ${
|
|
1001
|
-
if (
|
|
1002
|
-
console.error(`Plan: ${
|
|
1003
|
-
return buildSpecQuery(
|
|
1044
|
+
const spec = findSpecContent(workspaceRoot, issueId);
|
|
1045
|
+
if (!spec)
|
|
1046
|
+
throw new Error(`Spec ${issueId} not found`);
|
|
1047
|
+
const plan = findPlanContent(workspaceRoot, issueId);
|
|
1048
|
+
console.error(`Spec: ${spec.label}`);
|
|
1049
|
+
if (plan)
|
|
1050
|
+
console.error(`Plan: ${plan.label}`);
|
|
1051
|
+
return buildSpecQuery(spec, plan);
|
|
1004
1052
|
}
|
|
1005
1053
|
case 'plan': {
|
|
1006
|
-
const
|
|
1007
|
-
if (!
|
|
1008
|
-
throw new Error(`Plan ${
|
|
1009
|
-
const
|
|
1010
|
-
console.error(`Plan: ${
|
|
1011
|
-
if (
|
|
1012
|
-
console.error(`Spec: ${
|
|
1013
|
-
return buildPlanQuery(
|
|
1054
|
+
const plan = findPlanContent(workspaceRoot, issueId);
|
|
1055
|
+
if (!plan)
|
|
1056
|
+
throw new Error(`Plan ${issueId} not found`);
|
|
1057
|
+
const spec = findSpecContent(workspaceRoot, issueId);
|
|
1058
|
+
console.error(`Plan: ${plan.label}`);
|
|
1059
|
+
if (spec)
|
|
1060
|
+
console.error(`Spec: ${spec.label}`);
|
|
1061
|
+
return buildPlanQuery(plan, spec);
|
|
1014
1062
|
}
|
|
1015
1063
|
case 'impl': {
|
|
1016
|
-
const pr = findPRForIssue(workspaceRoot,
|
|
1064
|
+
const pr = findPRForIssue(workspaceRoot, issueId);
|
|
1017
1065
|
// Fetch the branch and diff from merge-base
|
|
1018
1066
|
try {
|
|
1019
1067
|
execSync(`git fetch origin ${pr.headRefName}`, { cwd: workspaceRoot, stdio: 'pipe' });
|
|
@@ -1022,24 +1070,24 @@ function resolveArchitectQuery(workspaceRoot, type, options) {
|
|
|
1022
1070
|
// May already be fetched
|
|
1023
1071
|
}
|
|
1024
1072
|
const mergeBase = execSync(`git merge-base main origin/${pr.headRefName}`, { cwd: workspaceRoot, encoding: 'utf-8' }).trim();
|
|
1025
|
-
const
|
|
1026
|
-
const
|
|
1027
|
-
console.error(`Project: ${
|
|
1028
|
-
if (
|
|
1029
|
-
console.error(`Spec: ${
|
|
1030
|
-
if (
|
|
1031
|
-
console.error(`Plan: ${
|
|
1032
|
-
return buildImplQuery(workspaceRoot,
|
|
1073
|
+
const spec = findSpecContent(workspaceRoot, issueId);
|
|
1074
|
+
const plan = findPlanContent(workspaceRoot, issueId);
|
|
1075
|
+
console.error(`Project: ${issueId} (PR #${pr.number}, branch: ${pr.headRefName})`);
|
|
1076
|
+
if (spec)
|
|
1077
|
+
console.error(`Spec: ${spec.label}`);
|
|
1078
|
+
if (plan)
|
|
1079
|
+
console.error(`Plan: ${plan.label}`);
|
|
1080
|
+
return buildImplQuery(workspaceRoot, spec, plan, options.planPhase, `${mergeBase}..origin/${pr.headRefName}`);
|
|
1033
1081
|
}
|
|
1034
1082
|
case 'pr': {
|
|
1035
|
-
const pr = findPRForIssue(workspaceRoot,
|
|
1083
|
+
const pr = findPRForIssue(workspaceRoot, issueId);
|
|
1036
1084
|
console.error(`PR: #${pr.number}`);
|
|
1037
|
-
return buildPRQuery(pr.number);
|
|
1085
|
+
return buildPRQuery(String(pr.number));
|
|
1038
1086
|
}
|
|
1039
1087
|
case 'integration': {
|
|
1040
|
-
const pr = findPRForIssue(workspaceRoot,
|
|
1088
|
+
const pr = findPRForIssue(workspaceRoot, issueId);
|
|
1041
1089
|
console.error(`PR: #${pr.number} (integration review)`);
|
|
1042
|
-
return buildPRQuery(pr.number);
|
|
1090
|
+
return buildPRQuery(String(pr.number));
|
|
1043
1091
|
}
|
|
1044
1092
|
default:
|
|
1045
1093
|
throw new Error(`Unknown review type: ${type}\nValid types: spec, plan, impl, pr, phase, integration`);
|
|
@@ -1144,7 +1192,7 @@ export async function consult(options) {
|
|
|
1144
1192
|
}
|
|
1145
1193
|
}
|
|
1146
1194
|
// Add file access instruction for Gemini
|
|
1147
|
-
if (model === 'gemini') {
|
|
1195
|
+
if (model === 'gemini' || model === 'hermes') {
|
|
1148
1196
|
query += '\n\nYou have file access. Read files directly from disk to review code.';
|
|
1149
1197
|
}
|
|
1150
1198
|
// Show the query/prompt being sent
|