@cluesmith/codev 3.3.2 → 3.3.3
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-CUIjS_Vb.js} +41 -41
- package/dashboard-dist/assets/index-CUIjS_Vb.js.map +1 -0
- package/dashboard-dist/assets/index-DnYLy5C_.css +32 -0
- package/dashboard-dist/index.html +2 -2
- package/dist/agent-farm/commands/inbox.d.ts.map +1 -1
- package/dist/agent-farm/commands/inbox.js +67 -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 +64 -6
- package/dist/agent-farm/commands/send.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/types.d.ts +22 -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/tunnel-client.d.ts.map +1 -1
- package/dist/agent-farm/lib/tunnel-client.js +43 -14
- 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 +21 -0
- package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -1
- package/dist/agent-farm/servers/gate-profiles.js +36 -4
- package/dist/agent-farm/servers/gate-profiles.js.map +1 -1
- package/dist/agent-farm/servers/mailbox-delivery.d.ts +83 -8
- package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-delivery.js +102 -26
- package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.d.ts +48 -15
- package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -1
- package/dist/agent-farm/servers/mailbox-wiring.js +116 -22
- package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -1
- package/dist/agent-farm/servers/render-gate.d.ts +24 -1
- package/dist/agent-farm/servers/render-gate.d.ts.map +1 -1
- package/dist/agent-farm/servers/render-gate.js +50 -12
- package/dist/agent-farm/servers/render-gate.js.map +1 -1
- package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-cron.js +3 -2
- 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 +11 -3
- 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 +133 -13
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +15 -2
- 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 +53 -5
- 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 +8 -1
- 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 +102 -5
- package/dist/agent-farm/utils/message-format.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/doctor.js +2 -2
- package/dist/commands/generate-image.d.ts +20 -1
- package/dist/commands/generate-image.d.ts.map +1 -1
- package/dist/commands/generate-image.js +188 -1
- 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/forge-contracts.d.ts +66 -5
- package/dist/lib/forge-contracts.d.ts.map +1 -1
- package/dist/lib/forge-contracts.js.map +1 -1
- package/dist/lib/forge.d.ts +1 -1
- package/dist/lib/forge.d.ts.map +1 -1
- package/dist/lib/forge.js +33 -11
- package/dist/lib/forge.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 +52 -4
- package/dist/terminal/pty-session.d.ts.map +1 -1
- package/dist/terminal/pty-session.js +157 -18
- package/dist/terminal/pty-session.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/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-search.sh +3 -1
- 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 +3 -1
- package/scripts/forge/linear/issue-view.sh +13 -2
- package/skeleton/.claude/skills/generate-image/SKILL.md +22 -1
- package/skeleton/.codex/skills/generate-image/SKILL.md +22 -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 +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,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,5 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: pr-search (GitLab via glab CLI)
|
|
3
|
-
|
|
3
|
+
# --all is required so the search includes merged/closed MRs; without it
|
|
4
|
+
# `glab mr list` defaults to opened only and post-merge lookups return nothing (#759).
|
|
5
|
+
exec glab mr list --all --search "$CODEV_SEARCH_QUERY" --output json
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Forge concept: issue-view (Linear via GraphQL API)
|
|
3
3
|
# Input: CODEV_ISSUE_ID (e.g. "ENG-123")
|
|
4
|
-
# Output: JSON {title, body, state, url, comments[]}
|
|
4
|
+
# Output: JSON {title, body, state, url, author, createdAt, assignees, labels, milestone, comments[]}
|
|
5
|
+
#
|
|
6
|
+
# Maps Linear's fields into the forge-neutral IssueView shape. Linear has a
|
|
7
|
+
# single `assignee` (emitted as a one-element `assignees` array) and `project`
|
|
8
|
+
# rather than milestones (mapped into `milestone.title`). These fields are
|
|
9
|
+
# optional by contract, so anything Linear leaves null degrades to an omitted
|
|
10
|
+
# line. Best-effort preset (Spec 589).
|
|
5
11
|
set -e
|
|
6
12
|
|
|
7
13
|
if [ -z "$LINEAR_API_KEY" ]; then
|
|
@@ -18,7 +24,7 @@ curl -sf -X POST https://api.linear.app/graphql \
|
|
|
18
24
|
-H "Content-Type: application/json" \
|
|
19
25
|
-H "Authorization: $LINEAR_API_KEY" \
|
|
20
26
|
-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 } } } } } }",
|
|
27
|
+
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
28
|
variables: { id: $id }
|
|
23
29
|
}')" \
|
|
24
30
|
| jq 'if (.data.issueVcsByFilter.nodes | length) == 0 then
|
|
@@ -29,6 +35,11 @@ curl -sf -X POST https://api.linear.app/graphql \
|
|
|
29
35
|
url: .url,
|
|
30
36
|
body: (.description // ""),
|
|
31
37
|
state: .state.name,
|
|
38
|
+
author: (if .creator then { login: .creator.displayName } else null end),
|
|
39
|
+
createdAt: .createdAt,
|
|
40
|
+
assignees: (if .assignee then [{ login: .assignee.displayName }] else [] end),
|
|
41
|
+
labels: [(.labels.nodes // [])[] | { name: .name }],
|
|
42
|
+
milestone: (if .project then { title: .project.name } else null end),
|
|
32
43
|
comments: [.comments.nodes[] | {
|
|
33
44
|
body: .body,
|
|
34
45
|
createdAt: .createdAt,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generate-image
|
|
3
|
-
description: AI image generation via Gemini
|
|
3
|
+
description: AI image generation via Gemini, or Atlas Cloud with `-p atlas`. 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 GEMINI_API_KEY or GOOGLE_API_KEY, or ATLASCLOUD_API_KEY when using `-p atlas`.
|
|
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: gemini (default) or atlas
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
## Aspect ratios
|
|
@@ -43,3 +44,23 @@ 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`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generate-image
|
|
3
|
-
description: AI image generation via Gemini
|
|
3
|
+
description: AI image generation via Gemini, or Atlas Cloud with `-p atlas`. 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 GEMINI_API_KEY or GOOGLE_API_KEY, or ATLASCLOUD_API_KEY when using `-p atlas`.
|
|
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: gemini (default) or atlas
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
## Aspect ratios
|
|
@@ -43,3 +44,23 @@ 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`.
|
|
@@ -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:
|
|
@@ -432,7 +432,7 @@ afx inbox dismiss <id> [options]
|
|
|
432
432
|
| `ID` | Mailbox row id (pass to `show` / `dismiss`) |
|
|
433
433
|
| `AGE` | How long the message has been held (`5s`, `3m`, `2h`, `1d`) |
|
|
434
434
|
| `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 |
|
|
435
|
+
| `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
436
|
| `WORKSPACE` | Owning workspace |
|
|
437
437
|
|
|
438
438
|
**Options:**
|
package/templates/tower.html
CHANGED
|
@@ -1667,6 +1667,11 @@
|
|
|
1667
1667
|
|
|
1668
1668
|
async function fetchCloudStatus() {
|
|
1669
1669
|
try {
|
|
1670
|
+
// Served through the tunnel, /api/tunnel/* is local-only — blocked at
|
|
1671
|
+
// the tunnel edge and again by Tower (#1370), so this poll can only
|
|
1672
|
+
// ever 403 (#1599). The widget renders nothing cloud-served anyway;
|
|
1673
|
+
// skip the forbidden request instead of paying it every refresh.
|
|
1674
|
+
if (isCloudServed()) return null;
|
|
1670
1675
|
const res = await authFetch('./api/tunnel/status');
|
|
1671
1676
|
if (res.status === 404) return null;
|
|
1672
1677
|
if (!res.ok) return { state: 'error' };
|
|
@@ -1676,6 +1681,16 @@
|
|
|
1676
1681
|
}
|
|
1677
1682
|
}
|
|
1678
1683
|
|
|
1684
|
+
// Is this page being viewed through Codev Cloud rather than served by the
|
|
1685
|
+
// local Tower directly? One shared predicate for the tunnel-status poll
|
|
1686
|
+
// and the cloud widget render, so the two can never drift (#1599).
|
|
1687
|
+
// Exact-or-subdomain match, not a bare suffix — `endsWith('codevos.ai')`
|
|
1688
|
+
// would also match an unrelated `evilcodevos.ai` (CMAP).
|
|
1689
|
+
function isCloudServed() {
|
|
1690
|
+
const h = window.location.hostname;
|
|
1691
|
+
return h === 'codevos.ai' || h.endsWith('.codevos.ai');
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1679
1694
|
function formatUptime(ms) {
|
|
1680
1695
|
const s = Math.floor(ms / 1000);
|
|
1681
1696
|
if (s < 60) return s + 's';
|
|
@@ -1723,7 +1738,7 @@
|
|
|
1723
1738
|
noteCloudStateChange(status && status.state ? status.state : null);
|
|
1724
1739
|
|
|
1725
1740
|
// When accessed through codevos.ai, cloud status is irrelevant
|
|
1726
|
-
if (
|
|
1741
|
+
if (isCloudServed()) {
|
|
1727
1742
|
el.innerHTML = '';
|
|
1728
1743
|
return;
|
|
1729
1744
|
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
|
-
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
|
-
* https://github.com/chjj/term.js
|
|
5
|
-
* @license MIT
|
|
6
|
-
*
|
|
7
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
-
* in the Software without restriction, including without limitation the rights
|
|
10
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
-
* furnished to do so, subject to the following conditions:
|
|
13
|
-
*
|
|
14
|
-
* The above copyright notice and this permission notice shall be included in
|
|
15
|
-
* all copies or substantial portions of the Software.
|
|
16
|
-
*
|
|
17
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
-
* THE SOFTWARE.
|
|
24
|
-
*
|
|
25
|
-
* Originally forked from (with the author's permission):
|
|
26
|
-
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
27
|
-
* http://bellard.org/jslinux/
|
|
28
|
-
* Copyright (c) 2011 Fabrice Bellard
|
|
29
|
-
* The original design remains. The terminal itself
|
|
30
|
-
* has been extended to include xterm CSI codes, among
|
|
31
|
-
* other features.
|
|
32
|
-
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{--bg-primary: #1a1a1a;--bg-secondary: #252525;--bg-tertiary: #2a2a2a;--bg-hover: #333333;--text-primary: #e0e0e0;--text-secondary: #a0a0a0;--text-muted: #666666;--border-color: #333333;--accent: #3b82f6;--accent-hover: #2563eb;--status-active: #22c55e;--status-waiting: #eab308;--status-error: #ef4444;--status-implementing: #f97316}*{margin:0;padding:0;box-sizing:border-box}html,body,#root{height:100%;width:100%;overflow:hidden}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,monospace;background:var(--bg-primary);color:var(--text-primary);font-size:13px}.fullscreen-terminal{height:100vh;width:100vw;overflow:hidden}.fullscreen-terminal>div{height:100%;width:100%}.app{display:flex;flex-direction:column;height:100vh}.app-header{display:flex;align-items:center;justify-content:space-between;padding:8px 16px;background:var(--bg-secondary);border-bottom:1px solid var(--border-color);height:40px;flex-shrink:0}.app-title{font-size:14px;font-weight:600;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.header-version{font-size:11px;color:var(--text-secondary);font-weight:400}.app-body{flex:1;overflow:hidden}.split-pane{display:flex;height:100%;width:100%}.split-left,.split-right{height:100%;overflow:hidden;position:relative}.split-handle{width:4px;cursor:col-resize;background:var(--border-color);flex-shrink:0}.split-handle:hover{background:var(--accent)}.expand-bar{width:24px;height:100%;flex-shrink:0;display:flex;align-items:center;justify-content:center;background:var(--bg-secondary);border:none;border-left:1px solid var(--border-color);border-right:1px solid var(--border-color);color:var(--text-muted);cursor:pointer;padding:0;font-family:inherit}.expand-bar:hover{background:var(--bg-hover);color:var(--accent)}.header-controls{display:flex;align-items:center;gap:4px}.header-btn{display:flex;align-items:center;justify-content:center;width:32px;height:28px;padding:0;background:transparent;border:1px solid var(--border-color);border-radius:4px;color:var(--text-secondary);cursor:pointer}.header-btn:hover{background:var(--bg-hover);color:var(--text-primary);border-color:var(--accent)}.right-panel{display:flex;flex-direction:column;height:100%}.tab-bar{display:flex;background:var(--bg-secondary);border-bottom:1px solid var(--border-color);overflow-x:auto;flex-shrink:0;height:34px}.tab{display:flex;align-items:center;gap:6px;padding:6px 12px;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-secondary);font-size:12px;cursor:pointer;white-space:nowrap;font-family:inherit}.tab:hover{background:var(--bg-hover);color:var(--text-primary)}.tab-active{color:var(--text-primary);border-bottom-color:var(--accent)}.tab-icon{flex-shrink:0}.tab-label{max-width:120px;overflow:hidden;text-overflow:ellipsis}.tab-close{font-size:14px;line-height:1;opacity:.5;padding:0 2px;border-radius:3px}.tab-close:hover{opacity:1;background:var(--bg-hover)}.remove-architect-modal-backdrop,.confirm-dialog-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000}.remove-architect-modal,.confirm-dialog{background:var(--bg-primary, #1e1e1e);color:var(--text-primary, #e0e0e0);border-radius:6px;padding:24px;max-width:500px;width:90%;box-shadow:0 10px 40px #00000080}.remove-architect-modal h2,.confirm-dialog h2{margin:0 0 12px;font-size:18px}.remove-architect-modal p,.confirm-dialog p{margin:0 0 16px;line-height:1.5}.remove-architect-modal code,.confirm-dialog code{background:var(--bg-secondary, #2a2a2a);padding:2px 6px;border-radius:3px;font-family:ui-monospace,monospace}.remove-architect-error{color:var(--text-error, #ff6b6b)}.remove-architect-modal-actions,.confirm-dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.remove-architect-modal-actions button,.confirm-dialog-actions button{padding:6px 14px;border:1px solid var(--border-color, #444);background:var(--bg-secondary, #2a2a2a);color:var(--text-primary, #e0e0e0);border-radius:4px;cursor:pointer}.remove-architect-modal-actions button:hover:not(:disabled),.confirm-dialog-actions button:hover:not(:disabled){background:var(--bg-hover, #333)}.remove-architect-modal-actions button.primary,.confirm-dialog-actions button.primary{background:var(--accent-color, #f44747);color:#fff;border-color:var(--accent-color, #f44747)}.remove-architect-modal-actions button:disabled,.confirm-dialog-actions button:disabled{opacity:.6;cursor:not-allowed}.tab-content{flex:1;overflow:hidden}.terminal-tab-pane{width:100%;height:100%}.file-path-decoration{border-bottom:1px dotted rgba(255,255,255,.3)!important;background:transparent!important;pointer-events:none}.file-path-decoration-hover{border-bottom-color:#ffffffb3!important}.terminal-iframe{display:block}.file-tree{padding:8px;overflow-y:auto;height:100%}.file-node{display:flex;align-items:center;gap:6px;padding:3px 0;cursor:pointer;font-size:12px;border-radius:4px}.file-node:hover{background:var(--bg-hover)}.file-icon{font-size:14px;flex-shrink:0}.file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-tree-error,.file-tree-loading{padding:16px;color:var(--text-muted);font-size:12px}.no-architect{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-muted);font-size:14px}.architect-pane{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;min-height:0}.architect-pane-body{flex:1;min-height:0}.virtual-keyboard{display:flex;gap:6px;padding:6px 8px;background:var(--bg-secondary);border-bottom:1px solid var(--border-color);flex-shrink:0}.virtual-key{padding:4px 12px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;color:var(--text-secondary);font-size:12px;font-family:inherit;cursor:pointer;touch-action:manipulation;user-select:none;-webkit-user-select:none}.virtual-key:active{background:var(--bg-hover);color:var(--text-primary)}.virtual-key-active{background:var(--accent);border-color:var(--accent);color:#fff}.virtual-key-active:active{background:var(--accent-hover)}.terminal-controls{position:absolute;top:8px;right:12px;z-index:20;display:flex;align-items:center;gap:4px;padding:4px 6px;background:#1e1e1ed9;border:1px solid rgba(255,255,255,.12);border-radius:8px}.terminal-control-btn{display:flex;align-items:center;justify-content:center;min-width:32px;min-height:32px;padding:0;background:transparent;border:1px solid transparent;border-radius:5px;color:silver;cursor:pointer;touch-action:manipulation;user-select:none;-webkit-user-select:none}.terminal-control-btn:hover{background:#ffffff1a;border-color:#ffffff26;color:#fff}.terminal-control-btn:active{background:#ffffff26}.toolbar-divider{width:1px;height:20px;background:#ffffff26;margin:0 2px;flex-shrink:0}.terminal-status-icon{cursor:default}.terminal-status-icon.terminal-status-connected{color:#22c55e;opacity:.7}.terminal-status-icon.terminal-status-reconnecting{color:#eab308;opacity:.8;animation:terminal-pulse 1.2s ease-in-out infinite}.terminal-status-icon.terminal-status-disconnected{color:#ef4444;opacity:.8}@keyframes terminal-pulse{0%,to{opacity:.8}50%{opacity:.2}}.mobile-layout{display:flex;flex-direction:column;height:100vh}.mobile-content{flex:1;overflow:hidden;display:flex;flex-direction:column}@media(max-width:768px){.app-header{padding:6px 12px}.tab{padding:4px 8px;font-size:11px}}.file-viewer{display:flex;flex-direction:column;height:100%;background:var(--bg-primary)}.file-loading,.file-error{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-secondary)}.file-error{color:var(--status-error)}.file-header{display:flex;align-items:center;gap:12px;padding:8px 12px;background:var(--bg-secondary);border-bottom:1px solid var(--border-color);flex-shrink:0}.file-path{font-family:monospace;font-size:12px;color:var(--text-primary);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-language{font-size:11px;color:var(--text-muted);text-transform:uppercase}.file-save-btn{padding:4px 12px;font-size:11px;background:var(--accent);color:#fff;border:none;border-radius:4px;cursor:pointer}.file-save-btn:hover{background:var(--accent-hover)}.file-save-btn:disabled{opacity:.5;cursor:not-allowed}.file-content{display:flex;flex:1;overflow:auto;background:var(--bg-primary)}.line-numbers{display:flex;flex-direction:column;padding:12px 8px;background:var(--bg-secondary);color:var(--text-muted);font-family:Menlo,Monaco,Courier New,monospace;font-size:13px;line-height:1.5;text-align:right;-webkit-user-select:none;user-select:none;flex-shrink:0;min-width:40px}.line-number{padding-right:8px}.line-number.highlighted-line{background:#3b82f64d}.file-text{flex:1;padding:12px;font-family:Menlo,Monaco,Courier New,monospace;font-size:13px;line-height:1.5;background:var(--bg-primary);color:var(--text-primary);border:none;outline:none;resize:none;white-space:pre;overflow:auto}.file-image-container,.file-video-container{flex:1;display:flex;align-items:center;justify-content:center;overflow:auto;padding:20px}.file-image{max-width:100%;max-height:100%;object-fit:contain}.file-video{max-width:100%;max-height:100%}.file-tree-container{display:flex;flex-direction:column;height:100%;overflow:hidden}.file-search{position:relative;padding:8px;border-bottom:1px solid var(--border-color);flex-shrink:0}.file-search-input{width:100%;padding:6px 10px;font-size:12px;font-family:inherit;background:var(--bg-primary);border:1px solid var(--border-color);border-radius:4px;color:var(--text-primary);outline:none}.file-search-input:focus{border-color:var(--accent)}.file-search-input::placeholder{color:var(--text-muted)}.file-search-suggestions{position:absolute;top:100%;left:8px;right:8px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:4px;box-shadow:0 4px 12px #0000004d;z-index:100;max-height:240px;overflow-y:auto}.file-search-suggestion{display:flex;flex-direction:column;padding:8px 10px;cursor:pointer;border-bottom:1px solid var(--border-color)}.file-search-suggestion:last-child{border-bottom:none}.file-search-suggestion:hover{background:var(--bg-hover)}.suggestion-name{font-size:12px;color:var(--text-primary);font-weight:500}.suggestion-path{font-size:10px;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-tree-section{display:flex;flex-direction:column;overflow:hidden}.file-tree-section:first-of-type{flex-shrink:0}.file-tree-section:last-of-type{flex:1;overflow:hidden}.file-tree-section-header{padding:8px 12px;font-size:11px;font-weight:600;text-transform:uppercase;color:var(--text-muted);letter-spacing:.5px;border-bottom:1px solid var(--border-color);flex-shrink:0}.recent-file{color:var(--text-secondary)}.recent-file:hover{color:var(--text-primary)}.file-path-hint{font-size:10px;color:var(--text-muted);margin-left:auto;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.git-indicator{font-family:monospace;font-size:10px;font-weight:700;padding:1px 4px;border-radius:3px;margin-left:auto;flex-shrink:0}.git-modified{color:var(--status-implementing);background:#f9731626}.git-staged{color:var(--status-active);background:#22c55e26}.git-untracked{color:var(--text-muted);background:#66666626}.cloud-status{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-secondary);margin-right:12px}.cloud-status--none{color:var(--text-muted)}.cloud-status--error{color:var(--status-error)}.cloud-dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0}.cloud-dot--green{background:var(--status-active)}.cloud-dot--yellow{background:var(--status-waiting);animation:cloud-pulse 1.2s ease-in-out infinite}@keyframes cloud-pulse{0%,to{opacity:1}50%{opacity:.3}}.cloud-dot--red{background:var(--status-error)}.cloud-dot--gray{background:var(--text-muted)}.cloud-uptime{color:var(--text-muted);font-size:11px}.held-badge{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-secondary);white-space:nowrap}.held-badge--attention{color:var(--status-waiting);font-weight:600}.held-dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--text-muted)}.held-dot--attention{background:var(--status-waiting);animation:cloud-pulse 1.2s ease-in-out infinite}.cloud-hint{color:var(--text-muted);font-size:11px;font-style:italic}.cloud-link{color:var(--accent);text-decoration:none;font-size:11px}.cloud-link:hover{text-decoration:underline}.cloud-btn{background:transparent;border:1px solid var(--border-color);color:var(--text-secondary);font-size:11px;padding:1px 6px;border-radius:3px;cursor:pointer}.cloud-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.cloud-btn:disabled{opacity:.5;cursor:default}.mobile-wrapper{display:flex;flex-direction:column;height:100vh}.mobile-header{padding:4px 8px;border-bottom:1px solid var(--border-color);background:var(--bg-primary)}.mobile-wrapper .mobile-layout{flex:1;min-height:0}.work-view{display:flex;flex-direction:column;height:100%;overflow:hidden}.work-content{flex:1;overflow-y:auto;padding:12px 16px}.work-view.file-panel-open .work-content{flex:2}.work-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.work-title{font-size:19px;font-weight:600;color:var(--text-primary)}.work-actions{display:flex;gap:6px}.work-btn{background:var(--accent);color:#fff;border:none;padding:4px 10px;border-radius:4px;font-size:14px;cursor:pointer}.work-btn:hover{background:var(--accent-hover)}.work-btn-secondary{background:transparent;border:1px solid var(--border-color);color:var(--text-secondary)}.work-btn-secondary:hover{background:var(--bg-hover);color:var(--text-primary)}.tip-banner{display:flex;align-items:center;gap:8px;padding:6px 12px;margin-bottom:16px;background:var(--bg-tertiary);border-radius:4px;font-size:14px;color:var(--text-secondary)}.tip-banner-label{font-weight:600;color:var(--text-muted);white-space:nowrap}.tip-banner-text{flex:1;min-width:0}.tip-banner-text code{font-family:var(--font-mono, monospace);background:var(--bg-primary);padding:1px 4px;border-radius:2px;font-size:13px;color:var(--text-primary)}.tip-banner-nav{background:none;border:none;color:var(--text-muted);cursor:pointer;padding:2px 4px;font-size:14px;line-height:1;border-radius:2px}.tip-banner-nav:hover{color:var(--text-primary);background:var(--bg-hover)}.tip-banner-dismiss{background:none;border:none;color:var(--text-muted);cursor:pointer;padding:2px 4px;font-size:14px;line-height:1;border-radius:2px;margin-left:4px}.tip-banner-dismiss:hover{color:var(--text-primary);background:var(--bg-hover)}.work-section{margin-bottom:20px}.work-section-title{font-size:13px;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px;display:flex;align-items:center;gap:6px}.work-empty{color:var(--text-muted);font-style:italic;font-size:14px;padding:8px 0}.work-unavailable{color:var(--status-waiting);font-size:14px;padding:8px 0}.work-error{color:var(--status-error);font-size:14px;padding:8px;margin-bottom:12px;background:#ef44441a;border-radius:4px}.work-loading{color:var(--text-muted);padding:16px}.builder-table{width:100%;border-collapse:separate;border-spacing:0 4px}.builder-table thead th{font-size:13px;font-weight:500;color:var(--text-secondary);text-align:left;padding:0 10px 4px;white-space:nowrap}.builder-row td{background:var(--bg-secondary);padding:8px 10px;font-size:16px;border-top:1px solid var(--border-color);border-bottom:1px solid var(--border-color)}.builder-row td:first-child{border-left:1px solid var(--border-color);border-radius:8px 0 0 8px}.builder-row td:last-child{border-right:1px solid var(--border-color);border-radius:0 8px 8px 0}.builder-row:hover td{border-color:var(--accent)}.builder-row--blocked td:first-child{border-left:3px solid var(--status-waiting)}.builder-col-id{font-weight:500;color:var(--accent);white-space:nowrap;min-width:60px}.builder-attribution{font-size:.9em;color:var(--text-secondary);font-weight:400}.builder-col-title{color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:0;width:40%}.builder-col-state{white-space:nowrap;width:140px}.builder-state-active{font-size:14px;color:var(--accent)}.builder-state-blocked{font-size:14px;color:var(--status-waiting)}.builder-col-progress{width:120px;white-space:nowrap}.progress-bar{width:80px;height:4px;background:var(--bg-tertiary);border-radius:2px;overflow:hidden;display:inline-block;vertical-align:middle}.progress-fill{height:100%;background:var(--status-active);border-radius:2px;transition:width .3s ease}.progress-fill--blocked{background:var(--status-waiting)}.progress-pct{font-size:13px;color:var(--text-secondary);margin-left:6px;vertical-align:middle}.builder-col-elapsed{font-size:14px;color:var(--text-secondary);white-space:nowrap;width:70px}.builder-col-actions{width:60px;text-align:right}.builder-row-open{font-size:13px;color:var(--accent);background:#3b82f614;border:1px solid rgba(59,130,246,.2);padding:3px 10px;border-radius:5px;cursor:pointer;white-space:nowrap}.builder-row-open:hover{background:#3b82f62e}.pr-rows{display:flex;flex-direction:column;gap:4px}a.pr-row{text-decoration:none;color:inherit;cursor:pointer}.pr-row{display:flex;align-items:center;gap:10px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:8px;padding:10px 14px}.pr-row:hover{border-color:var(--accent)}.pr-row-number{font-size:16px;font-weight:500;color:var(--accent);white-space:nowrap}.pr-row-title{flex:1;font-size:16px;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pr-row-status{font-size:13px;white-space:nowrap}.pr-status--approved{color:var(--status-active)}.pr-status--reviewing{color:var(--status-waiting)}.pr-status--changes{color:var(--status-error)}.pr-row-age{font-size:13px;color:var(--text-muted);white-space:nowrap}.pr-row-author{font-size:12px;color:var(--text-muted);white-space:nowrap}.attention-rows{display:flex;flex-direction:column;gap:4px}a.attention-row{text-decoration:none;color:inherit;cursor:pointer}.attention-row{display:flex;align-items:center;gap:10px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:8px;padding:10px 14px}.attention-row:hover{border-color:var(--accent)}.attention-row-id{font-size:16px;font-weight:500;color:var(--accent);white-space:nowrap}.attention-row-title{flex:1;font-size:16px;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.attention-row-kind{font-size:13px;white-space:nowrap}.attention-kind--pr{color:var(--status-waiting)}.attention-kind--spec,.attention-kind--plan{color:var(--status-error)}.attention-kind--dev{color:var(--status-implementing)}.attention-kind--verify{color:var(--status-waiting)}.attention-row-age{font-size:13px;color:var(--text-muted);white-space:nowrap}.backlog-rows{display:flex;flex-direction:column;gap:2px}.backlog-row{display:flex;align-items:center;gap:6px;padding:4px 14px;border-radius:6px}.backlog-row:hover{background:var(--bg-secondary)}.backlog-row-main{display:flex;align-items:center;gap:10px;flex:1;min-width:0;text-decoration:none;color:inherit}.backlog-row-main:hover .backlog-row-title{color:var(--accent)}.backlog-artifacts{display:flex;gap:4px;flex-shrink:0}.backlog-artifact-link{font-size:12px;padding:1px 5px;border-radius:3px;border:1px solid var(--border-color);background:transparent;color:var(--text-secondary);cursor:pointer;white-space:nowrap}.backlog-artifact-link:hover{background:var(--bg-hover);color:var(--accent);border-color:var(--accent)}.backlog-priority-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}.priority-dot--high{background:var(--status-error)}.priority-dot--med{background:var(--status-waiting)}.priority-dot--low{background:var(--text-muted)}.backlog-row-number{font-size:16px;font-weight:500;color:var(--accent);white-space:nowrap}.backlog-type-tag{font-size:12px;padding:1px 5px;border-radius:3px;font-weight:500;white-space:nowrap}.type-tag--bug{background:#ef444426;color:var(--status-error)}.type-tag--project{background:#a855f71f;color:#a855f7}.type-tag--spike{background:#0ea5e91f;color:#0ea5e9}.backlog-row-title{flex:1;font-size:16px;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.backlog-row-age{font-size:13px;color:var(--text-muted);white-space:nowrap}.backlog-row-author,.backlog-row-assignees{font-size:12px;color:var(--text-muted);white-space:nowrap}.recently-closed-rows{display:flex;flex-direction:column;gap:2px}.recently-closed-row{display:flex;align-items:center;gap:6px;padding:4px 14px;border-radius:6px;opacity:.7}.recently-closed-row:hover{background:var(--bg-secondary);opacity:1}.recently-closed-row-main{display:flex;align-items:center;gap:10px;flex:1;min-width:0;text-decoration:none;color:inherit}.recently-closed-check{font-size:13px;color:var(--status-active);flex-shrink:0}.work-file-panel{border-top:1px solid var(--border-color);background:var(--bg-secondary)}.work-file-panel.expanded{flex:1;display:flex;flex-direction:column;overflow:hidden}.work-file-panel.collapsed{flex-shrink:0}.work-file-panel-header{display:flex;align-items:center;gap:6px;padding:6px 12px;cursor:pointer;-webkit-user-select:none;user-select:none}.work-file-panel-header:hover{background:var(--bg-hover)}.work-file-panel-toggle{font-size:12px;color:var(--text-muted)}.work-file-panel-label{font-size:14px;font-weight:500;color:var(--text-secondary)}.work-file-panel-search{flex:1;margin-left:8px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:3px;color:var(--text-primary);font-size:14px;padding:3px 8px;outline:none}.work-file-panel-search::placeholder{color:var(--text-muted)}.work-file-panel-search:focus{border-color:var(--accent)}.work-file-panel-content{flex:1;overflow-y:auto;padding:0 12px 12px}@media(max-width:768px){.work-content{padding:8px 12px}.work-header{flex-wrap:wrap;gap:8px}.pr-row,.attention-row{flex-wrap:wrap}.builder-table{font-size:14px}.builder-col-elapsed,.builder-table thead th:nth-child(5){display:none}.pr-row-title,.attention-row-title,.backlog-row-title{min-width:60%}}.analytics-view{display:flex;flex-direction:column;height:100%;overflow:hidden}.analytics-content{flex:1;overflow-y:auto;padding:12px 16px}.analytics-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.analytics-title{font-size:16px;font-weight:600;color:var(--text-primary)}.analytics-actions{display:flex;gap:6px;align-items:center}.analytics-range-selector{display:flex;border:1px solid var(--border-color);border-radius:4px;overflow:hidden}.analytics-range-btn{background:transparent;border:none;border-right:1px solid var(--border-color);padding:3px 8px;font-size:11px;cursor:pointer;color:var(--text-secondary)}.analytics-range-btn:last-child{border-right:none}.analytics-range-btn:hover{background:var(--bg-hover)}.analytics-range-btn.active{background:var(--accent);color:#fff}.analytics-section{margin-bottom:16px}.analytics-section-title{font-size:11px;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px;display:flex;align-items:center;gap:4px}.analytics-collapse-icon{font-size:10px;width:12px;display:inline-block}.analytics-error{color:var(--status-error);font-size:12px;margin-bottom:8px;padding:6px 8px;background:#ef44441a;border-radius:4px}.analytics-loading{color:var(--text-secondary);font-size:13px;padding:20px 0;text-align:center}.analytics-metric-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px}.analytics-metric{display:flex;flex-direction:column;padding:8px 10px;background:var(--bg-secondary, var(--bg-hover));border-radius:4px}.analytics-metric-value{font-size:18px;font-weight:600;color:var(--text-primary);line-height:1.2}.analytics-metric-label{font-size:10px;color:var(--text-secondary);margin-top:2px}.analytics-sub-section{margin-top:10px}.analytics-sub-title{font-size:11px;font-weight:500;color:var(--text-secondary);margin-bottom:4px}.analytics-table{width:100%;border-collapse:collapse;font-size:11px}.analytics-table th{text-align:left;color:var(--text-secondary);font-weight:500;padding:3px 6px;border-bottom:1px solid var(--border-color)}.analytics-table td{padding:3px 6px;color:var(--text-primary);border-bottom:1px solid var(--border-subtle, var(--border-color))}.analytics-list{list-style:none;padding:0;margin:0}.analytics-list li{display:flex;justify-content:space-between;padding:2px 0;font-size:12px}.analytics-list-label{color:var(--text-secondary)}.analytics-list-value{color:var(--text-primary);font-weight:500}.analytics-charts-row{display:flex;gap:8px}.analytics-chart-half{flex:1;min-width:0}.team-view{display:flex;flex-direction:column;height:100%;overflow:hidden}.team-content{flex:1;overflow-y:auto;padding:12px 16px}.team-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.team-title{font-size:16px;font-weight:600;color:var(--text-primary);margin:0}.team-refresh-btn{background:transparent;border:1px solid var(--border-color);border-radius:4px;padding:4px 10px;font-size:11px;color:var(--text-secondary);cursor:pointer}.team-refresh-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.team-refresh-btn:disabled{opacity:.5;cursor:default}.team-error{color:var(--status-error);font-size:12px;margin-bottom:8px;padding:6px 8px;background:#ef44441a;border-radius:4px}.team-loading{color:var(--text-secondary);font-size:13px;padding:20px 0;text-align:center}.team-section{margin-bottom:16px}.team-section-title{font-size:11px;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px}.team-member-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:8px}.team-member-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:6px;padding:10px 12px}.team-member-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px}.team-member-name{font-size:13px;font-weight:600;color:var(--text-primary)}.team-member-role{font-size:10px;color:var(--text-muted);background:var(--bg-tertiary);padding:1px 5px;border-radius:3px;text-transform:uppercase;letter-spacing:.3px}.team-member-github{font-size:11px;color:var(--accent);text-decoration:none;display:block;margin-bottom:6px}.team-member-github:hover{text-decoration:underline}.team-member-section{margin-top:6px}.team-section-label{font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.3px;display:block;margin-bottom:2px}.team-item-list{display:flex;flex-direction:column}.team-item-link{display:block;font-size:11px;color:var(--accent);text-decoration:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;padding:1px 0}.team-item-link:hover{text-decoration:underline}.team-item-empty{font-size:11px;color:var(--text-muted);font-style:italic}.team-member-activity{display:flex;gap:8px;font-size:10px;color:var(--text-muted);margin-top:4px}.team-review-blocking-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:2px}.team-review-blocking-item{display:flex;align-items:baseline;gap:6px;font-size:11px;line-height:1.3;min-width:0}.team-review-blocking-sentence{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.team-review-blocking-sentence strong{font-weight:600}.team-review-blocking-link{display:inline;white-space:normal}.team-review-blocking-age{flex:0 0 auto;font-size:10px;color:var(--text-muted);font-style:italic}.team-activity-label{color:var(--text-muted);font-style:italic}.team-messages{display:flex;flex-direction:column;gap:6px}.team-message{padding:8px 10px;background:var(--bg-secondary);border-radius:4px;border-left:2px solid var(--border-color)}.team-message-header{display:flex;align-items:baseline;gap:8px;margin-bottom:4px}.team-message-author{font-size:12px;font-weight:600;color:var(--text-primary)}.team-message-time{font-size:10px;color:var(--text-muted)}.team-message-body{font-size:12px;color:var(--text-secondary);white-space:pre-wrap;word-break:break-word}.team-no-messages{font-size:12px;color:var(--text-muted);padding:8px 0}.team-activity-feed{display:flex;flex-direction:column;gap:2px}.team-activity-entry{display:flex;align-items:baseline;gap:6px;font-size:12px;color:var(--text-secondary);text-decoration:none;padding:4px 8px;border-radius:3px}.team-activity-entry:hover{background:var(--bg-secondary)}.team-activity-date{font-size:10px;color:var(--text-muted);min-width:50px;flex-shrink:0}.team-activity-author{color:var(--accent);flex-shrink:0}.team-activity-action{color:var(--text-muted);flex-shrink:0}.team-activity-ref{color:var(--text-secondary);flex-shrink:0}.team-activity-title{color:var(--text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.ofs-rows{display:flex;flex-direction:column;gap:2px}.ofs-subgroup-label{font-size:11px;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.05em;padding:4px 14px 2px}.ofs-row{display:flex;align-items:center;gap:8px;padding:5px 14px;border-radius:6px;cursor:pointer;font-size:14px}.ofs-row:hover{background:var(--bg-secondary)}.ofs-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.ofs-dot--running{background:var(--status-active)}.ofs-dot--idle{background:var(--text-secondary)}.ofs-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ofs-idle{font-size:12px;color:var(--text-secondary);white-space:nowrap}.ofs-file-icon{font-size:14px;flex-shrink:0}.ofs-path{font-size:12px;color:var(--text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|