@songsid/agend 2.2.0-beta.1 → 2.2.0-beta.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/README.md +1 -1
- package/README.zh-TW.md +1 -1
- package/dist/agent-cli-instructions.md +10 -7
- package/dist/agent-endpoint.js +21 -9
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.d.ts +47 -0
- package/dist/agent-whats-new.js +141 -0
- package/dist/agent-whats-new.js.map +1 -0
- package/dist/auth-api.d.ts +2 -2
- package/dist/auth-api.js +4 -2
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/kiro-engine-ledger.d.ts +5 -0
- package/dist/backend/kiro-engine-ledger.js +20 -0
- package/dist/backend/kiro-engine-ledger.js.map +1 -1
- package/dist/backend/kiro-identity.d.ts +6 -0
- package/dist/backend/kiro-identity.js +19 -5
- package/dist/backend/kiro-identity.js.map +1 -1
- package/dist/backend/kiro.d.ts +14 -2
- package/dist/backend/kiro.js +84 -9
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +4 -2
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +11 -1
- package/dist/channel/adapters/discord.js +23 -1
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +19 -1
- package/dist/channel/adapters/telegram.js +60 -9
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-server.js +9 -1
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +11 -0
- package/dist/channel/mcp-tools.js +23 -12
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/telegram-markdown.d.ts +6 -0
- package/dist/channel/telegram-markdown.js +104 -0
- package/dist/channel/telegram-markdown.js.map +1 -0
- package/dist/channel/tool-router.js +9 -3
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/channel/types.d.ts +14 -2
- package/dist/cli.js +55 -16
- package/dist/cli.js.map +1 -1
- package/dist/command-table.js +1 -1
- package/dist/command-table.js.map +1 -1
- package/dist/config-validator.js +49 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/cross-instance-envelope.d.ts +15 -2
- package/dist/cross-instance-envelope.js +27 -5
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/daemon.d.ts +48 -0
- package/dist/daemon.js +250 -22
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +17 -2
- package/dist/delivery-outbox.js +13 -2
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +18 -1
- package/dist/delivery-reconciliation.js +67 -2
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/fleet-manager.d.ts +63 -1
- package/dist/fleet-manager.js +314 -20
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/backend-providers/SKILL.md +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +9 -6
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +11 -2
- package/dist/general-knowledge/skills/delegation-playbook/SKILL.md +8 -8
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +5 -5
- package/dist/general-knowledge/skills/fleet-health/SKILL.md +4 -4
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +13 -13
- package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +3 -2
- package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +6 -0
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +9 -9
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +8 -2
- package/dist/general-knowledge/skills/scheduling/SKILL.md +5 -3
- package/dist/general-knowledge/skills/session-management/SKILL.md +6 -5
- package/dist/general-knowledge/skills/tui-effort/SKILL.md +2 -2
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +4 -3
- package/dist/general-knowledge/steering/core-rules.md +8 -7
- package/dist/instance-avatar.d.ts +36 -0
- package/dist/instance-avatar.js +57 -0
- package/dist/instance-avatar.js.map +1 -0
- package/dist/instance-config-impact.js +5 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +4 -0
- package/dist/instance-lifecycle.js +3 -1
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +2 -0
- package/dist/instructions.js +10 -7
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +36 -26
- package/dist/locale.js.map +1 -1
- package/dist/next-steps.js +1 -1
- package/dist/next-steps.js.map +1 -1
- package/dist/outbound-handlers.d.ts +2 -0
- package/dist/outbound-handlers.js +28 -15
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +10 -2
- package/dist/outbound-schemas.js +15 -5
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +7 -2
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/service-activation.js +4 -3
- package/dist/service-activation.js.map +1 -1
- package/dist/settings-api.js +71 -21
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +70 -1
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +26 -4
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.js +7 -0
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +1 -1
- package/dist/status-emojis.d.ts +10 -3
- package/dist/status-emojis.js +11 -2
- package/dist/status-emojis.js.map +1 -1
- package/dist/tips.js +4 -4
- package/dist/tips.js.map +1 -1
- package/dist/transcript-delta-reader.d.ts +3 -3
- package/dist/transcript-delta-reader.js +8 -8
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/transcript-monitor.d.ts +8 -0
- package/dist/transcript-monitor.js +26 -2
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +54 -0
- package/dist/transcript-sources.js +188 -27
- package/dist/transcript-sources.js.map +1 -1
- package/dist/transcript-turns.d.ts +15 -2
- package/dist/transcript-turns.js +15 -2
- package/dist/transcript-turns.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/ui/chat-emojis.js +33 -0
- package/dist/ui/chat-render.js +12 -0
- package/dist/ui/chat-store.js +1 -1
- package/dist/ui/chat-strings.js +12 -12
- package/dist/ui/chat-thread.js +23 -4
- package/dist/ui/panel-chat.js +16 -3
- package/dist/ui/panel-needs.js +5 -2
- package/dist/ui/panel-settings.js +129 -31
- package/dist/ui/settings-dialogs.js +7 -2
- package/dist/ui/settings-model.js +2 -1
- package/dist/ui/settings-strings.js +44 -4
- package/dist/ui/shared/app-i18n.js +37 -15
- package/dist/ui/shared/app-prefs.js +249 -0
- package/dist/ui/shared/app-route.js +1 -1
- package/dist/ui/shared/app-shell.js +17 -4
- package/dist/ui/shared/app-store.js +3 -1
- package/dist/ui/shared/app.css +55 -0
- package/dist/ui/shared/app.js +6 -1
- package/dist/ui/shared/header-tools.js +55 -5
- package/dist/ui/shared/instance-nav.js +169 -32
- package/dist/ui/shared/panel-view.js +6 -0
- package/dist/ui/shared/signin.js +7 -7
- package/dist/ui/shared/theme.js +39 -7
- package/dist/ui/shared/ui-icons.js +1 -0
- package/dist/ui/shared/usage-dialog.js +13 -4
- package/dist/ui/shared/view-strings.js +22 -4
- package/dist/ui/signin.html +1 -1
- package/dist/update-install.d.ts +15 -1
- package/dist/update-install.js +6 -0
- package/dist/update-install.js.map +1 -1
- package/dist/update-preflight.d.ts +100 -0
- package/dist/update-preflight.js +264 -0
- package/dist/update-preflight.js.map +1 -0
- package/dist/updater-caller.d.ts +31 -0
- package/dist/updater-caller.js +109 -0
- package/dist/updater-caller.js.map +1 -0
- package/dist/view-api.d.ts +1 -1
- package/dist/view-api.js +38 -8
- package/dist/view-api.js.map +1 -1
- package/dist/wake-coordinator.d.ts +11 -0
- package/dist/wake-coordinator.js +38 -4
- package/dist/wake-coordinator.js.map +1 -1
- package/dist/web-api.d.ts +21 -1
- package/dist/web-api.js +157 -1
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.d.ts +2 -2
- package/dist/web-auth.js +7 -4
- package/dist/web-auth.js.map +1 -1
- package/dist/web-host-guard.d.ts +3 -11
- package/dist/web-host-guard.js +3 -12
- package/dist/web-host-guard.js.map +1 -1
- package/dist/web-images.d.ts +47 -0
- package/dist/web-images.js +169 -0
- package/dist/web-images.js.map +1 -0
- package/dist/web-prefs.d.ts +63 -0
- package/dist/web-prefs.js +263 -0
- package/dist/web-prefs.js.map +1 -0
- package/dist/web-session.d.ts +36 -1
- package/dist/web-session.js +53 -6
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +21 -0
- package/dist/web-settings-patch.js +74 -0
- package/dist/web-settings-patch.js.map +1 -0
- package/dist/web-shell-routes.d.ts +1 -1
- package/dist/web-shell-routes.js +1 -1
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/workflow-templates/default.md +1 -1
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@ AgEnD selects a provider; the backend CLI owns endpoint and credential definitio
|
|
|
14
14
|
|---|---|
|
|
15
15
|
| Codex | Select with `backend_options.codex.provider`; define the provider in Codex `config.toml`. |
|
|
16
16
|
| OpenCode | Define the provider in `opencode.json`; use model ID `<provider>/<model>`. |
|
|
17
|
-
| Claude Code, Kiro CLI, Antigravity, Grok | Provider is fixed by the CLI; do not set `backend_options` for provider selection. |
|
|
17
|
+
| Claude Code, Kiro CLI, Antigravity, Grok, Muse | Provider is fixed by the CLI; do not set `backend_options` for provider selection. |
|
|
18
18
|
|
|
19
19
|
## Create a Codex custom-provider instance
|
|
20
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: credential-profiles
|
|
3
|
-
description: Run agents on more than one subscription of the same backend. Use when someone asks for a worker on a different account, wants an agent moved to another subscription, or asks which subscription an agent is using. Currently kiro-cli
|
|
3
|
+
description: Run agents on more than one subscription of the same backend. Use when someone asks for a worker on a different account, wants an agent moved to another subscription, or asks which subscription an agent is using. Currently kiro-cli and codex.
|
|
4
4
|
roles: [general]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -47,8 +47,8 @@ CODEX_HOME="${AGEND_HOME:-~/.agend}/credential-profiles/codex/<profile>" codex l
|
|
|
47
47
|
|
|
48
48
|
```
|
|
49
49
|
create_instance(
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
topic_name: "research-b",
|
|
51
|
+
directory: "/home/you/projects/app",
|
|
52
52
|
backend: "kiro-cli",
|
|
53
53
|
backend_options: { "kiro-cli": { "credential_profile": "personal" } },
|
|
54
54
|
)
|
|
@@ -66,8 +66,10 @@ update_instance_config(
|
|
|
66
66
|
)
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
The credentials are read when the CLI starts, so
|
|
70
|
-
for you** and the reply says `restarted: true`.
|
|
69
|
+
The credentials are read when the CLI starts, so a running instance **is
|
|
70
|
+
restarted for you** and the reply says `restarted: true`. A paused or stopped one
|
|
71
|
+
is not started: the reply says `restarted: false`, and the switch applies at its
|
|
72
|
+
next start.
|
|
71
73
|
|
|
72
74
|
**For kiro**, a switch is always a **new conversation**, and the reply says so
|
|
73
75
|
(`conversation_carried_over: false`). kiro keeps its conversations in the same
|
|
@@ -116,7 +118,8 @@ Say "the default login", not "no subscription".
|
|
|
116
118
|
`get_usage` returns one row per subscription: `Kiro (work)` and
|
|
117
119
|
`Kiro (personal)` rather than a single `Kiro`. Read them out separately — they
|
|
118
120
|
are two quotas, and adding them together would give a number that is true of
|
|
119
|
-
neither. An agent with no profile appears under the plain `Kiro` row.
|
|
121
|
+
neither. An agent with no profile appears under the plain `Kiro` row. Codex works
|
|
122
|
+
the same way: `Codex (<profile>)` rows next to the plain `Codex`.
|
|
120
123
|
|
|
121
124
|
A profile that is configured but has never been logged in still gets a row,
|
|
122
125
|
reading **Signed out — run `kiro-cli` to log in**. That is the reminder to go
|
|
@@ -7,11 +7,20 @@ roles: [general, worker]
|
|
|
7
7
|
## How to send
|
|
8
8
|
|
|
9
9
|
Use fleet tools only (`send_to_instance`, `delegate_task`, `request_information`, `report_result`, `broadcast`):
|
|
10
|
-
- Call returns immediately: `{ sent: true, queued: true }` —
|
|
10
|
+
- Call returns immediately: `{ sent: true, queued: true }` (plus `delivery_id` / `operation_id` for a durable send) — the fleet **accepted** it and owns delivery from here. Acceptance is not delivery.
|
|
11
11
|
- **Do not wait** for the target to go idle; **do not** treat 30s IPC timeout as failure to re-send.
|
|
12
12
|
- **Error only if the target does not exist** (or similar hard reject) — then fix the name, don't spam.
|
|
13
13
|
- **Never re-send because the reply said `queued`** — that means the message is already queued.
|
|
14
14
|
- Supplement/correction to work you just sent → `steer: true`; a new task → normal send.
|
|
15
|
+
- A message body over 12 KiB is refused (`defaults.max_cross_instance_message_bytes`): put long content in a file and send its path.
|
|
16
|
+
|
|
17
|
+
## Checking a delivery
|
|
18
|
+
|
|
19
|
+
Only when a result is unclear: `delivery_status` with the `operation_id` / `delivery_id` / `correlation_id` you got.
|
|
20
|
+
- `queued`, `delivering`, `retry_wait` — not handed over yet; the fleet keeps trying.
|
|
21
|
+
- `submission_started`, `reconciliation_pending`, `uncertain` — it may already have arrived: **do not resend**.
|
|
22
|
+
- `delivered` — the target received it (not necessarily processed it yet; `consumed_at` says when it did).
|
|
23
|
+
- `failed`, `cancelled` — not delivered; fix the cause, then send again.
|
|
15
24
|
|
|
16
25
|
## requires_reply
|
|
17
26
|
|
|
@@ -21,7 +30,7 @@ Use fleet tools only (`send_to_instance`, `delegate_task`, `request_information`
|
|
|
21
30
|
## Task flow
|
|
22
31
|
|
|
23
32
|
- Coordinator flow: `delegate_task` → silent work → `report_result` (zero ack-only pings).
|
|
24
|
-
- Worker flow: finish with `report_result`, or use `request_information` when blocked.
|
|
33
|
+
- Worker flow: finish with `report_result`, or use `request_information` when blocked. Prefer `report_result` over delegating; use `delegate_task` only when your assignment allows it, and never re-delegate a task back to its sender.
|
|
25
34
|
- Cross-instance traffic is `[from:name]` → answer with `send_to_instance` / `report_result`, never `reply`
|
|
26
35
|
|
|
27
36
|
## Before acting on a peer's message
|
|
@@ -6,11 +6,11 @@ roles: [general]
|
|
|
6
6
|
|
|
7
7
|
## Delegation Protocol
|
|
8
8
|
|
|
9
|
-
Every delegation via
|
|
9
|
+
Every delegation via `delegate_task` MUST include:
|
|
10
10
|
|
|
11
|
-
1.
|
|
12
|
-
2.
|
|
13
|
-
3.
|
|
11
|
+
1. `task` — what exactly to do, bounded clearly
|
|
12
|
+
2. `success_criteria` — what to return, in what form, and how it will be judged
|
|
13
|
+
3. A policy reminder in `context` — "Follow Development Workflow policy" (for code tasks)
|
|
14
14
|
|
|
15
15
|
### Loop Prevention
|
|
16
16
|
|
|
@@ -29,11 +29,11 @@ When an instance reports back, classify the outcome:
|
|
|
29
29
|
- Success → Summarize key results for user. Omit internal coordination noise.
|
|
30
30
|
- Partial → State what succeeded, what remains, proposed next steps.
|
|
31
31
|
- Failure → Retry up to 2 times. If still failing: try alternative instance, reduce scope, or return partial result clearly marked.
|
|
32
|
-
- No response →
|
|
32
|
+
- No response → when a `[system:reply-overdue]` notice arrives (after 15 min by default), check `describe_instance` and `delivery_status` before asking again. If still silent: report to user with options.
|
|
33
33
|
|
|
34
34
|
## Shared Decisions
|
|
35
35
|
|
|
36
|
-
Use post_decision
|
|
36
|
+
Use `post_decision` / `list_decisions` for any choice that affects more than 1 instance, changes an API contract, introduces a new dependency, or alters deployment process. The default `scope: "project"` reaches only instances in the same working directory — use `scope: "fleet"` for anything wider.
|
|
37
37
|
|
|
38
38
|
When instances disagree, collect both viewpoints, make a decision, and record it via post_decision.
|
|
39
39
|
|
|
@@ -47,6 +47,6 @@ When instances disagree, collect both viewpoints, make a decision, and record it
|
|
|
47
47
|
|
|
48
48
|
When users create specialized instances, suggest these configurations:
|
|
49
49
|
|
|
50
|
-
- **Reviewer instances
|
|
51
|
-
- **Collab mode**: For multi-bot channels,
|
|
50
|
+
- **Reviewer instances** (kiro): add `pre_task_command: "/chat load reviewer-base.json"` to reset context before each review. It is pasted before every message as-is, so on other backends use a command their CLI accepts.
|
|
51
|
+
- **Collab mode**: For multi-bot channels, a channel admin's `/collab` lets other bots' and webhooks' messages reach the instance.
|
|
52
52
|
- **Cost control**: Set per-instance `cost_guard` for expensive backends.
|
|
@@ -40,16 +40,16 @@ instances:
|
|
|
40
40
|
backend: kiro-cli
|
|
41
41
|
kiro_ui: legacy # default — current stable behavior
|
|
42
42
|
# kiro_ui: tui # try the newer TUI
|
|
43
|
-
# kiro_ui: v3 # try the v3 profile
|
|
44
43
|
```
|
|
44
|
+
`kiro_ui: v3` is refused by validation — do not set it.
|
|
45
45
|
Leave unset (or `legacy`) unless testing a newer profile. Ignored by other backends.
|
|
46
46
|
|
|
47
47
|
## Reply completion guard
|
|
48
48
|
|
|
49
49
|
`reply_completion_guard` detects a human-channel turn that ended without a
|
|
50
50
|
delivered reply and asks the agent to send one bounded recovery reply. It is
|
|
51
|
-
enabled by default for Claude Code
|
|
52
|
-
Kiro v3 is excluded because its turn-end signal is unverified.
|
|
51
|
+
enabled by default for Claude Code, Codex, Muse and Kiro legacy/TUI (it needs the
|
|
52
|
+
MCP server). Kiro v3 is excluded because its turn-end signal is unverified. Other
|
|
53
53
|
backends keep the setting but do not claim the protection is active.
|
|
54
54
|
|
|
55
55
|
Prefer a narrow per-instance override when one worker repeatedly finishes work
|
|
@@ -79,14 +79,14 @@ it does not turn tool-call text into proof that the reply reached the channel.
|
|
|
79
79
|
Fix all errors before `agend reload`; warnings are advisory.
|
|
80
80
|
|
|
81
81
|
**Common fleet.yaml mistakes:**
|
|
82
|
-
-
|
|
82
|
+
- `channel.mode` left out → it is `topic` (say so explicitly if you mean another mode)
|
|
83
83
|
- Wrong indentation (YAML is indent-sensitive)
|
|
84
84
|
- `topic_id` as string vs number (both work, but be consistent)
|
|
85
85
|
- `backend` typo (valid: `claude-code`, `codex`, `opencode`, `kiro-cli`, `antigravity`, `grok`, `muse`); `gemini-cli` was removed in 2.1.12 — use `antigravity`
|
|
86
86
|
- `model` using wrong format for the backend
|
|
87
87
|
|
|
88
88
|
**Common classicBot.yaml mistakes:**
|
|
89
|
-
- `allowed_guilds` values
|
|
89
|
+
- `allowed_guilds` values should be quoted strings: numbers are accepted, but a Discord ID above 2^53 loses digits as a YAML integer
|
|
90
90
|
- Channel IDs as keys must be quoted strings
|
|
91
91
|
- Missing `defaults` section (optional but recommended)
|
|
92
92
|
|
|
@@ -7,9 +7,9 @@ roles: [general]
|
|
|
7
7
|
## Check health
|
|
8
8
|
|
|
9
9
|
Prefer the fleet tools — they already know each instance's state:
|
|
10
|
-
- `
|
|
11
|
-
- `describe_instance("<name>")` — one instance's status, last activity, description.
|
|
12
|
-
- `
|
|
10
|
+
- `list_instances` — every instance with its status and `instance_state`: idle / working / stuck / paused / awaiting_input (the CLI is waiting at an on-screen dialog or input).
|
|
11
|
+
- `describe_instance("<name>")` — one instance's status, state, last activity, description.
|
|
12
|
+
- `get_fleet_status` — just the counts: total, running, paused, stopped.
|
|
13
13
|
|
|
14
14
|
The daemon derives idle/working/stuck itself (per-backend), so you do **not** need to
|
|
15
15
|
scrape prompts. Don't hand-write pane-text checks like `X% !>` — that prompt is
|
|
@@ -20,7 +20,7 @@ kiro-specific and wrong for claude-code / codex / grok / antigravity.
|
|
|
20
20
|
When the user wants the live screen (not just a status word):
|
|
21
21
|
- `get_instance_logs("<name>")` — recent output (the raw terminal stream).
|
|
22
22
|
- Raw terminal (last resort, no tool for the live pane):
|
|
23
|
-
`tmux capture-pane -t agend:<name> -e -p | tail -20` — keep `-e`: without it the screen's styling is lost.
|
|
23
|
+
`tmux capture-pane -t agend:<name> -e -p | tail -20` on the default AGEND_HOME (an isolated home uses session `agend-<hash>` on its own `-L` socket; `agend attach <name>` works in both) — keep `-e`: without it the screen's styling is lost.
|
|
24
24
|
|
|
25
25
|
**Faint text is not input.** A CLI paints its own suggestion or placeholder in the input box
|
|
26
26
|
exactly like typed text, only faint (Claude Code: `❯ Try "…"`, or a suggested next prompt).
|
|
@@ -7,18 +7,23 @@ roles: [general]
|
|
|
7
7
|
## Fleet Restart & Recovery
|
|
8
8
|
|
|
9
9
|
**Restart types:**
|
|
10
|
-
- `agend fleet restart` —
|
|
10
|
+
- `agend fleet restart` — graceful, in the same process: instances restart once idle (does **not** load new code)
|
|
11
|
+
- `agend fleet restart --reload` — full process restart: new code and new connections take effect
|
|
12
|
+
- `agend fleet restart <name>` — restart one instance now
|
|
11
13
|
- `agend reload` — SIGHUP hot-reload, reconciles instances without restarting the fleet process
|
|
12
14
|
- `restart_instance("<name>")` — single instance restart, reloads fleet.yaml first
|
|
15
|
+
- `agend restart` — restarts the AgEnD service itself (systemd / launchd / detached), not one instance
|
|
16
|
+
|
|
17
|
+
**From a fleet agent session**, `agend stop`, `agend restart`, `agend update`, `agend fleet stop` and `agend fleet restart` (without a name) affect every instance and are refused unless you pass `--yes`. Each is written to `restart-audit.log` first. `--force` is for an operator's own shell only.
|
|
13
18
|
|
|
14
19
|
**After tmux crash:**
|
|
15
|
-
- Fleet
|
|
20
|
+
- Fleet detects the tmux server's death and opens a recovery window: spawns and deliveries are held 30 s, then 2 min and 10 min if it crashes again (losing single windows while the server lives holds nothing)
|
|
16
21
|
- Some instances may fail to restart due to rate limits from simultaneous startup
|
|
17
22
|
- Fix: manually restart failed instances, or do another `agend fleet restart`
|
|
18
23
|
- Check failed instances: `agend ls` shows "stopped" status
|
|
19
24
|
|
|
20
25
|
**Rate limit recovery:**
|
|
21
|
-
- If
|
|
26
|
+
- If the log shows `PTY error: …rate limit…`, or the notice "crashed 3+ times shortly after launch — paused for recovery", wait 1-2 minutes
|
|
22
27
|
- Then `restart_instance` the affected instance
|
|
23
28
|
- Do NOT restart all instances simultaneously — this worsens rate limits
|
|
24
29
|
|
|
@@ -26,21 +31,16 @@ roles: [general]
|
|
|
26
31
|
|
|
27
32
|
**Update AgEnD to latest version:**
|
|
28
33
|
```bash
|
|
29
|
-
agend update
|
|
30
|
-
agend update --version 2.
|
|
34
|
+
agend update --yes # from a fleet session: the installed channel's latest (a beta stays on beta), then restart
|
|
35
|
+
agend update --version 2.2.0 --yes # a specific version
|
|
31
36
|
```
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
- Detects if sudo is needed (switches to nvm if so)
|
|
35
|
-
- Installs new version
|
|
36
|
-
- Verifies installation succeeded
|
|
37
|
-
- Updates service file (ExecStart path)
|
|
38
|
-
- Restarts fleet
|
|
38
|
+
It installs the selected release, checks the install, and restarts the fleet service. `--alpha` / `--beta` / `--stable` pick a channel; details in docs/cli.md.
|
|
39
39
|
|
|
40
40
|
**Manual restart (if update isn't needed):**
|
|
41
41
|
```bash
|
|
42
|
-
agend fleet restart
|
|
43
|
-
agend fleet
|
|
42
|
+
agend fleet restart --yes # graceful (SIGUSR2) — keeps sessions, reloads config
|
|
43
|
+
agend fleet restart --reload --yes # full process restart — new code takes effect
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
**NEVER do:**
|
|
@@ -22,7 +22,8 @@ roles: [general]
|
|
|
22
22
|
|
|
23
23
|
## Monitoring state
|
|
24
24
|
|
|
25
|
-
- `
|
|
26
|
-
activity (the daemon derives the state; don't scrape pane
|
|
25
|
+
- `describe_instance("<name>")` / `list_instances` — status + `instance_state` (idle / working /
|
|
26
|
+
stuck / paused / awaiting_input) + last activity (the daemon derives the state; don't scrape pane
|
|
27
|
+
prompts). `get_fleet_status` only counts running / paused / stopped.
|
|
27
28
|
- For the raw screen, see the fleet-health skill (`get_instance_logs` / tmux capture), including
|
|
28
29
|
why faint text in another instance's input box is a CLI suggestion, not the operator's input.
|
|
@@ -54,3 +54,9 @@ The user has already been shown the plain notice in this topic. When they ask, e
|
|
|
54
54
|
conversation, and the move cannot be undone.
|
|
55
55
|
- Never run `kiro-cli` yourself, and never delete or edit anything under `~/.kiro` or kiro's data directory.
|
|
56
56
|
- Never reply to the `[system:kiro-incompat]` notice itself. It is information, not a request.
|
|
57
|
+
|
|
58
|
+
## One kiro agent per instance (#906)
|
|
59
|
+
|
|
60
|
+
Since kiro-cli 2.21, each AgEnD kiro instance (tui / v2 engine) runs as its own kiro agent, holding only its own
|
|
61
|
+
AgEnD MCP server and instructions, and resumes its own conversation by id — instances sharing a working directory
|
|
62
|
+
no longer see each other's tools. Legacy (`kiro_ui: legacy`) launches are unchanged.
|
|
@@ -21,16 +21,16 @@ capability (cheap/fast vs deep reasoning), or the backend needs one to behave
|
|
|
21
21
|
| Backend | Omit `model` means | Notes |
|
|
22
22
|
|---|---|---|
|
|
23
23
|
| kiro-cli | account default | **`model: auto`** lets kiro pick per turn — usually what you want |
|
|
24
|
-
| claude-code | account default | ids are aliases: `sonnet`, `opus`, `haiku`, `opusplan`, `default` |
|
|
24
|
+
| claude-code | account default | ids are aliases: `sonnet`, `opus`, `haiku`, `opusplan`, `default`, `Fable`; `list_models` also offers the account's full ids (with `[1m]` variants) |
|
|
25
25
|
| codex | account default | |
|
|
26
26
|
| grok | account default | |
|
|
27
27
|
| antigravity | account default | |
|
|
28
|
-
| opencode | provider default | ids are **`provider/model`**,
|
|
28
|
+
| opencode | provider default | ids are **`provider/model`**, as `opencode models` prints them |
|
|
29
29
|
|
|
30
30
|
## Discover real names
|
|
31
31
|
|
|
32
|
-
**Use the `list_models` tool** — it reads the fleet's probe cache (
|
|
33
|
-
|
|
32
|
+
**Use the `list_models` tool** — it reads the fleet's probe cache (re-probed when
|
|
33
|
+
older than 1 h; never used past 24 h) and falls back to a live probe:
|
|
34
34
|
|
|
35
35
|
- `list_models({ backend: "kiro-cli" })` → the account catalog
|
|
36
36
|
- `list_models({ instance_name: "x" })` → read through **that instance's** config
|
|
@@ -47,11 +47,11 @@ Underlying commands, if you need them by hand:
|
|
|
47
47
|
|
|
48
48
|
| Backend | Command |
|
|
49
49
|
|---|---|
|
|
50
|
-
| kiro-cli | `kiro-cli --list-models` |
|
|
50
|
+
| kiro-cli | `kiro-cli chat --list-models --format json` |
|
|
51
51
|
| grok | `grok models` |
|
|
52
52
|
| opencode | `opencode models` |
|
|
53
53
|
| antigravity | `agy models` |
|
|
54
|
-
| codex |
|
|
54
|
+
| codex | `codex debug models` (with its CODEX_HOME set) — refreshes `models_cache.json` when it is older than a few minutes |
|
|
55
55
|
| claude-code | fixed alias set (no command) |
|
|
56
56
|
|
|
57
57
|
## Setting one on create_instance
|
|
@@ -65,9 +65,9 @@ Underlying commands, if you need them by hand:
|
|
|
65
65
|
## Two traps
|
|
66
66
|
|
|
67
67
|
**antigravity: keep the effort suffix.** The suffix is part of the selectable id,
|
|
68
|
-
not decoration —
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
not decoration — the same model at two effort levels is two different ids. Take
|
|
69
|
+
the id from `list_models` (e.g. `gemini-3.6-flash-high`), not the display label
|
|
70
|
+
the TUI shows.
|
|
71
71
|
|
|
72
72
|
**Pass-through: AgEnD does not gate model names.** An unknown id is warned about,
|
|
73
73
|
then handed to the CLI anyway. So a name missing from `list_models` may still be
|
|
@@ -55,11 +55,17 @@ The `channel_id` field explicitly binds a general to an adapter. Without it, mat
|
|
|
55
55
|
|---------|---------|-----|
|
|
56
56
|
| One general for two platforms | TG messages reply in DC | Add a second general with `channel_id` |
|
|
57
57
|
| `channels:` without unique `id` per entry | Adapter collision | Set `id: discord` / `id: telegram` |
|
|
58
|
-
| Using `channel:` (singular) for multi-platform | Second platform ignored | Switch to `channels:` array |
|
|
58
|
+
| Using `channel:` (singular) for multi-platform | Second platform ignored | Switch to `channels:` array (`channel:` is deprecated; the validator warns when both are set) |
|
|
59
|
+
|
|
60
|
+
## Web chat
|
|
61
|
+
|
|
62
|
+
The dashboard's web chat is one more way in, not a `channels:` entry: its messages reach an instance as
|
|
63
|
+
`[user:… via web, …]` and are answered with `reply` like any other. By default each is also copied to the
|
|
64
|
+
instance's own topic (`web.echo_to_channel: false` turns that off; ClassicBot rooms only with `web_echo: true`).
|
|
59
65
|
|
|
60
66
|
## Single → Multi Migration
|
|
61
67
|
|
|
62
68
|
1. Change `channel:` to `channels:` array, add `id` to existing entry
|
|
63
69
|
2. Add new platform entry with its own `id`
|
|
64
70
|
3. Add a general instance for the new platform with `channel_id: <new-adapter-id>`
|
|
65
|
-
4. Restart
|
|
71
|
+
4. Restart the whole process — connections are created when it starts: `agend fleet restart --reload` (`--yes` from a fleet session)
|
|
@@ -8,15 +8,17 @@ roles: [general, worker]
|
|
|
8
8
|
|
|
9
9
|
- `create_schedule` — make a schedule (recurring or one-shot).
|
|
10
10
|
- `list_schedules` — list all (optionally filter by target instance).
|
|
11
|
-
- `update_schedule` — change cron/at/message/timezone/enabled of an existing one.
|
|
11
|
+
- `update_schedule` — change cron/at/message/target/label/timezone/enabled of an existing one.
|
|
12
12
|
- `delete_schedule` — remove one.
|
|
13
13
|
|
|
14
14
|
A schedule injects `message` into the `target` instance when it fires
|
|
15
|
-
(`target` defaults to the current instance).
|
|
15
|
+
(`target` defaults to the current instance). With the worker or standard tool set you may
|
|
16
|
+
manage only schedules that target you and that you created; for anything else ask the
|
|
17
|
+
coordinator with `report_result`.
|
|
16
18
|
|
|
17
19
|
## Three ways to schedule
|
|
18
20
|
|
|
19
|
-
**1. Recurring (cron)** — `cron` + optional `timezone` (IANA
|
|
21
|
+
**1. Recurring (cron)** — `cron` + optional `timezone` (IANA; default the fleet's `defaults.scheduler.default_timezone`, `Asia/Taipei` unless set):
|
|
20
22
|
```
|
|
21
23
|
create_schedule({ cron: "0 9 * * *", message: "Daily standup summary", timezone: "Asia/Taipei" })
|
|
22
24
|
```
|
|
@@ -8,7 +8,8 @@ roles: [general]
|
|
|
8
8
|
|
|
9
9
|
When AgEnD sees `auth_error` it **pauses** that instance (`pausePending` sticky):
|
|
10
10
|
- One notification **per backend** (not per instance) — log in once, same-backend peers recover.
|
|
11
|
-
- Auth is **per-
|
|
11
|
+
- Auth is **per backend**: one re-login restores every instance on that backend (claude-code, codex, kiro-cli, grok, opencode, antigravity, muse).
|
|
12
|
+
- Re-login: `/login <backend>` (opencode: `opencode auth login` in a terminal), then wake the affected instance.
|
|
12
13
|
- Messages while paused stay in the **queue** — do not re-send.
|
|
13
14
|
- After the user re-auths: `wake` / normal wake clears `pausePending`.
|
|
14
15
|
|
|
@@ -24,7 +25,7 @@ Verified by running each one, not read from docs.
|
|
|
24
25
|
| **codex** | ⚠️ no index — parse rollout files | ✅ `codex exec resume <id>` | ❌ must parse the rollout |
|
|
25
26
|
| **antigravity** | ❌ index covers ~23%, 2 months stale | ✅ `agy --conversation <id>` | ⚠️ `title` empty, use `preview` |
|
|
26
27
|
|
|
27
|
-
**Restoring a specific session is a manual operator action, not an AgEnD feature.** AgEnD
|
|
28
|
+
**Restoring a specific session is a manual operator action, not an AgEnD feature.** AgEnD launches each backend on the instance's own session: codex `resume <id>` (the thread for this exact directory; `--last` only as a fallback when the session DB is unreadable and no other codex instance shares the repository), grok `--resume <id>`, kiro its own conversation id, claude-code `--continue` (only when the instance has a `session-id` marker and the directory has a Claude transcript). To reach any other session someone must drive the pane or the CLI by hand.
|
|
28
29
|
|
|
29
30
|
**kiro is the exception worth knowing:** its export → `/chat load` works on a **live, idle instance** with no restart. Every other backend needs the instance stopped (or the CLI run manually) because the session is chosen by a launch flag.
|
|
30
31
|
|
|
@@ -118,7 +119,7 @@ grep -h '"type":"ai-title"' <file>.jsonl | tail -1
|
|
|
118
119
|
```
|
|
119
120
|
A session with no `ai-title` line is simply untitled — say so rather than inventing a label.
|
|
120
121
|
|
|
121
|
-
**Restore:** `claude -r <session-id>` (or `claude --resume` for a picker that accepts a search term). `-c` / `--continue` takes the most recent for the cwd —
|
|
122
|
+
**Restore:** `claude -r <session-id>` (or `claude --resume` for a picker that accepts a search term). `-c` / `--continue` takes the most recent for the cwd — AgEnD launches with it only when the instance has a `session-id` marker and the cwd has a Claude transcript.
|
|
122
123
|
|
|
123
124
|
> ⚠️ **Check the ID exists before using it.** AgEnD guards `--continue` precisely because resuming a session that isn't there sends claude into a restart loop. Confirm the `<id>.jsonl` file is present in the encoded project dir first.
|
|
124
125
|
|
|
@@ -150,7 +151,7 @@ for ts, sid in sorted(out, reverse=True):
|
|
|
150
151
|
```
|
|
151
152
|
It opens many files, but only one line each, so it stays cheap.
|
|
152
153
|
|
|
153
|
-
**Restore:** `codex exec resume <session-id> "<prompt>"` non-interactively, or `codex resume <session-id>` for the TUI (bare `codex resume` opens a picker). `codex resume --last` is
|
|
154
|
+
**Restore:** `codex exec resume <session-id> "<prompt>"` non-interactively, or `codex resume <session-id>` for the TUI (bare `codex resume` opens a picker). AgEnD launches `codex resume <id>` with the thread recorded for this exact directory; `codex resume --last` is only its fallback (an unreadable session DB, no other codex instance in the repository). The ID argument also accepts a session *name*.
|
|
154
155
|
|
|
155
156
|
**Summary:** ❌ none available without parsing. `session_meta` carries only id/cwd/timestamp; to describe a session you must read further `event_msg` lines. Tell the user the timestamp and let them pick, rather than guessing at a topic.
|
|
156
157
|
|
|
@@ -186,6 +187,6 @@ cur.execute("SELECT conversation_id, preview, step_count, last_modified_time "
|
|
|
186
187
|
## Fork (source must be idle)
|
|
187
188
|
|
|
188
189
|
- **kiro:** `/chat save name.json -f` → `create_instance` → copy workspace file → `/chat load name.json`
|
|
189
|
-
- **claude-code:** copy the newest `*.jsonl` into the target's encoded project dir → start (
|
|
190
|
+
- **claude-code:** copy the newest `*.jsonl` into the target's encoded project dir → start (AgEnD adds `--continue` only if the target's instance dir also has its `session-id` marker)
|
|
190
191
|
- **grok:** `/fork` inside the TUI branches the conversation into a peer session
|
|
191
192
|
- Prefer `replace_instance` when the whole session is poisoned (see instance-lifecycle)
|
|
@@ -18,8 +18,8 @@ instances:
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
**kiro_ui 模式差異:**
|
|
21
|
-
- `kiro_ui: tui`:Kiro v2 TUI
|
|
22
|
-
- `kiro_ui: v3
|
|
21
|
+
- `kiro_ui: tui`:Kiro v2 TUI(需明確設定;預設是 `legacy`);本 skill 適用。
|
|
22
|
+
- `kiro_ui: v3`:目前會被設定驗證拒絕,不要設定。
|
|
23
23
|
- `kiro_ui: legacy`:舊 UI,互動行為不同,本 skill 不適用。
|
|
24
24
|
|
|
25
25
|
若修改 `kiro_ui`,先 reload 再 restart:
|
|
@@ -11,9 +11,10 @@ roles: [worker]
|
|
|
11
11
|
- Treat the assignment as the full scope unless the sender explicitly expands it.
|
|
12
12
|
- Work without acknowledgment-only messages. Silence means the task is in progress.
|
|
13
13
|
- Fleet orchestration is not yours: you do not have `create_instance`,
|
|
14
|
-
`delete_instance`, `restart_instance`, `deploy_template
|
|
15
|
-
the tools
|
|
16
|
-
with an explanation rather than silently
|
|
14
|
+
`delete_instance`, `restart_instance`, `deploy_template` or the team tools,
|
|
15
|
+
and the schedule tools reach only schedules that target you and that you
|
|
16
|
+
created. Anything else is refused with an explanation rather than silently
|
|
17
|
+
ignored. If the work needs more
|
|
17
18
|
capacity or another agent restarted, say so with `report_result` and let the
|
|
18
19
|
coordinator decide.
|
|
19
20
|
- You can still *look*: `list_schedules`, `list_deployments`, `list_instances`
|
|
@@ -8,7 +8,7 @@ When creating a new instance with `create_instance`:
|
|
|
8
8
|
|
|
9
9
|
**Pre-checks (mandatory):**
|
|
10
10
|
1. **Check for duplicate working directory** — Run `list_instances` and verify no existing instance uses the same `working_directory`. Two instances sharing a directory causes file conflicts and race conditions.
|
|
11
|
-
2. **Verify the directory exists** — If specifying a directory, confirm it exists on disk before calling create.
|
|
11
|
+
2. **Verify the directory exists** — If specifying a directory, confirm it exists on disk before calling create. When the fleet sets `project_roots`, it must also be inside one of them, or create is refused.
|
|
12
12
|
3. **Use unique names** — The instance name is derived from `topic_name` or `basename(directory)`. Avoid generic names like "dev" or "test" that may collide.
|
|
13
13
|
|
|
14
14
|
**Post-checks (mandatory):**
|
|
@@ -23,12 +23,13 @@ When creating a new instance with `create_instance`:
|
|
|
23
23
|
## What NOT to Do (Dangerous Operations)
|
|
24
24
|
|
|
25
25
|
- **Don't delete `~/.agend/fleet.yaml`** while fleet is running
|
|
26
|
-
- **Don't delete `~/.agend/fleet.pid`** manually — use `agend fleet stop`
|
|
26
|
+
- **Don't delete `~/.agend/fleet.pid`** manually — use `agend fleet stop` (from a fleet session it needs `--yes`, and it stops every instance)
|
|
27
27
|
- **Don't kill tmux server** (`tmux kill-server`) — kills all agent sessions
|
|
28
28
|
- **Don't edit instance output.log** — it's actively written by the daemon
|
|
29
29
|
- **Don't run two fleet processes** on the same AGEND_HOME — port/socket conflicts
|
|
30
30
|
- **Don't change `channel.group_id`** without re-creating all topics — routing breaks
|
|
31
31
|
- **Don't remove an instance from fleet.yaml** that has active work — stop it first
|
|
32
|
+
- **Don't try to get around a Settings confirmation** — a sensitive change made in the web Settings (access, secrets, connections, …) waits for a fleet admin to confirm it in General, or with `agend settings confirm <id>` on the host
|
|
32
33
|
|
|
33
34
|
## Access Mode Reference
|
|
34
35
|
|
|
@@ -37,7 +38,7 @@ fleet.yaml `channel.access.mode` valid values:
|
|
|
37
38
|
| Mode | Behavior |
|
|
38
39
|
|------|----------|
|
|
39
40
|
| `locked` | Only `allowed_users` can interact (default) |
|
|
40
|
-
| `pairing` |
|
|
41
|
+
| `pairing` | A user sends `/pair` (Telegram), gets a code, and the owner grants access |
|
|
41
42
|
| `open` | All users can interact, no restrictions |
|
|
42
43
|
|
|
43
44
|
Example:
|
|
@@ -46,7 +47,7 @@ channel:
|
|
|
46
47
|
access:
|
|
47
48
|
mode: open # everyone can use
|
|
48
49
|
# mode: locked # whitelist only (add allowed_users)
|
|
49
|
-
# mode: pairing #
|
|
50
|
+
# mode: pairing # /pair gives a code the owner approves
|
|
50
51
|
allowed_users: [123456789] # only needed for locked/pairing
|
|
51
52
|
```
|
|
52
53
|
|
|
@@ -72,14 +73,14 @@ Always use a dedicated subdirectory like `/home/user/projects/my-project` or let
|
|
|
72
73
|
Use layered memory to minimize context usage:
|
|
73
74
|
|
|
74
75
|
1. **Fleet Decision** — short, shared rules only (role, workflow rules, TODOs). Keep concise (~20 lines guideline). If it exceeds this, consider whether the details belong in soul.md instead.
|
|
75
|
-
2. **soul.md** (workspace root) — full memory: architecture, decisions, history.
|
|
76
|
+
2. **soul.md** (workspace root) — full memory: architecture, decisions, history. AgEnD does not load it for you: read it when you need it.
|
|
76
77
|
- If soul.md doesn't exist, do NOT create one unprompted. Only create when the user explicitly asks.
|
|
77
|
-
3. **Skills**
|
|
78
|
+
3. **Skills** — reusable workflows, loaded on demand, in your backend's skills directory: `.kiro/skills/` (kiro), `.claude/skills/` (claude-code), `.agents/skills/` (codex, opencode, muse, antigravity), `.grok/skills/` (grok).
|
|
78
79
|
|
|
79
80
|
Rules:
|
|
80
81
|
- Keep Fleet Decisions minimal. Move details to soul.md.
|
|
81
82
|
- Each instance maintains its own soul.md (not shared).
|
|
82
|
-
- Good workflows → **propose** converting to a skill. Create
|
|
83
|
+
- Good workflows → **propose** converting to a skill. Create `<skills directory>/<name>/SKILL.md` (see Skills above) only after user approval.
|
|
83
84
|
- Global skills (`src/general-knowledge/skills/`) only for knowledge ALL instances need.
|
|
84
85
|
- Never put architecture details or bug history in Fleet Decisions.
|
|
85
86
|
- After completing a **multi-step task that introduced new architectural knowledge or a reusable process**, suggest updating soul.md. Do NOT ask after routine tasks (reviews, single-file fixes, Q&A).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type AvatarDescriptor = {
|
|
2
|
+
kind: "image";
|
|
3
|
+
src: string;
|
|
4
|
+
} | {
|
|
5
|
+
kind: "emoji";
|
|
6
|
+
text: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "emoji";
|
|
9
|
+
src: string;
|
|
10
|
+
alt: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "initial";
|
|
13
|
+
text: string;
|
|
14
|
+
};
|
|
15
|
+
/** The first user-perceived character, upper-cased where that means anything ("é" → "É", "中" stays). */
|
|
16
|
+
export declare function firstCharacter(text: string): string;
|
|
17
|
+
export declare function avatarFor(input: {
|
|
18
|
+
name: string;
|
|
19
|
+
displayName?: string | null;
|
|
20
|
+
/** The profile picture's version, when one is uploaded (step 0). */
|
|
21
|
+
profileVersion?: string | null;
|
|
22
|
+
/** The bot's avatar: its connection id and cached version, when the instance has its own bot and the avatar is on disk. */
|
|
23
|
+
bot?: {
|
|
24
|
+
connection: string;
|
|
25
|
+
version: string;
|
|
26
|
+
} | null;
|
|
27
|
+
/** The instance's own `status_emojis.delivered`, as configured. */
|
|
28
|
+
personaEmoji?: unknown;
|
|
29
|
+
}): AvatarDescriptor;
|
|
30
|
+
/**
|
|
31
|
+
* The connections that are ONE instance's own bot: not the primary (that is the fleet's shared bot), and answering for
|
|
32
|
+
* exactly one instance or ClassicBot room. `assignments` is every instance and room with the connection it uses.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ownBotConnections(primary: string | undefined, assignments: ReadonlyArray<readonly [instance: string, connection: string | undefined]>): Map<string, string>;
|
|
35
|
+
/** A Discord role colour as the page may use it: `#rrggbb`, never black (Discord's "no colour"). */
|
|
36
|
+
export declare function accentColor(raw: unknown): string | null;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #1630 (design: the comment on #1630): what stands for an instance in the web app — decided here, on the server,
|
|
3
|
+
* once; the page only draws it. In order:
|
|
4
|
+
* 0. the picture uploaded for it in View (its profile avatar);
|
|
5
|
+
* 1. its own bot's avatar — only when it has a bot of its own: an instance on the shared bot skips this, the same
|
|
6
|
+
* face for everyone tells nobody apart; so does a bot with no avatar set (a default avatar says nothing);
|
|
7
|
+
* 2. its persona emoji (`status_emojis.delivered`, what set_persona_emoji sets): unicode as text, a Discord server
|
|
8
|
+
* emoji through the emoji route (a Telegram custom emoji has no picture here and falls through);
|
|
9
|
+
* 3. the first character of its display name, or of its name.
|
|
10
|
+
* Images are same-origin `/ui/img/…` URLs only; the version makes a changed picture a new URL.
|
|
11
|
+
*/
|
|
12
|
+
import { normalizeEmoji } from "./status-emojis.js";
|
|
13
|
+
const GRAPHEMES = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
14
|
+
/** The first user-perceived character, upper-cased where that means anything ("é" → "É", "中" stays). */
|
|
15
|
+
export function firstCharacter(text) {
|
|
16
|
+
for (const { segment } of GRAPHEMES.segment(text.trim()))
|
|
17
|
+
return segment.toLocaleUpperCase();
|
|
18
|
+
return "?";
|
|
19
|
+
}
|
|
20
|
+
export function avatarFor(input) {
|
|
21
|
+
if (input.profileVersion)
|
|
22
|
+
return { kind: "image", src: `/ui/img/avatar/${encodeURIComponent(input.name)}?v=${encodeURIComponent(input.profileVersion)}` };
|
|
23
|
+
if (input.bot)
|
|
24
|
+
return { kind: "image", src: `/ui/img/bot/${encodeURIComponent(input.bot.connection)}?v=${encodeURIComponent(input.bot.version)}` };
|
|
25
|
+
const emoji = normalizeEmoji(input.personaEmoji);
|
|
26
|
+
if (emoji?.kind === "unicode")
|
|
27
|
+
return { kind: "emoji", text: emoji.value };
|
|
28
|
+
if (emoji?.kind === "custom")
|
|
29
|
+
return { kind: "emoji", src: `/ui/img/emoji/${emoji.id}`, alt: `:${emoji.name}:` };
|
|
30
|
+
return { kind: "initial", text: firstCharacter(input.displayName || input.name) };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The connections that are ONE instance's own bot: not the primary (that is the fleet's shared bot), and answering for
|
|
34
|
+
* exactly one instance or ClassicBot room. `assignments` is every instance and room with the connection it uses.
|
|
35
|
+
*/
|
|
36
|
+
export function ownBotConnections(primary, assignments) {
|
|
37
|
+
const users = new Map();
|
|
38
|
+
for (const [instance, connection] of assignments) {
|
|
39
|
+
if (!connection)
|
|
40
|
+
continue;
|
|
41
|
+
const list = users.get(connection);
|
|
42
|
+
if (list)
|
|
43
|
+
list.push(instance);
|
|
44
|
+
else
|
|
45
|
+
users.set(connection, [instance]);
|
|
46
|
+
}
|
|
47
|
+
const own = new Map(); // instance → its own connection
|
|
48
|
+
for (const [connection, instances] of users)
|
|
49
|
+
if (connection !== primary && instances.length === 1)
|
|
50
|
+
own.set(instances[0], connection);
|
|
51
|
+
return own;
|
|
52
|
+
}
|
|
53
|
+
/** A Discord role colour as the page may use it: `#rrggbb`, never black (Discord's "no colour"). */
|
|
54
|
+
export function accentColor(raw) {
|
|
55
|
+
return typeof raw === "string" && /^#[0-9a-f]{6}$/i.test(raw) && raw.toLowerCase() !== "#000000" ? raw.toLowerCase() : null;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=instance-avatar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-avatar.js","sourceRoot":"","sources":["../src/instance-avatar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAQpD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;AAC7E,wGAAwG;AACxG,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAAE,OAAO,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAC7F,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KASzB;IACC,IAAI,KAAK,CAAC,cAAc;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,kBAAkB,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,kBAAkB,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC;IAC1J,IAAI,KAAK,CAAC,GAAG;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,eAAe,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;IACnJ,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACjD,IAAI,KAAK,EAAE,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAC3E,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC;IACjH,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AACpF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA2B,EAAE,WAAuF;IACpJ,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,WAAW,EAAE,CAAC;QACjD,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACnC,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;;YAAM,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC,CAAU,gCAAgC;IAChF,KAAK,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,KAAK;QAAE,IAAI,UAAU,KAAK,OAAO,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAE,EAAE,UAAU,CAAC,CAAC;IACtI,OAAO,GAAG,CAAC;AACb,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9H,CAAC"}
|
|
@@ -82,6 +82,11 @@ const FLEET_FIELD_IMPACTS = {
|
|
|
82
82
|
"web.public_link.allow_public": "now",
|
|
83
83
|
"web.public_link.ttl_minutes": "now",
|
|
84
84
|
"web.public_link.protocol": "now",
|
|
85
|
+
// #1620: read at every session check, and by /login when it starts a terminal.
|
|
86
|
+
"web.session.local.absolute_hours": "now",
|
|
87
|
+
"web.session.local.idle_hours": "now",
|
|
88
|
+
"web_terminal.enabled": "now",
|
|
89
|
+
"web_terminal.ttl_minutes": "now",
|
|
85
90
|
"defaults.locale": "now",
|
|
86
91
|
"fleet.channels": "fleet",
|
|
87
92
|
"fleet.channel.access.mode": "fleet",
|