@cluesmith/codev 3.3.2 → 3.3.4
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/dashboard-dist/assets/{index-D3XaKpZW.js → index-DZf6pNPE.js} +41 -41
- package/dashboard-dist/assets/index-DZf6pNPE.js.map +1 -0
- package/dashboard-dist/assets/index-DnYLy5C_.css +32 -0
- package/dashboard-dist/index.html +2 -2
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +48 -0
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/ide.d.ts +20 -0
- package/dist/agent-farm/commands/ide.d.ts.map +1 -0
- package/dist/agent-farm/commands/ide.js +138 -0
- package/dist/agent-farm/commands/ide.js.map +1 -0
- package/dist/agent-farm/commands/inbox.d.ts.map +1 -1
- package/dist/agent-farm/commands/inbox.js +79 -10
- package/dist/agent-farm/commands/inbox.js.map +1 -1
- package/dist/agent-farm/commands/interrupt.d.ts +4 -1
- package/dist/agent-farm/commands/interrupt.d.ts.map +1 -1
- package/dist/agent-farm/commands/interrupt.js +6 -3
- package/dist/agent-farm/commands/interrupt.js.map +1 -1
- package/dist/agent-farm/commands/reset.d.ts +4 -1
- package/dist/agent-farm/commands/reset.d.ts.map +1 -1
- package/dist/agent-farm/commands/reset.js +6 -3
- package/dist/agent-farm/commands/reset.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts +28 -0
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +79 -6
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js +16 -7
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
- package/dist/agent-farm/commands/tower.d.ts +21 -9
- package/dist/agent-farm/commands/tower.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower.js +90 -30
- package/dist/agent-farm/commands/tower.js.map +1 -1
- package/dist/agent-farm/db/index.d.ts +3 -1
- package/dist/agent-farm/db/index.d.ts.map +1 -1
- package/dist/agent-farm/db/index.js +8 -443
- package/dist/agent-farm/db/index.js.map +1 -1
- package/dist/agent-farm/db/mailbox.d.ts +47 -7
- package/dist/agent-farm/db/mailbox.d.ts.map +1 -1
- package/dist/agent-farm/db/mailbox.js +56 -12
- package/dist/agent-farm/db/mailbox.js.map +1 -1
- package/dist/agent-farm/db/migrations.d.ts +57 -0
- package/dist/agent-farm/db/migrations.d.ts.map +1 -0
- package/dist/agent-farm/db/migrations.js +530 -0
- package/dist/agent-farm/db/migrations.js.map +1 -0
- package/dist/agent-farm/db/schema.d.ts +1 -1
- package/dist/agent-farm/db/schema.d.ts.map +1 -1
- package/dist/agent-farm/db/schema.js +1 -0
- package/dist/agent-farm/db/schema.js.map +1 -1
- package/dist/agent-farm/db/tower-owner.d.ts +168 -0
- package/dist/agent-farm/db/tower-owner.d.ts.map +1 -0
- package/dist/agent-farm/db/tower-owner.js +369 -0
- package/dist/agent-farm/db/tower-owner.js.map +1 -0
- package/dist/agent-farm/db/types.d.ts +47 -0
- package/dist/agent-farm/db/types.d.ts.map +1 -1
- package/dist/agent-farm/db/types.js.map +1 -1
- package/dist/agent-farm/lib/ide-record.d.ts +65 -0
- package/dist/agent-farm/lib/ide-record.d.ts.map +1 -0
- package/dist/agent-farm/lib/ide-record.js +118 -0
- package/dist/agent-farm/lib/ide-record.js.map +1 -0
- package/dist/agent-farm/lib/tunnel-client.d.ts +22 -0
- package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.js +96 -19
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
- package/dist/agent-farm/servers/cron-delivery.d.ts +7 -1
- package/dist/agent-farm/servers/cron-delivery.d.ts.map +1 -1
- package/dist/agent-farm/servers/cron-delivery.js +2 -1
- package/dist/agent-farm/servers/cron-delivery.js.map +1 -1
- package/dist/agent-farm/servers/gate-profiles.d.ts +44 -2
- package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -1
- package/dist/agent-farm/servers/gate-profiles.js +79 -6
- package/dist/agent-farm/servers/gate-profiles.js.map +1 -1
- package/dist/agent-farm/servers/ide-forward.d.ts +62 -0
- package/dist/agent-farm/servers/ide-forward.d.ts.map +1 -0
- package/dist/agent-farm/servers/ide-forward.js +274 -0
- package/dist/agent-farm/servers/ide-forward.js.map +1 -0
- package/dist/agent-farm/servers/ide-server.d.ts +68 -0
- package/dist/agent-farm/servers/ide-server.d.ts.map +1 -0
- package/dist/agent-farm/servers/ide-server.js +281 -0
- package/dist/agent-farm/servers/ide-server.js.map +1 -0
- package/dist/agent-farm/servers/mailbox-delivery.d.ts +296 -12
- package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-delivery.js +566 -69
- package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.d.ts +66 -19
- package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.js +204 -37
- package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -1
- package/dist/agent-farm/servers/message-write.d.ts +138 -11
- package/dist/agent-farm/servers/message-write.d.ts.map +1 -1
- package/dist/agent-farm/servers/message-write.js +144 -35
- package/dist/agent-farm/servers/message-write.js.map +1 -1
- package/dist/agent-farm/servers/overview.d.ts +28 -12
- package/dist/agent-farm/servers/overview.d.ts.map +1 -1
- package/dist/agent-farm/servers/overview.js +130 -79
- package/dist/agent-farm/servers/overview.js.map +1 -1
- package/dist/agent-farm/servers/render-gate.d.ts +77 -1
- package/dist/agent-farm/servers/render-gate.d.ts.map +1 -1
- package/dist/agent-farm/servers/render-gate.js +174 -25
- package/dist/agent-farm/servers/render-gate.js.map +1 -1
- package/dist/agent-farm/servers/session-submit.d.ts +7 -4
- package/dist/agent-farm/servers/session-submit.d.ts.map +1 -1
- package/dist/agent-farm/servers/session-submit.js +7 -4
- package/dist/agent-farm/servers/session-submit.js.map +1 -1
- package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-cron.js +7 -3
- 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 +17 -10
- package/dist/agent-farm/servers/tower-instances.js.map +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts +32 -0
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +186 -26
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +79 -9
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts +21 -0
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +106 -13
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-utils.d.ts +35 -0
- package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-utils.js +39 -0
- package/dist/agent-farm/servers/tower-utils.js.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-websocket.js +26 -2
- package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
- package/dist/agent-farm/utils/message-format.d.ts +78 -2
- package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
- package/dist/agent-farm/utils/message-format.js +107 -11
- package/dist/agent-farm/utils/message-format.js.map +1 -1
- package/dist/agent-farm/utils/port.d.ts +22 -0
- package/dist/agent-farm/utils/port.d.ts.map +1 -0
- package/dist/agent-farm/utils/port.js +35 -0
- package/dist/agent-farm/utils/port.js.map +1 -0
- package/dist/agent-farm/utils/server-utils.d.ts +26 -0
- package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
- package/dist/agent-farm/utils/server-utils.js +36 -0
- package/dist/agent-farm/utils/server-utils.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +61 -1
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/consult/tree-tripwire.d.ts +177 -0
- package/dist/commands/consult/tree-tripwire.d.ts.map +1 -0
- package/dist/commands/consult/tree-tripwire.js +356 -0
- package/dist/commands/consult/tree-tripwire.js.map +1 -0
- package/dist/commands/doctor.d.ts +69 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +165 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/generate-image.d.ts +25 -1
- package/dist/commands/generate-image.d.ts.map +1 -1
- package/dist/commands/generate-image.js +410 -2
- package/dist/commands/generate-image.js.map +1 -1
- package/dist/commands/porch/prompts.d.ts.map +1 -1
- package/dist/commands/porch/prompts.js +18 -2
- package/dist/commands/porch/prompts.js.map +1 -1
- package/dist/lib/agent-env.d.ts +86 -0
- package/dist/lib/agent-env.d.ts.map +1 -0
- package/dist/lib/agent-env.js +126 -0
- package/dist/lib/agent-env.js.map +1 -0
- package/dist/lib/forge-contracts.d.ts +76 -5
- package/dist/lib/forge-contracts.d.ts.map +1 -1
- package/dist/lib/forge-contracts.js.map +1 -1
- package/dist/lib/forge-rate-limit.d.ts +45 -0
- package/dist/lib/forge-rate-limit.d.ts.map +1 -0
- package/dist/lib/forge-rate-limit.js +89 -0
- package/dist/lib/forge-rate-limit.js.map +1 -0
- package/dist/lib/forge.d.ts +29 -1
- package/dist/lib/forge.d.ts.map +1 -1
- package/dist/lib/forge.js +96 -21
- package/dist/lib/forge.js.map +1 -1
- package/dist/lib/github.d.ts +13 -1
- package/dist/lib/github.d.ts.map +1 -1
- package/dist/lib/github.js +58 -15
- package/dist/lib/github.js.map +1 -1
- package/dist/lib/test-env.d.ts +17 -0
- package/dist/lib/test-env.d.ts.map +1 -1
- package/dist/lib/test-env.js +20 -0
- package/dist/lib/test-env.js.map +1 -1
- package/dist/terminal/pty-manager.d.ts +10 -1
- package/dist/terminal/pty-manager.d.ts.map +1 -1
- package/dist/terminal/pty-manager.js +38 -9
- package/dist/terminal/pty-manager.js.map +1 -1
- package/dist/terminal/pty-session.d.ts +174 -8
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +299 -25
- package/dist/terminal/pty-session.js.map +1 -1
- package/dist/terminal/session-manager.d.ts +23 -2
- package/dist/terminal/session-manager.d.ts.map +1 -1
- package/dist/terminal/session-manager.js +115 -36
- package/dist/terminal/session-manager.js.map +1 -1
- package/dist/terminal/session-screen.d.ts +34 -5
- package/dist/terminal/session-screen.d.ts.map +1 -1
- package/dist/terminal/session-screen.js +52 -6
- package/dist/terminal/session-screen.js.map +1 -1
- package/dist/terminal/shellper-client.d.ts +73 -0
- package/dist/terminal/shellper-client.d.ts.map +1 -1
- package/dist/terminal/shellper-client.js +151 -0
- package/dist/terminal/shellper-client.js.map +1 -1
- package/dist/terminal/shellper-main.js +20 -3
- package/dist/terminal/shellper-main.js.map +1 -1
- package/dist/terminal/shellper-process.d.ts +2 -0
- package/dist/terminal/shellper-process.d.ts.map +1 -1
- package/dist/terminal/shellper-process.js +17 -1
- package/dist/terminal/shellper-process.js.map +1 -1
- package/dist/terminal/shellper-protocol.d.ts +28 -0
- package/dist/terminal/shellper-protocol.d.ts.map +1 -1
- package/dist/terminal/shellper-protocol.js.map +1 -1
- package/dist/terminal/terminal-replies.d.ts +102 -0
- package/dist/terminal/terminal-replies.d.ts.map +1 -0
- package/dist/terminal/terminal-replies.js +181 -0
- package/dist/terminal/terminal-replies.js.map +1 -0
- package/package.json +4 -4
- package/scripts/forge/gitea/_lib.sh +214 -0
- package/scripts/forge/gitea/issue-comment.sh +8 -1
- package/scripts/forge/gitea/issue-view.sh +95 -4
- package/scripts/forge/gitea/pr-create.sh +155 -0
- package/scripts/forge/gitea/pr-exists.sh +32 -4
- package/scripts/forge/gitea/pr-list.sh +40 -31
- package/scripts/forge/gitea/pr-view.sh +65 -4
- package/scripts/forge/gitea/recently-merged.sh +91 -21
- package/scripts/forge/gitea/user-identity.sh +30 -1
- package/scripts/forge/github/issue-view.sh +5 -2
- package/scripts/forge/github/pr-create.sh +47 -0
- package/scripts/forge/github/pr-list.sh +6 -2
- package/scripts/forge/github/pr-search.sh +6 -2
- package/scripts/forge/gitlab/issue-search.sh +1 -0
- package/scripts/forge/gitlab/issue-view.sh +24 -4
- package/scripts/forge/gitlab/pr-create.sh +53 -0
- package/scripts/forge/gitlab/pr-search.sh +37 -2
- package/scripts/forge/linear/auth-status.sh +1 -0
- package/scripts/forge/linear/issue-comment.sh +1 -0
- package/scripts/forge/linear/issue-list.sh +1 -0
- package/scripts/forge/linear/issue-search.sh +1 -0
- package/scripts/forge/linear/issue-view.sh +14 -2
- package/scripts/forge/linear/recently-closed.sh +1 -0
- package/scripts/forge/linear/user-identity.sh +1 -0
- package/skeleton/.claude/skills/generate-image/SKILL.md +39 -1
- package/skeleton/.codex/skills/generate-image/SKILL.md +39 -1
- package/skeleton/protocols/air/prompts/pr.md +6 -1
- package/skeleton/protocols/aspir/prompts/review.md +6 -1
- package/skeleton/protocols/bugfix/prompts/pr.md +6 -1
- package/skeleton/protocols/bugfix/protocol.md +2 -1
- package/skeleton/protocols/maintain/prompts/review.md +6 -1
- package/skeleton/protocols/pir/prompts/review.md +10 -7
- package/skeleton/protocols/spir/prompts/review.md +6 -1
- package/skeleton/resources/commands/agent-farm.md +28 -3
- package/skeleton/roles/consultant.md +32 -0
- package/skeleton/templates/AGENTS.md +1 -1
- package/skeleton/templates/CLAUDE.md +1 -1
- package/templates/tower.html +16 -1
- package/dashboard-dist/assets/index-BZRTEMtH.css +0 -32
- package/dashboard-dist/assets/index-D3XaKpZW.js.map +0 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Forge concept: pr-create (GitHub via gh CLI)
|
|
3
|
+
# forge-executable: gh
|
|
4
|
+
#
|
|
5
|
+
# Input: CODEV_PR_TITLE (required)
|
|
6
|
+
# CODEV_PR_BODY (required, may be empty)
|
|
7
|
+
# CODEV_PR_BASE, CODEV_PR_HEAD, CODEV_PR_REPO, CODEV_PR_DRAFT (optional)
|
|
8
|
+
# Output: {"number": <int>, "url": "<web url>"}
|
|
9
|
+
#
|
|
10
|
+
# `gh pr create` prints the new PR's URL on stdout; the number is its last path
|
|
11
|
+
# segment. Anything gh writes that isn't a URL (hints, prompts) is ignored.
|
|
12
|
+
set -e
|
|
13
|
+
|
|
14
|
+
if [ -z "$CODEV_PR_TITLE" ]; then
|
|
15
|
+
echo "pr-create: CODEV_PR_TITLE is required" >&2
|
|
16
|
+
exit 2
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# An empty body is allowed; an *absent* one is not. Without this, forgetting the
|
|
20
|
+
# variable opens a PR with no body at exit 0 — the silent failure #1455 is about.
|
|
21
|
+
if [ -z "${CODEV_PR_BODY+x}" ]; then
|
|
22
|
+
echo "pr-create: CODEV_PR_BODY is required (set it to \"\" for an empty body)" >&2
|
|
23
|
+
exit 2
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
set -- --title "$CODEV_PR_TITLE" --body "$CODEV_PR_BODY"
|
|
27
|
+
if [ -n "$CODEV_PR_BASE" ]; then set -- "$@" --base "$CODEV_PR_BASE"; fi
|
|
28
|
+
if [ -n "$CODEV_PR_HEAD" ]; then set -- "$@" --head "$CODEV_PR_HEAD"; fi
|
|
29
|
+
if [ -n "$CODEV_PR_REPO" ]; then set -- "$@" --repo "$CODEV_PR_REPO"; fi
|
|
30
|
+
if [ "$CODEV_PR_DRAFT" = "1" ]; then set -- "$@" --draft; fi
|
|
31
|
+
|
|
32
|
+
url=$(gh pr create "$@" | grep -E '^https?://' | tail -n 1)
|
|
33
|
+
|
|
34
|
+
if [ -z "$url" ]; then
|
|
35
|
+
echo "pr-create: gh pr create returned no PR URL" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
number=${url##*/}
|
|
40
|
+
case "$number" in
|
|
41
|
+
'' | *[!0-9]*)
|
|
42
|
+
echo "pr-create: could not parse a PR number from '$url'" >&2
|
|
43
|
+
exit 1
|
|
44
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
|
|
47
|
+
printf '{"number":%s,"url":"%s"}\n' "$number" "$url"
|
|
@@ -7,5 +7,9 @@
|
|
|
7
7
|
# as objects (users carry `login`; teams carry `slug`/`name` and no `login`), so
|
|
8
8
|
# `.login // empty` keeps user reviewers and drops team reviewers — matching the
|
|
9
9
|
# `reviewRequests: string[]` contract in PrListItem (forge-contracts.ts).
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
#
|
|
11
|
+
# Not `gh … | jq`: POSIX sh has no pipefail, so the caller would see jq's exit
|
|
12
|
+
# status and a rate-limited gh would look like a successful empty list (#1645).
|
|
13
|
+
# forge-executable: gh
|
|
14
|
+
out="$(gh pr list --json number,title,url,reviewDecision,body,createdAt,author,reviewRequests,isDraft)" || exit 1
|
|
15
|
+
printf '%s' "$out" | jq '[.[] | .reviewRequests = [.reviewRequests[].login // empty]]'
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: pr-search (GitHub via gh CLI)
|
|
3
3
|
# Input: CODEV_SEARCH_QUERY
|
|
4
|
-
# Output: JSON [{number, headRefName, baseRefName}]
|
|
5
|
-
|
|
4
|
+
# Output: JSON [{number, headRefName, baseRefName, state}]
|
|
5
|
+
# --state all is required so the search includes merged/closed PRs; without it
|
|
6
|
+
# `gh pr list` defaults to --state open and post-merge lookups return nothing (#759).
|
|
7
|
+
# `state` (OPEN/MERGED/CLOSED) lets consumers that only want open PRs filter
|
|
8
|
+
# client-side — the spawn collision guard must ignore merged/closed ones (#1637).
|
|
9
|
+
exec gh pr list --state all --search "$CODEV_SEARCH_QUERY" --json number,headRefName,baseRefName,state
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: issue-view (GitLab via glab CLI)
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
|
|
3
|
+
# Maps GitLab's fields into the forge-neutral IssueView shape. `. + {…}` is
|
|
4
|
+
# non-destructive for keys we don't touch; the mapped keys are optional by
|
|
5
|
+
# contract, so a shape mismatch degrades to an omitted line rather than a crash
|
|
6
|
+
# (jq returns null for missing keys, and the guards below tolerate null):
|
|
7
|
+
# web_url -> url
|
|
8
|
+
# author.username -> author.login
|
|
9
|
+
# created_at -> createdAt
|
|
10
|
+
# assignees[].username -> assignees[].login
|
|
11
|
+
# labels[] -> labels[].name (newer glab emits label objects; older emits strings)
|
|
12
|
+
# milestone.title -> milestone.title (null when unset)
|
|
13
|
+
# Best-effort preset (Spec 589): fields GitLab doesn't expose stay absent. The
|
|
14
|
+
# contract's optional fields are added only when present (via `+ {…}` merges) so
|
|
15
|
+
# an absent field is OMITTED, not emitted as null — `author?`/`createdAt?` are not
|
|
16
|
+
# nullable (only `milestone` is). `exec` is dropped: with a pipe it would replace
|
|
17
|
+
# only the glab subshell, not the whole pipeline, so it's misleading here.
|
|
18
|
+
glab issue view "$CODEV_ISSUE_ID" --output json | jq '
|
|
19
|
+
.
|
|
20
|
+
+ {url: .web_url}
|
|
21
|
+
+ {assignees: [(.assignees // [])[] | {login: .username}]}
|
|
22
|
+
+ {labels: [(.labels // [])[] | if type == "string" then {name: .} else {name: .name} end]}
|
|
23
|
+
+ (if .author.username then {author: {login: .author.username}} else {} end)
|
|
24
|
+
+ (if .created_at then {createdAt: .created_at} else {} end)
|
|
25
|
+
+ (if .milestone then {milestone: {title: .milestone.title}} else {} end)
|
|
26
|
+
'
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Forge concept: pr-create (GitLab via glab CLI — merge requests)
|
|
3
|
+
# forge-executable: glab
|
|
4
|
+
#
|
|
5
|
+
# Input: CODEV_PR_TITLE (required)
|
|
6
|
+
# CODEV_PR_BODY (required, may be empty)
|
|
7
|
+
# CODEV_PR_BASE, CODEV_PR_HEAD, CODEV_PR_REPO, CODEV_PR_DRAFT (optional)
|
|
8
|
+
# Output: {"number": <int>, "url": "<web url>"}
|
|
9
|
+
#
|
|
10
|
+
# ⚠️ UNVERIFIED — `glab` is not available in the authoring environment (same
|
|
11
|
+
# constraint as gitea/issue-search.sh, #920). Written against glab's
|
|
12
|
+
# documented `mr create` flags; smoke-test before relying on it. Without this
|
|
13
|
+
# file the gitlab preset would fall through to the GitHub default and shell
|
|
14
|
+
# out to `gh` — the bug this concept exists to close (#1455).
|
|
15
|
+
#
|
|
16
|
+
# `glab mr create --yes` skips the interactive prompts and prints the new MR's
|
|
17
|
+
# URL; the number (GitLab's `iid`) is its last path segment.
|
|
18
|
+
set -e
|
|
19
|
+
|
|
20
|
+
if [ -z "$CODEV_PR_TITLE" ]; then
|
|
21
|
+
echo "pr-create: CODEV_PR_TITLE is required" >&2
|
|
22
|
+
exit 2
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# An empty body is allowed; an *absent* one is not. Without this, forgetting the
|
|
26
|
+
# variable opens a PR with no body at exit 0 — the silent failure #1455 is about.
|
|
27
|
+
if [ -z "${CODEV_PR_BODY+x}" ]; then
|
|
28
|
+
echo "pr-create: CODEV_PR_BODY is required (set it to \"\" for an empty body)" >&2
|
|
29
|
+
exit 2
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
set -- --title "$CODEV_PR_TITLE" --description "$CODEV_PR_BODY" --yes
|
|
33
|
+
if [ -n "$CODEV_PR_BASE" ]; then set -- "$@" --target-branch "$CODEV_PR_BASE"; fi
|
|
34
|
+
if [ -n "$CODEV_PR_HEAD" ]; then set -- "$@" --source-branch "$CODEV_PR_HEAD"; fi
|
|
35
|
+
if [ -n "$CODEV_PR_REPO" ]; then set -- "$@" --repo "$CODEV_PR_REPO"; fi
|
|
36
|
+
if [ "$CODEV_PR_DRAFT" = "1" ]; then set -- "$@" --draft; fi
|
|
37
|
+
|
|
38
|
+
url=$(glab mr create "$@" | grep -E '^https?://' | tail -n 1)
|
|
39
|
+
|
|
40
|
+
if [ -z "$url" ]; then
|
|
41
|
+
echo "pr-create: glab mr create returned no MR URL" >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
number=${url##*/}
|
|
46
|
+
case "$number" in
|
|
47
|
+
'' | *[!0-9]*)
|
|
48
|
+
echo "pr-create: could not parse an MR number from '$url'" >&2
|
|
49
|
+
exit 1
|
|
50
|
+
;;
|
|
51
|
+
esac
|
|
52
|
+
|
|
53
|
+
printf '{"number":%s,"url":"%s"}\n' "$number" "$url"
|
|
@@ -1,3 +1,38 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
-
# Forge concept: pr-search (GitLab via glab CLI)
|
|
3
|
-
|
|
2
|
+
# Forge concept: pr-search (GitLab via glab CLI — merge requests)
|
|
3
|
+
# Output: JSON [{number, headRefName, baseRefName, state, ...glab fields}]
|
|
4
|
+
#
|
|
5
|
+
# ⚠️ UNVERIFIED — `glab` is not available in the authoring environment (#920);
|
|
6
|
+
# written against glab's documented `mr list --output json` shape (confirmed
|
|
7
|
+
# against the field mappings already documented in gitlab/pr-list.sh and
|
|
8
|
+
# gitlab/pr-exists.sh). Smoke-test before relying on it.
|
|
9
|
+
#
|
|
10
|
+
# --all is required so the search includes merged/closed MRs; without it
|
|
11
|
+
# `glab mr list` defaults to opened only and post-merge lookups return nothing (#759).
|
|
12
|
+
#
|
|
13
|
+
# Maps glab's GitLab-shaped fields into the forge-neutral PrSearchItem contract
|
|
14
|
+
# (forge-contracts.ts); `. + {…}` is non-destructive for keys we don't touch:
|
|
15
|
+
# iid -> number (the MR number glab mr view/merge expects)
|
|
16
|
+
# source_branch -> headRefName
|
|
17
|
+
# target_branch -> baseRefName
|
|
18
|
+
# Without this the spawn guard's message reads `PR #undefined` and consult's
|
|
19
|
+
# findPRForIssue can't resolve the MR's base branch on GitLab.
|
|
20
|
+
#
|
|
21
|
+
# glab reports state lowercase (opened/merged/closed/locked); normalize to the
|
|
22
|
+
# GitHub convention (OPEN/MERGED/CLOSED) so consumers filter with one comparison.
|
|
23
|
+
# The spawn collision guard keys off state === "OPEN" to ignore merged MRs (#1637).
|
|
24
|
+
# `locked` (a transient merging state) maps to OPEN too: the guard should err
|
|
25
|
+
# toward the recoverable --force prompt, never silently skip a live collision.
|
|
26
|
+
#
|
|
27
|
+
# Not `glab … | jq`: POSIX sh has no pipefail, so the caller would see jq's exit
|
|
28
|
+
# status and a failed glab would look like a successful empty list (#1645).
|
|
29
|
+
# The capture-then-pipe shape hides `glab` from extractExecutable's first-line
|
|
30
|
+
# heuristic (it lands on the `printf` builtin), so declare the backend explicitly
|
|
31
|
+
# — same as github/pr-list.sh (#1645).
|
|
32
|
+
# forge-executable: glab
|
|
33
|
+
out="$(glab mr list --all --search "$CODEV_SEARCH_QUERY" --output json)" || exit 1
|
|
34
|
+
printf '%s' "$out" | jq 'map(.
|
|
35
|
+
+ {number: .iid}
|
|
36
|
+
+ {headRefName: .source_branch}
|
|
37
|
+
+ {baseRefName: .target_branch}
|
|
38
|
+
+ {state: ((.state // "") | ascii_downcase as $s | if $s == "opened" or $s == "locked" then "OPEN" else ($s | ascii_upcase) end)})'
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: issue-view (Linear via GraphQL API)
|
|
3
|
+
# forge-executable: curl
|
|
3
4
|
# Input: CODEV_ISSUE_ID (e.g. "ENG-123")
|
|
4
|
-
# Output: JSON {title, body, state, url, comments[]}
|
|
5
|
+
# Output: JSON {title, body, state, url, author, createdAt, assignees, labels, milestone, comments[]}
|
|
6
|
+
#
|
|
7
|
+
# Maps Linear's fields into the forge-neutral IssueView shape. Linear has a
|
|
8
|
+
# single `assignee` (emitted as a one-element `assignees` array) and `project`
|
|
9
|
+
# rather than milestones (mapped into `milestone.title`). These fields are
|
|
10
|
+
# optional by contract, so anything Linear leaves null degrades to an omitted
|
|
11
|
+
# line. Best-effort preset (Spec 589).
|
|
5
12
|
set -e
|
|
6
13
|
|
|
7
14
|
if [ -z "$LINEAR_API_KEY" ]; then
|
|
@@ -18,7 +25,7 @@ curl -sf -X POST https://api.linear.app/graphql \
|
|
|
18
25
|
-H "Content-Type: application/json" \
|
|
19
26
|
-H "Authorization: $LINEAR_API_KEY" \
|
|
20
27
|
-d "$(jq -n --arg id "$CODEV_ISSUE_ID" '{
|
|
21
|
-
query: "query($id: String!) { issueVcsByFilter: issues(filter: { identifier: { eq: $id } }) { nodes { title url description state { name } comments { nodes { body createdAt user { displayName } } } } } }",
|
|
28
|
+
query: "query($id: String!) { issueVcsByFilter: issues(filter: { identifier: { eq: $id } }) { nodes { title url description createdAt state { name } creator { displayName } assignee { displayName } labels { nodes { name } } project { name } comments { nodes { body createdAt user { displayName } } } } } }",
|
|
22
29
|
variables: { id: $id }
|
|
23
30
|
}')" \
|
|
24
31
|
| jq 'if (.data.issueVcsByFilter.nodes | length) == 0 then
|
|
@@ -29,6 +36,11 @@ curl -sf -X POST https://api.linear.app/graphql \
|
|
|
29
36
|
url: .url,
|
|
30
37
|
body: (.description // ""),
|
|
31
38
|
state: .state.name,
|
|
39
|
+
author: (if .creator then { login: .creator.displayName } else null end),
|
|
40
|
+
createdAt: .createdAt,
|
|
41
|
+
assignees: (if .assignee then [{ login: .assignee.displayName }] else [] end),
|
|
42
|
+
labels: [(.labels.nodes // [])[] | { name: .name }],
|
|
43
|
+
milestone: (if .project then { title: .project.name } else null end),
|
|
32
44
|
comments: [.comments.nodes[] | {
|
|
33
45
|
body: .body,
|
|
34
46
|
createdAt: .createdAt,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generate-image
|
|
3
|
-
description: AI image generation via Gemini. Use when the user wants to generate, create, or make an image, or when you need to create visual assets like logos, diagrams, or illustrations. Requires
|
|
3
|
+
description: AI image generation via Gemini with optional async providers. Use when the user wants to generate, create, or make an image, or when you need to create visual assets like logos, diagrams, or illustrations. Requires the API key for the selected provider.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# generate-image - AI Image Generation
|
|
@@ -22,6 +22,7 @@ Note: this is a `codev` subcommand, not standalone.
|
|
|
22
22
|
-r, --resolution <res> Resolution: 1K, 2K, 4K (default: 1K)
|
|
23
23
|
-a, --aspect <ratio> Aspect ratio (default: 1:1)
|
|
24
24
|
--ref <image> Reference image (repeatable, max 14)
|
|
25
|
+
-p, --provider <name> Provider name (default: gemini)
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
## Aspect ratios
|
|
@@ -43,3 +44,40 @@ codev generate-image prompt.txt -o result.png # Prompt from .txt file
|
|
|
43
44
|
- Prompt can be a `.txt` file path (auto-detected by extension)
|
|
44
45
|
- Reference images must exist on disk
|
|
45
46
|
- Requires `GEMINI_API_KEY` or `GOOGLE_API_KEY` environment variable
|
|
47
|
+
|
|
48
|
+
## Alternative provider: Atlas Cloud
|
|
49
|
+
|
|
50
|
+
`-p atlas` generates through Atlas Cloud, which serves the same Nano Banana Pro
|
|
51
|
+
model over a submit-then-poll REST API. Useful when a Google AI Studio key is
|
|
52
|
+
not available. Requires `ATLASCLOUD_API_KEY`; the default provider is unchanged.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
codev generate-image "A sunset over mountains" -p atlas -a 16:9
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Measured differences on that path:
|
|
59
|
+
|
|
60
|
+
- `-a/--aspect` works (`1:1` returns 1024x1024, `16:9` returns 1376x768).
|
|
61
|
+
- `-r/--resolution` has no equivalent field; a note is printed and the model's
|
|
62
|
+
default resolution comes back.
|
|
63
|
+
- `--ref` is not supported (text-to-image only) and exits with an error rather
|
|
64
|
+
than silently ignoring the images.
|
|
65
|
+
- The model returns JPEG, so the output file is named after its actual bytes
|
|
66
|
+
instead of writing JPEG into the default `output.png`.
|
|
67
|
+
|
|
68
|
+
## MuAPI provider
|
|
69
|
+
|
|
70
|
+
`-p muapi` uses MuAPI's Nano Banana Pro endpoint with the same aspect-ratio and
|
|
71
|
+
resolution controls. Set `MUAPI_API_KEY` (or `MU_API_KEY`) using the [MuAPI
|
|
72
|
+
access keys page](https://muapi.ai/access-keys). Reference images are uploaded
|
|
73
|
+
to MuAPI and sent to the edit endpoint; returned media is downloaded only over
|
|
74
|
+
HTTPS.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
codev generate-image "A sunset over mountains" -p muapi -a 16:9
|
|
78
|
+
codev generate-image "Keep the subject, change the lighting" -p muapi --ref subject.png
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The provider submits a job, polls the [MuAPI image API](https://muapi.ai/ai-image-api),
|
|
82
|
+
and writes the returned image locally. Polling and individual requests are
|
|
83
|
+
bounded, and the API key is never sent to the returned media host.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generate-image
|
|
3
|
-
description: AI image generation via Gemini. Use when the user wants to generate, create, or make an image, or when you need to create visual assets like logos, diagrams, or illustrations. Requires
|
|
3
|
+
description: AI image generation via Gemini with optional async providers. Use when the user wants to generate, create, or make an image, or when you need to create visual assets like logos, diagrams, or illustrations. Requires the API key for the selected provider.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# generate-image - AI Image Generation
|
|
@@ -22,6 +22,7 @@ Note: this is a `codev` subcommand, not standalone.
|
|
|
22
22
|
-r, --resolution <res> Resolution: 1K, 2K, 4K (default: 1K)
|
|
23
23
|
-a, --aspect <ratio> Aspect ratio (default: 1:1)
|
|
24
24
|
--ref <image> Reference image (repeatable, max 14)
|
|
25
|
+
-p, --provider <name> Provider name (default: gemini)
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
## Aspect ratios
|
|
@@ -43,3 +44,40 @@ codev generate-image prompt.txt -o result.png # Prompt from .txt file
|
|
|
43
44
|
- Prompt can be a `.txt` file path (auto-detected by extension)
|
|
44
45
|
- Reference images must exist on disk
|
|
45
46
|
- Requires `GEMINI_API_KEY` or `GOOGLE_API_KEY` environment variable
|
|
47
|
+
|
|
48
|
+
## Alternative provider: Atlas Cloud
|
|
49
|
+
|
|
50
|
+
`-p atlas` generates through Atlas Cloud, which serves the same Nano Banana Pro
|
|
51
|
+
model over a submit-then-poll REST API. Useful when a Google AI Studio key is
|
|
52
|
+
not available. Requires `ATLASCLOUD_API_KEY`; the default provider is unchanged.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
codev generate-image "A sunset over mountains" -p atlas -a 16:9
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Measured differences on that path:
|
|
59
|
+
|
|
60
|
+
- `-a/--aspect` works (`1:1` returns 1024x1024, `16:9` returns 1376x768).
|
|
61
|
+
- `-r/--resolution` has no equivalent field; a note is printed and the model's
|
|
62
|
+
default resolution comes back.
|
|
63
|
+
- `--ref` is not supported (text-to-image only) and exits with an error rather
|
|
64
|
+
than silently ignoring the images.
|
|
65
|
+
- The model returns JPEG, so the output file is named after its actual bytes
|
|
66
|
+
instead of writing JPEG into the default `output.png`.
|
|
67
|
+
|
|
68
|
+
## MuAPI provider
|
|
69
|
+
|
|
70
|
+
`-p muapi` uses MuAPI's Nano Banana Pro endpoint with the same aspect-ratio and
|
|
71
|
+
resolution controls. Set `MUAPI_API_KEY` (or `MU_API_KEY`) using the [MuAPI
|
|
72
|
+
access keys page](https://muapi.ai/access-keys). Reference images are uploaded
|
|
73
|
+
to MuAPI and sent to the edit endpoint; returned media is downloaded only over
|
|
74
|
+
HTTPS.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
codev generate-image "A sunset over mountains" -p muapi -a 16:9
|
|
78
|
+
codev generate-image "Keep the subject, change the lighting" -p muapi --ref subject.png
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The provider submits a job, polls the [MuAPI image API](https://muapi.ai/ai-image-api),
|
|
82
|
+
and writes the returned image locally. Polling and individual requests are
|
|
83
|
+
bounded, and the API key is never sent to the returned media host.
|
|
@@ -18,7 +18,8 @@ Open the PR with the review embedded in its body, optionally run CMAP, and notif
|
|
|
18
18
|
The body must carry `Closes #<N>` for the driving issue — one per issue if several — so GitHub auto-closes it on merge. **Exception:** a partial fix uses `Refs #<N>` or `Part of #<N>` instead. Substitute the real number for `<N>`; leave no `{{...}}` tag or `<N>` placeholder in the committed body.
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
|
|
21
|
+
export CODEV_PR_TITLE="[Air #<N>] feat: <brief description>"
|
|
22
|
+
export CODEV_PR_BODY="$(cat <<'EOF'
|
|
22
23
|
## Summary
|
|
23
24
|
|
|
24
25
|
<1-2 sentence description of the feature>
|
|
@@ -44,8 +45,12 @@ Closes #<N> <!-- Substitute <N>; use "Refs #<N>" for a partial fix -->
|
|
|
44
45
|
<anything the reviewer should focus on, or "Standard implementation — no special concerns">
|
|
45
46
|
EOF
|
|
46
47
|
)"
|
|
48
|
+
|
|
49
|
+
{{pr_create_command}}
|
|
47
50
|
```
|
|
48
51
|
|
|
52
|
+
The command above is your forge's `pr-create` concept, substituted by porch (`gh pr create` by default). It takes `CODEV_PR_TITLE` / `CODEV_PR_BODY` — optionally `CODEV_PR_BASE`, `CODEV_PR_HEAD`, `CODEV_PR_REPO` — from the environment, which is why they are exported rather than prefixed onto the command line: an inline override that spells `--title "$CODEV_PR_TITLE"` needs them set in the calling shell too. It prints `{"number": <int>, "url": "<url>"}`.
|
|
53
|
+
|
|
49
54
|
## Optional CMAP review
|
|
50
55
|
|
|
51
56
|
CMAP is your judgement call for AIR. Skip it for simple changes (config, small UI); run it for features touching core logic or several modules:
|
|
@@ -44,7 +44,8 @@ The review's `## Architecture Updates` and `## Lessons Learned Updates` sections
|
|
|
44
44
|
The PR body must carry `Closes #<N>` (feature) or `Fixes #<N>` (bug) for the driving issue — one keyword per issue if several — so GitHub auto-closes on merge. **Exception:** a PR that only partially addresses its issue uses `Refs #<N>` or `Part of #<N>` instead, leaving the issue open for the follow-up.
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
|
|
47
|
+
export CODEV_PR_TITLE="[Spec {{project_id}}] {{title}}"
|
|
48
|
+
export CODEV_PR_BODY="$(cat <<'EOF'
|
|
48
49
|
## Summary
|
|
49
50
|
[what was implemented]
|
|
50
51
|
|
|
@@ -63,8 +64,12 @@ codev/specs/{{artifact_name}}.md
|
|
|
63
64
|
codev/reviews/{{artifact_name}}.md
|
|
64
65
|
EOF
|
|
65
66
|
)"
|
|
67
|
+
|
|
68
|
+
{{pr_create_command}}
|
|
66
69
|
```
|
|
67
70
|
|
|
71
|
+
The command above is your forge's `pr-create` concept, substituted by porch (`gh pr create` by default). It takes `CODEV_PR_TITLE` / `CODEV_PR_BODY` — optionally `CODEV_PR_BASE`, `CODEV_PR_HEAD`, `CODEV_PR_REPO` — from the environment, which is why they are exported rather than prefixed onto the command line: an inline override that spells `--title "$CODEV_PR_TITLE"` needs them set in the calling shell too. It prints `{"number": <int>, "url": "<url>"}`.
|
|
72
|
+
|
|
68
73
|
## Signals
|
|
69
74
|
|
|
70
75
|
- Review document complete:
|
|
@@ -16,7 +16,8 @@ Open the PR, run CMAP review on it, address feedback, and hand off to the archit
|
|
|
16
16
|
The PR body must carry `Fixes #<N>` for the driving issue — one per issue if several — so GitHub auto-closes it on merge. **Exception:** a PR that only partially addresses the issue uses `Refs #<N>` or `Part of #<N>` instead, leaving it open for the follow-up. Substitute the real number for `<N>`; leave no `{{...}}` tag or `<N>` placeholder in the committed body.
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
|
|
19
|
+
export CODEV_PR_TITLE="Fix #<N>: <brief description>"
|
|
20
|
+
export CODEV_PR_BODY="$(cat <<'EOF'
|
|
20
21
|
## Summary
|
|
21
22
|
|
|
22
23
|
<1-2 sentence description of the bug and fix>
|
|
@@ -38,8 +39,12 @@ Fixes #<N> <!-- Substitute <N>; use "Refs #<N>" for a partial fix -->
|
|
|
38
39
|
- [ ] All tests pass
|
|
39
40
|
EOF
|
|
40
41
|
)"
|
|
42
|
+
|
|
43
|
+
{{pr_create_command}}
|
|
41
44
|
```
|
|
42
45
|
|
|
46
|
+
The command above is your forge's `pr-create` concept, substituted by porch (`gh pr create` by default). It takes `CODEV_PR_TITLE` / `CODEV_PR_BODY` — optionally `CODEV_PR_BASE`, `CODEV_PR_HEAD`, `CODEV_PR_REPO` — from the environment, which is why they are exported rather than prefixed onto the command line: an inline override that spells `--title "$CODEV_PR_TITLE"` needs them set in the calling shell too. It prints `{"number": <int>, "url": "<url>"}`.
|
|
47
|
+
|
|
43
48
|
## Run CMAP review
|
|
44
49
|
|
|
45
50
|
BUGFIX runs its own 3-way consultation on the PR (porch does not do it for you). Dispatch all three in the background:
|
|
@@ -27,7 +27,8 @@ refactor surrounding code, fix unrelated bugs (file separate issues), or add fea
|
|
|
27
27
|
[Bugfix #42] Test: regression for unencoded username
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
**PR** — open with `
|
|
30
|
+
**PR** — open with the `pr-create` forge concept command the PR-phase prompt hands you (`gh
|
|
31
|
+
pr create` on GitHub), body carrying Summary, Root Cause, Fix and Test Plan plus
|
|
31
32
|
`Fixes #<N>` so the issue closes on merge. Run one CMAP pass (Gemini, Codex, Claude), record
|
|
32
33
|
each verdict, and address or rebut every `REQUEST_CHANGES`. Notify the architect with the
|
|
33
34
|
verdicts, then `porch done <id>` and wait.
|
|
@@ -46,7 +46,8 @@ If the run was not tied to any issue, the `Closes` line can be omitted.
|
|
|
46
46
|
```bash
|
|
47
47
|
git push origin HEAD
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
export CODEV_PR_TITLE="[Maintain] Codebase maintenance run NNNN"
|
|
50
|
+
export CODEV_PR_BODY="$(cat <<'PREOF'
|
|
50
51
|
## Summary
|
|
51
52
|
|
|
52
53
|
<2-3 bullet points of what was done>
|
|
@@ -67,8 +68,12 @@ Closes #<N> <!-- Only if this run was triggered by a GitHub issue. Use "Refs #<
|
|
|
67
68
|
- [x] Documentation links resolve
|
|
68
69
|
PREOF
|
|
69
70
|
)"
|
|
71
|
+
|
|
72
|
+
{{pr_create_command}}
|
|
70
73
|
```
|
|
71
74
|
|
|
75
|
+
The command above is your forge's `pr-create` concept, substituted by porch (`gh pr create` by default). It takes `CODEV_PR_TITLE` / `CODEV_PR_BODY` — optionally `CODEV_PR_BASE`, `CODEV_PR_HEAD`, `CODEV_PR_REPO` — from the environment, which is why they are exported rather than prefixed onto the command line: an inline override that spells `--title "$CODEV_PR_TITLE"` needs them set in the calling shell too. It prints `{"number": <int>, "url": "<url>"}`.
|
|
76
|
+
|
|
72
77
|
## Signals
|
|
73
78
|
|
|
74
79
|
When PR is created:
|
|
@@ -108,13 +108,16 @@ git push
|
|
|
108
108
|
PR_TITLE="<concise description of the change>"
|
|
109
109
|
BRANCH="$(git branch --show-current)"
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
export CODEV_PR_TITLE="$PR_TITLE"
|
|
112
|
+
export CODEV_PR_BODY="$(cat codev/reviews/{{artifact_name}}.md)"
|
|
113
|
+
export CODEV_PR_BASE=main
|
|
114
|
+
export CODEV_PR_HEAD="$BRANCH"
|
|
115
|
+
|
|
116
|
+
{{pr_create_command}}
|
|
116
117
|
```
|
|
117
118
|
|
|
119
|
+
The command above is your forge's `pr-create` concept, substituted by porch (`gh pr create` by default). It prints `{"number": <int>, "url": "<url>"}`. The inputs are **exported** so an inline override that spells `--title "$CODEV_PR_TITLE"` sees them too. The body goes in as an environment variable, not `--body-file` — read the created PR back and confirm the body arrived intact before moving on.
|
|
120
|
+
|
|
118
121
|
**Verify the PR body contains `Fixes #{{issue.number}}`** (it should — the review file has it at the top). If somehow missing, edit and re-apply:
|
|
119
122
|
|
|
120
123
|
```bash
|
|
@@ -154,7 +157,7 @@ For any `REQUEST_CHANGES`:
|
|
|
154
157
|
|
|
155
158
|
1. Read the finding in full (`codev/projects/{{project_id}}-*/{{project_id}}-<model>.txt`).
|
|
156
159
|
2. **Assess it honestly:**
|
|
157
|
-
- **Real defect** (correctness / cancellation / security / data-loss): fix it in code, add a regression test that fails without the fix, commit + push (the PR updates automatically — no
|
|
160
|
+
- **Real defect** (correctness / cancellation / security / data-loss): fix it in code, add a regression test that fails without the fix, commit + push (the PR updates automatically — no second PR). Then document the finding, your fix, and the pinning test in the review file's **"Things to Look At During PR Review"** section.
|
|
158
161
|
- **False positive / out of scope**: write a brief rebuttal in that same section explaining why no change is warranted.
|
|
159
162
|
3. Do **not** re-run `porch done` expecting another consultation pass — `max_iterations: 1` means it will not re-review. Proceed to step 7.
|
|
160
163
|
|
|
@@ -257,7 +260,7 @@ Together with the `--pr` record from step 4a and the `--merged` record from step
|
|
|
257
260
|
```
|
|
258
261
|
- Resolve conflicts (do NOT use destructive shortcuts)
|
|
259
262
|
- Force-push with lease: `git push --force-with-lease`
|
|
260
|
-
- Re-run
|
|
263
|
+
- Re-run the PR creation command from step 4
|
|
261
264
|
|
|
262
265
|
**If porch's consultation fails (e.g., model unavailable):**
|
|
263
266
|
- `porch done` will report the failure. Inspect `codev/projects/{{project_id}}-*/{{project_id}}-<model>.txt` for the failure details.
|
|
@@ -44,7 +44,8 @@ The review's `## Architecture Updates` and `## Lessons Learned Updates` sections
|
|
|
44
44
|
The PR body must carry `Closes #<N>` (feature) or `Fixes #<N>` (bug) for the driving issue — one keyword per issue if several — so GitHub auto-closes on merge. **Exception:** a PR that only partially addresses its issue uses `Refs #<N>` or `Part of #<N>` instead, leaving the issue open for the follow-up.
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
|
|
47
|
+
export CODEV_PR_TITLE="[Spec {{project_id}}] {{title}}"
|
|
48
|
+
export CODEV_PR_BODY="$(cat <<'EOF'
|
|
48
49
|
## Summary
|
|
49
50
|
[what was implemented]
|
|
50
51
|
|
|
@@ -63,8 +64,12 @@ codev/specs/{{artifact_name}}.md
|
|
|
63
64
|
codev/reviews/{{artifact_name}}.md
|
|
64
65
|
EOF
|
|
65
66
|
)"
|
|
67
|
+
|
|
68
|
+
{{pr_create_command}}
|
|
66
69
|
```
|
|
67
70
|
|
|
71
|
+
The command above is your forge's `pr-create` concept, substituted by porch (`gh pr create` by default). It takes `CODEV_PR_TITLE` / `CODEV_PR_BODY` — optionally `CODEV_PR_BASE`, `CODEV_PR_HEAD`, `CODEV_PR_REPO` — from the environment, which is why they are exported rather than prefixed onto the command line: an inline override that spells `--title "$CODEV_PR_TITLE"` needs them set in the calling shell too. It prints `{"number": <int>, "url": "<url>"}`.
|
|
72
|
+
|
|
68
73
|
## Signals
|
|
69
74
|
|
|
70
75
|
- Review document complete:
|
|
@@ -391,11 +391,36 @@ Sends text to a builder's terminal. Useful for:
|
|
|
391
391
|
|
|
392
392
|
- **delivered** — the message was written to the recipient's prompt after a clean render-gate pass (an empty, render-verified prompt).
|
|
393
393
|
- **held** — the prompt was not clear, so the message is persisted in Tower's durable mailbox and **delivers automatically** the moment the recipient's prompt is clean (after a submit, on output quiescence, or a poll backstop). The response carries a **why-held reason** and a mailbox id:
|
|
394
|
-
- `busy` —
|
|
394
|
+
- `busy` — the prompt is occupied. `afx inbox` qualifies it with the gate's own detail:
|
|
395
|
+
`busy:user-text` (a draft, menu, dialog, or wrapper screen), `busy:recent-input` (the
|
|
396
|
+
terminal received input within the last fraction of a second — a keystroke, a click, or an
|
|
397
|
+
ungated `--interrupt`/`--escape` write — so the composer may be changing under the gate; it
|
|
398
|
+
clears by itself a moment after the input stops), `busy:composer-redraw` (the composer is
|
|
399
|
+
empty but its rendered region moved a moment ago — a turn-end redraw, a rotating
|
|
400
|
+
placeholder, a resize; also self-clearing, about a quarter second after it stops moving), or
|
|
401
|
+
`busy:no-region-end` / `busy:no-composer-marker` (the classifier could not verify the
|
|
402
|
+
composer at all — the one hold class that does NOT clear on its own);
|
|
395
403
|
- `no-profile` — the target app has no render-gate classifier profile (only `claude`, `codex`, and `agy` are modeled);
|
|
396
404
|
- `no-live-pty` — the recipient agent has no live terminal right now (it delivers when the agent respawns — rows address agents, not PTYs).
|
|
397
405
|
|
|
398
|
-
A
|
|
406
|
+
**A recipient that is simply TALKING does not hold mail** (Issue #1664). claude and codex accept
|
|
407
|
+
input during a turn and queue it for the next one, so a message written onto their empty composer
|
|
408
|
+
mid-turn is safe and lands as one message when the turn ends — the gate waits only on the
|
|
409
|
+
*composer*, never on the spinner or the streaming transcript above it. Before that, mail queued
|
|
410
|
+
behind whole turns: measured over 24 h, 227 deliveries waited more than 2 s, averaging 54 s and
|
|
411
|
+
peaking at 561 s.
|
|
412
|
+
|
|
413
|
+
A held message is **never force-injected** onto a busy line: a message body is only ever written to a verified-empty prompt, so it cannot fuse with a draft the gate can see, and held rows survive Tower restart/shutdown (no shutdown force-flush). Two signals make a draft visible (Issue #1473) — the composer classifier reads it off the rendered screen, and every write that reaches the PTY **through Tower** (browser and VS Code keystrokes, the terminal input API, an ungated `--interrupt`/`--escape`) is observed there — whatever survives the terminal-reply filter bumps an input counter the gate folds into its change token, so even a keystroke the app has not echoed yet holds the message, while a chunk that is nothing but a DA/DSR/CPR answer moves nothing. **`afx attach` is the one exception:** it pipes your keystrokes straight to the shellper socket, never through Tower's `PtySession.write()`, so they move no counter — a draft typed under `afx attach` is seen only once the app has echoed it and the classifier can read it off the screen. See held mail with `afx inbox`, read one (including its body) with `afx inbox show <id>`, and clear one with `afx inbox dismiss <id>`. `--interrupt` is the explicit, deliberate bypass: it interrupts the agent and writes without holding (unchanged semantics).
|
|
414
|
+
|
|
415
|
+
**How a body is typed (Issue #1567):** a frame under 4 lines and at most 256 bytes is one write plus
|
|
416
|
+
Enter, as always. Anything longer is written as **one explicit bracketed paste** (`ESC[200~ … ESC[201~`,
|
|
417
|
+
in ≤512-byte pieces 5 ms apart) with the Enter as a separate write after a short settle. This is the fix
|
|
418
|
+
for the delivery-side head loss where a >1 KB single write was split by the PTY input queue and the
|
|
419
|
+
recipient's paste heuristic discarded the first chunk (only the tail arrived, with `delivered` at the
|
|
420
|
+
sender). While it sits in the composer, claude shows the paste as `[Pasted text #N +M lines]` and codex
|
|
421
|
+
as `[Pasted Content N chars]`; the echo verification behind the `(unverified — …)` suffix accepts a new
|
|
422
|
+
placard as well as the header, so a correct long delivery is reported verified. agy keeps the older
|
|
423
|
+
line-by-line shape (also chunked) because its paste handling has not been measured.
|
|
399
424
|
|
|
400
425
|
**Examples:**
|
|
401
426
|
|
|
@@ -432,7 +457,7 @@ afx inbox dismiss <id> [options]
|
|
|
432
457
|
| `ID` | Mailbox row id (pass to `show` / `dismiss`) |
|
|
433
458
|
| `AGE` | How long the message has been held (`5s`, `3m`, `2h`, `1d`) |
|
|
434
459
|
| `REASON` | Why-held: `busy`, `no-profile`, or `no-live-pty`; a trailing `!` marks a row past the escalation age |
|
|
435
|
-
| `FROM → TO` | Sender → recipient agent |
|
|
460
|
+
| `FROM → TO` | Sender → recipient agent. An architect sender carries its name (`architect:main`); the column is sized to its content, so long ids are never truncated |
|
|
436
461
|
| `WORKSPACE` | Owning workspace |
|
|
437
462
|
|
|
438
463
|
**Options:**
|