toolroll 0.9.54 → 0.9.56
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/CHANGELOG.md +19 -0
- package/README.md +29 -12
- package/dist/action-ledger.d.ts +2 -4
- package/dist/action-ledger.js +2 -10
- package/dist/agent-onboard.js +4 -1
- package/dist/approval-policy.d.ts +5 -5
- package/dist/approval-policy.js +4 -4
- package/dist/approval-rules-ui.d.ts +3 -2
- package/dist/approval-rules-ui.js +17 -22
- package/dist/assignment-ui.d.ts +3 -2
- package/dist/assignment-ui.js +4 -11
- package/dist/backup-ui.d.ts +2 -1
- package/dist/backup-ui.js +16 -27
- package/dist/brand-mark.d.ts +3 -2
- package/dist/brand-mark.js +4 -4
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +25 -25
- package/dist/browser-shell.d.ts +2 -1
- package/dist/browser-shell.js +9 -9
- package/dist/browser-workspace.d.ts +14 -15
- package/dist/browser-workspace.js +0 -3
- package/dist/budget-alerts.js +3 -3
- package/dist/chat-actions.d.ts +23 -18
- package/dist/chat-actions.js +110 -88
- package/dist/chat-ask.d.ts +2 -2
- package/dist/chat-ask.js +5 -5
- package/dist/chat-channel.d.ts +15 -15
- package/dist/chat-channel.js +20 -20
- package/dist/chat-controls.d.ts +0 -4
- package/dist/chat-controls.js +0 -1
- package/dist/chat-core.js +1 -1
- package/dist/chat-delivery-state.js +2 -2
- package/dist/chat-delivery.d.ts +2 -2
- package/dist/chat-delivery.js +27 -34
- package/dist/chat-flow.js +3 -3
- package/dist/chat-messages.d.ts +1 -1
- package/dist/chat-messages.js +4 -4
- package/dist/chat-migration.d.ts +1 -1
- package/dist/chat-migration.js +11 -11
- package/dist/chat-polish.d.ts +5 -4
- package/dist/chat-polish.js +9 -10
- package/dist/chat-rooms.js +3 -3
- package/dist/chat-warmth.d.ts +2 -2
- package/dist/check-levels-ui.d.ts +2 -1
- package/dist/check-levels-ui.js +26 -53
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +15 -10
- package/dist/coding-shipping-ui.d.ts +2 -1
- package/dist/coding-shipping-ui.js +6 -6
- package/dist/coding-ui.d.ts +3 -1
- package/dist/coding-ui.js +30 -29
- package/dist/contracts/chat-actions.d.ts +32 -27
- package/dist/contracts/chat-actions.js +29 -11
- package/dist/contracts/chat-content.d.ts +1 -1
- package/dist/contracts/chat-content.js +1 -1
- package/dist/contracts/chat-tables.js +4 -4
- package/dist/contracts/cli.d.ts +1 -3
- package/dist/contracts/console-api.d.ts +7 -7
- package/dist/contracts/console-api.js +13 -12
- package/dist/contracts/flow-propose.d.ts +3 -3
- package/dist/contracts/flow.d.ts +132 -125
- package/dist/contracts/flow.js +27 -12
- package/dist/contracts/health.d.ts +1 -3
- package/dist/contracts/lead-context.d.ts +1 -1
- package/dist/contracts/lead-context.js +2 -2
- package/dist/contracts/lead-tools.d.ts +20 -18
- package/dist/contracts/lead-tools.js +15 -15
- package/dist/contracts/stage-output.d.ts +1 -1
- package/dist/contracts/stage-output.js +1 -1
- package/dist/contracts/store-json.d.ts +23 -22
- package/dist/contracts/store-json.js +17 -17
- package/dist/contracts/{teammate-turn.d.ts → subagent-turn.d.ts} +5 -5
- package/dist/contracts/{teammate-turn.js → subagent-turn.js} +7 -7
- package/dist/control-ui.d.ts +5 -4
- package/dist/control-ui.js +9 -34
- package/dist/converse.d.ts +23 -23
- package/dist/converse.js +28 -28
- package/dist/coordinator-proposals.d.ts +2 -2
- package/dist/coordinator-proposals.js +1 -1
- package/dist/coordinator.js +1 -1
- package/dist/credentials-ui.d.ts +5 -4
- package/dist/credentials-ui.js +23 -24
- package/dist/demo-chat.d.ts +3 -3
- package/dist/demo-chat.js +29 -76
- package/dist/deprecations.d.ts +12 -0
- package/dist/deprecations.js +20 -0
- package/dist/desktop-update-gate.js +8 -4
- package/dist/desktop-update.js +6 -1
- package/dist/discord-chat.js +6 -6
- package/dist/discord-settings.d.ts +3 -2
- package/dist/discord-settings.js +17 -42
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/envelope.js +10 -1
- package/dist/evidence-pack.d.ts +2 -1
- package/dist/evidence-pack.js +45 -49
- package/dist/export-ui.d.ts +7 -2
- package/dist/export-ui.js +4 -10
- package/dist/export.js +7 -7
- package/dist/flow-engine.d.ts +2 -2
- package/dist/flow-engine.js +21 -21
- package/dist/flow-gallery-ui.d.ts +4 -3
- package/dist/flow-gallery-ui.js +28 -43
- package/dist/flow-insights.d.ts +1 -1
- package/dist/flow-share.js +13 -8
- package/dist/flow-starters-ui.d.ts +2 -1
- package/dist/flow-starters-ui.js +12 -15
- package/dist/flow-steps.d.ts +5 -5
- package/dist/flow-steps.js +19 -19
- package/dist/flow-triggers.d.ts +2 -1
- package/dist/flow-triggers.js +17 -15
- package/dist/flows-cli.js +1 -1
- package/dist/flows-ui.d.ts +4 -3
- package/dist/flows-ui.js +38 -49
- package/dist/flows.js +21 -20
- package/dist/guides.js +112 -6
- package/dist/html.d.ts +76 -0
- package/dist/html.js +173 -0
- package/dist/integrations-ui.d.ts +2 -1
- package/dist/integrations-ui.js +19 -23
- package/dist/invoke.js +1 -1
- package/dist/kits-ui.d.ts +5 -4
- package/dist/kits-ui.js +22 -24
- package/dist/kits.d.ts +12 -12
- package/dist/kits.js +31 -31
- package/dist/knowledge-ui.d.ts +6 -5
- package/dist/knowledge-ui.js +26 -25
- package/dist/{mate-cli.d.ts → lead-cli.d.ts} +11 -11
- package/dist/{mate-cli.js → lead-cli.js} +38 -38
- package/dist/lead-commitments.js +4 -4
- package/dist/lead-context.d.ts +12 -2
- package/dist/lead-context.js +15 -17
- package/dist/{mate-contract.d.ts → lead-contract.d.ts} +3 -3
- package/dist/{mate-contract.js → lead-contract.js} +7 -6
- package/dist/{mate-doors.d.ts → lead-doors.d.ts} +6 -6
- package/dist/{mate-doors.js → lead-doors.js} +24 -24
- package/dist/lead-follow.d.ts +5 -5
- package/dist/lead-follow.js +9 -9
- package/dist/lead-people.d.ts +5 -5
- package/dist/lead-people.js +14 -14
- package/dist/{mate-progress.d.ts → lead-progress.d.ts} +9 -9
- package/dist/{mate-progress.js → lead-progress.js} +3 -3
- package/dist/{mate-tools.d.ts → lead-tools.d.ts} +19 -19
- package/dist/{mate-tools.js → lead-tools.js} +109 -101
- package/dist/{mate.d.ts → lead.d.ts} +27 -27
- package/dist/{mate.js → lead.js} +102 -102
- package/dist/ledger-view.d.ts +2 -1
- package/dist/ledger-view.js +27 -29
- package/dist/limits-ui.d.ts +3 -2
- package/dist/limits-ui.js +8 -8
- package/dist/live-bus.d.ts +50 -8
- package/dist/live-bus.js +133 -50
- package/dist/mcp-connect.d.ts +1 -1
- package/dist/mcp-connect.js +3 -3
- package/dist/mcp-core.js +1 -1
- package/dist/mcp-oauth.js +35 -36
- package/dist/memory-pass.d.ts +2 -2
- package/dist/memory-pass.js +7 -7
- package/dist/models-ui.d.ts +2 -1
- package/dist/models-ui.js +25 -35
- package/dist/monitoring-ui.d.ts +4 -3
- package/dist/monitoring-ui.js +13 -26
- package/dist/notification-rows.d.ts +2 -2
- package/dist/openrouter-models.d.ts +2 -1
- package/dist/openrouter-models.js +5 -9
- package/dist/operate.d.ts +3 -3
- package/dist/operate.js +46 -41
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +13 -13
- package/dist/policy-ui.d.ts +3 -2
- package/dist/policy-ui.js +17 -23
- package/dist/policy.d.ts +1 -1
- package/dist/principal.d.ts +1 -1
- package/dist/principal.js +2 -2
- package/dist/project-delete-ui.d.ts +4 -3
- package/dist/project-delete-ui.js +16 -28
- package/dist/project-delete.d.ts +1 -1
- package/dist/project-delete.js +26 -26
- package/dist/project-memory.js +1 -1
- package/dist/project-tools.d.ts +1 -1
- package/dist/project-tools.js +1 -1
- package/dist/pull-request-ui.d.ts +2 -1
- package/dist/pull-request-ui.js +17 -32
- package/dist/recipe-ui.d.ts +8 -7
- package/dist/recipe-ui.js +39 -32
- package/dist/release-adapters.d.ts +60 -0
- package/dist/release-adapters.js +435 -0
- package/dist/release-cli.d.ts +24 -0
- package/dist/release-cli.js +181 -0
- package/dist/release-gate.d.ts +80 -0
- package/dist/release-gate.js +150 -0
- package/dist/release-links.d.ts +29 -0
- package/dist/release-links.js +102 -0
- package/dist/release.d.ts +331 -0
- package/dist/release.js +550 -0
- package/dist/reply-shape.d.ts +2 -1
- package/dist/reply-shape.js +5 -5
- package/dist/repository-context-ui.d.ts +2 -1
- package/dist/repository-context-ui.js +2 -7
- package/dist/request-budget-ui.d.ts +2 -1
- package/dist/request-budget-ui.js +16 -16
- package/dist/result-review.d.ts +2 -3
- package/dist/result-review.js +3 -9
- package/dist/retention-ui.d.ts +7 -1
- package/dist/retention-ui.js +7 -11
- package/dist/retention.js +4 -4
- package/dist/scope.d.ts +2 -2
- package/dist/scout-report.d.ts +1 -1
- package/dist/scout-report.js +1 -1
- package/dist/serve.d.ts +11 -2
- package/dist/serve.js +105 -99
- package/dist/server/chat.d.ts +7 -10
- package/dist/server/chat.js +984 -1021
- package/dist/server/chrome.d.ts +291 -0
- package/dist/server/chrome.js +747 -0
- package/dist/server/console.css +2819 -0
- package/dist/server/flows.d.ts +2 -6
- package/dist/server/flows.js +854 -773
- package/dist/server/guards.d.ts +1 -1
- package/dist/server/guards.js +8 -5
- package/dist/server/handler-context.d.ts +1 -1
- package/dist/server/handler-context.js +1 -1
- package/dist/server/handler-registry.d.ts +8 -6
- package/dist/server/handler-registry.js +14 -2
- package/dist/server/http.d.ts +274 -0
- package/dist/server/http.js +239 -0
- package/dist/server/live.d.ts +34 -0
- package/dist/server/live.js +309 -0
- package/dist/server/pages.d.ts +2 -6
- package/dist/server/pages.js +808 -789
- package/dist/server/people-tokens.d.ts +1 -6
- package/dist/server/people-tokens.js +581 -573
- package/dist/server/remote.d.ts +4 -7
- package/dist/server/remote.js +39 -70
- package/dist/server/render-chat.d.ts +402 -0
- package/dist/server/render-chat.js +927 -0
- package/dist/server/render-pages.d.ts +535 -0
- package/dist/server/render-pages.js +1277 -0
- package/dist/server/render-people.d.ts +32 -0
- package/dist/server/render-people.js +121 -0
- package/dist/server/render-results.d.ts +744 -0
- package/dist/server/render-results.js +2237 -0
- package/dist/server/render-settings.d.ts +154 -0
- package/dist/server/render-settings.js +580 -0
- package/dist/server/render-tasks.d.ts +632 -0
- package/dist/server/render-tasks.js +2345 -0
- package/dist/server/request-context.d.ts +46 -0
- package/dist/server/request-context.js +17 -0
- package/dist/server/route-table.d.ts +25 -3
- package/dist/server/route-table.js +167 -77
- package/dist/server/runtime.d.ts +28 -20
- package/dist/server/runtime.js +7 -1
- package/dist/server/session.d.ts +138 -0
- package/dist/server/session.js +94 -0
- package/dist/server/settings.d.ts +1 -5
- package/dist/server/settings.js +2186 -2121
- package/dist/server/task-views.d.ts +11 -4
- package/dist/server/task-views.js +26 -22
- package/dist/server/tasks.d.ts +9 -9
- package/dist/server/tasks.js +1489 -1420
- package/dist/server-telemetry.d.ts +4 -3
- package/dist/server-telemetry.js +4 -8
- package/dist/setup-guide.d.ts +2 -2
- package/dist/skills-ui.d.ts +4 -3
- package/dist/skills-ui.js +14 -17
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +2 -1
- package/dist/slack-chat.d.ts +2 -2
- package/dist/slack-chat.js +6 -6
- package/dist/slack-settings.d.ts +3 -2
- package/dist/slack-settings.js +17 -42
- package/dist/spend-ui.d.ts +5 -4
- package/dist/spend-ui.js +17 -40
- package/dist/spend.d.ts +14 -14
- package/dist/spend.js +31 -31
- package/dist/sso-ui.d.ts +3 -2
- package/dist/sso-ui.js +26 -27
- package/dist/storage-ui.d.ts +2 -1
- package/dist/storage-ui.js +14 -33
- package/dist/store-baseline.d.ts +19 -0
- package/dist/store-baseline.js +2873 -0
- package/dist/store.d.ts +197 -249
- package/dist/store.js +747 -3084
- package/dist/subagent-admin.d.ts +53 -0
- package/dist/{teammate-admin.js → subagent-admin.js} +37 -37
- package/dist/{teammate-desk.d.ts → subagent-desk.d.ts} +22 -23
- package/dist/{teammate-desk.js → subagent-desk.js} +26 -35
- package/dist/{teammate-memory.d.ts → subagent-memory.d.ts} +17 -17
- package/dist/{teammate-memory.js → subagent-memory.js} +41 -41
- package/dist/{teammate-question.d.ts → subagent-question.d.ts} +6 -6
- package/dist/{teammate-question.js → subagent-question.js} +17 -17
- package/dist/{teammate-tools.d.ts → subagent-tools.d.ts} +18 -18
- package/dist/{teammate-tools.js → subagent-tools.js} +36 -36
- package/dist/{teammate-week.d.ts → subagent-week.d.ts} +10 -10
- package/dist/{teammate-week.js → subagent-week.js} +23 -23
- package/dist/{teammate-work.d.ts → subagent-work.d.ts} +21 -21
- package/dist/{teammate-work.js → subagent-work.js} +50 -50
- package/dist/subagents-ui.d.ts +22 -0
- package/dist/subagents-ui.js +137 -0
- package/dist/{teammates.d.ts → subagents.d.ts} +11 -11
- package/dist/{teammates.js → subagents.js} +21 -21
- package/dist/subscription-chat.d.ts +13 -13
- package/dist/subscription-chat.js +19 -19
- package/dist/surface.d.ts +19 -2
- package/dist/surface.js +20 -33
- package/dist/task-composer.d.ts +2 -1
- package/dist/task-composer.js +7 -7
- package/dist/task-status.d.ts +4 -3
- package/dist/task-status.js +15 -16
- package/dist/team-cli.d.ts +1 -0
- package/dist/team-cli.js +14 -2
- package/dist/team-http.d.ts +5 -9
- package/dist/team-http.js +5 -63
- package/dist/team-leads.js +13 -13
- package/dist/team-runtime.d.ts +2 -2
- package/dist/team-runtime.js +8 -8
- package/dist/team-ui.d.ts +2 -1
- package/dist/team-ui.js +2 -5
- package/dist/teams-chat.js +6 -6
- package/dist/teams-settings.d.ts +3 -2
- package/dist/teams-settings.js +20 -31
- package/dist/telegram-flow.d.ts +3 -3
- package/dist/telegram-flow.js +3 -3
- package/dist/{telegram-mate.d.ts → telegram-lead.d.ts} +5 -5
- package/dist/{telegram-mate.js → telegram-lead.js} +27 -27
- package/dist/telegram-settings.d.ts +3 -2
- package/dist/telegram-settings.js +14 -25
- package/dist/telegram-status.js +1 -1
- package/dist/telegram-team.d.ts +1 -1
- package/dist/telegram-team.js +5 -5
- package/dist/telegram.d.ts +1 -1
- package/dist/telegram.js +9 -30
- package/dist/text-limits.d.ts +18 -18
- package/dist/text-limits.js +18 -18
- package/dist/toolroll-update-ui.d.ts +3 -2
- package/dist/toolroll-update-ui.js +35 -39
- package/dist/toolroll-update.d.ts +8 -0
- package/dist/toolroll-update.js +45 -8
- package/dist/tools-ui.d.ts +5 -2
- package/dist/tools-ui.js +31 -31
- package/dist/when-html.d.ts +11 -3
- package/dist/when-html.js +5 -6
- package/dist/workspace-ui.d.ts +4 -2
- package/dist/workspace-ui.js +10 -10
- package/package.json +1 -2
- package/dist/server/shared.d.ts +0 -3151
- package/dist/server/shared.js +0 -12001
- package/dist/teammate-admin.d.ts +0 -53
- package/dist/teammates-ui.d.ts +0 -20
- package/dist/teammates-ui.js +0 -166
package/dist/surface.js
CHANGED
|
@@ -19,13 +19,11 @@ import { FLOWS_DESCRIPTORS } from "./flows-cli.js";
|
|
|
19
19
|
* CANNOT prove — that a given flag is read by a given handler — is why
|
|
20
20
|
* SURFACE_NOTES.flags says "intended".
|
|
21
21
|
*/
|
|
22
|
-
import { SESSION_DESCRIPTORS } from './session-contract.js';
|
|
23
|
-
import { sessionCliFlags } from './session-cli.js';
|
|
24
22
|
import { commandEntries } from './contracts/cli.js';
|
|
25
23
|
/** The guide's limits, stated machine-readably in every dump. */
|
|
26
24
|
export const SURFACE_NOTES = {
|
|
27
|
-
authority: "documentation is not permission;
|
|
28
|
-
flags: "
|
|
25
|
+
authority: "documentation is not permission; legacy entries remain advisory",
|
|
26
|
+
flags: "flags are intended per command and may use a global parser vocabulary",
|
|
29
27
|
reasons: "curated, not exhaustive — the runtime `reason` field is the truth; ignore tokens you do not recognize",
|
|
30
28
|
database: "local database commands wait up to 15 seconds for another writer; an exhausted wait returns database-busy and names the selected file",
|
|
31
29
|
};
|
|
@@ -66,22 +64,9 @@ const GUIDE_ROWS = [
|
|
|
66
64
|
{ invocation: "graph", synopsis: "report which work graph is already here", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag] },
|
|
67
65
|
{ invocation: "repos", synopsis: "list connected repositories", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag] },
|
|
68
66
|
operator("proposals", "what coordinators proposed over the MCP gateway — list, confirm <id> [--yes], dismiss <id>; confirming runs the plane's own door under your password"),
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
operator('lead create', 'create a central lead with --name, --instructions and repeatable --project paths admitted by the server'),
|
|
73
|
-
operator('lead update', 'change --name, --instructions or --status for --lead at --revision; projects remain fixed'),
|
|
74
|
-
operator('lead member', 'set --account membership on --lead with --role, --active true|false and the current --revision'),
|
|
75
|
-
operator('lead transfer', 'move ownership of --task to --lead at --revision; existing execution authority remains unchanged'),
|
|
76
|
-
operatorRead('conversation list', 'list admitted conversations, optionally within --lead; attachment never starts model work'),
|
|
77
|
-
operator('conversation create', 'create a conversation with --lead, --title, --visibility private|team and repeatable --project paths'),
|
|
78
|
-
operatorRead('conversation show', 'read --conversation messages and saved work; no model call or read-marker mutation'),
|
|
79
|
-
operator('conversation member', 'set --account membership on --conversation with --role, --active true|false and the current --revision; lead membership must already permit the role'),
|
|
80
|
-
operator('conversation edit', 'edit your queued --message in --conversation at --revision using --text; running messages cannot be edited'),
|
|
81
|
-
operator('conversation withdraw', 'withdraw your queued --message in --conversation at --revision; an active turn requires stop'),
|
|
82
|
-
operator('conversation read', 'explicitly record your read position at --message within --conversation'),
|
|
83
|
-
operator('conversation follow', 'enable or pause automatic lead summaries with --conversation and --enabled true|false, within the existing paid chat authorization; passive chat --follow only reads updates'),
|
|
84
|
-
operator('conversation stop', 'request stopping the exact --message in --conversation; retain uncertain work until its owner settles it'),
|
|
67
|
+
// D5: the central team service (connect, the central lead verbs, conversation …) and native coding sessions are
|
|
68
|
+
// deprecated: they still run this release, with a warning, but are no longer declared here.
|
|
69
|
+
operator("chat", "talk to your lead: one conversation across every project; --say sends one message; --follow enables crew updates and --no-follow pauses them; proposals keep their approval requirements"),
|
|
85
70
|
{ invocation: "repos add", synopsis: "add a project: a Git repository, in the console at once; the lead adds with its token", audience: "agent", agentMayInvoke: true, mutation: "identity-idempotent",
|
|
86
71
|
positionals: [{ name: "path", required: false, meaning: "the repository (default: the one you are in)" }],
|
|
87
72
|
flags: [jsonFlag, { name: "token", takesValue: true, meaning: "the lead token (or TOOLROLL_LEAD_TOKEN)" }],
|
|
@@ -114,13 +99,18 @@ const GUIDE_ROWS = [
|
|
|
114
99
|
operator("link", "put toolroll on PATH"),
|
|
115
100
|
operator("unlink", "take it off PATH"),
|
|
116
101
|
operator("update", "update to the latest release: verified provenance, drained work, backup, rehearsal, health check, automatic restore; --rollback undoes it"),
|
|
102
|
+
{ invocation: "release", synopsis: "release Toolroll itself from a branch: gate the exact commit, wait for the owner's approval, check, complete, deploy, merge, tag, publish, Homebrew; rerun to resume",
|
|
103
|
+
audience: "operator", agentMayInvoke: false, mutation: "unkeyed",
|
|
104
|
+
positionals: [{ name: "branch", required: true, meaning: "the pushed branch with an open pull request" }],
|
|
105
|
+
flags: [jsonFlag,
|
|
106
|
+
{ name: "repo", takesValue: true, meaning: "the gate checkout the release check runs in (default: this checkout)" },
|
|
107
|
+
{ name: "new", takesValue: false, meaning: "release a new commit on the branch, setting the earlier unfinished release aside" },
|
|
108
|
+
{ name: "limit", takesValue: true, meaning: "<step>=<minutes>: one waiting step's time limit" },
|
|
109
|
+
{ name: "tap", takesValue: true, meaning: "the Homebrew tap, owner/name" },
|
|
110
|
+
{ name: "release-gate", takesValue: true, meaning: "<id>: show why an update pause left before a deployment's swap is safe to lift" },
|
|
111
|
+
{ name: "yes", takesValue: false, meaning: "with --release-gate: lift that one pause once it is proved" }],
|
|
112
|
+
notableReasons: ["usage", "ambiguous", "drift", "timeout", "check-failed", "ci-failed", "tree-mismatch", "conflict", "mixed-runtime", "gate-held", "after-swap"] },
|
|
117
113
|
operator("demo", "a seeded throwaway sandbox"),
|
|
118
|
-
{ invocation: 'session capabilities', synopsis: 'Show executable session schemas and operator authority requirements; no credentials needed', audience: 'agent', agentMayInvoke: true, mutation: 'none', flags: [jsonFlag] },
|
|
119
|
-
...SESSION_DESCRIPTORS.map(spec => ({
|
|
120
|
-
invocation: `session ${spec.operation}`, synopsis: spec.synopsis, audience: spec.audience, agentMayInvoke: spec.agentMayInvoke,
|
|
121
|
-
mutation: spec.mutation ? 'keyed' : 'none', inputSchema: spec.inputSchema,
|
|
122
|
-
flags: Object.entries(sessionCliFlags(spec)).map(([name, arity]) => ({ name, takesValue: arity === 'value', meaning: name === 'key' ? 'keep the same key when reconciling; inspect after unknown delivery, never blind-retry' : `see session ${spec.operation} --help` })),
|
|
123
|
-
})),
|
|
124
114
|
...KNOWLEDGE_DESCRIPTORS.map(spec => ({ invocation: `knowledge ${spec.action}`, synopsis: spec.synopsis, audience: "audience" in spec ? spec.audience : "agent", agentMayInvoke: !("audience" in spec), mutation: spec.mutation, flags: spec.flags, ...(spec.takesQuery ? { positionals: [{ name: "query", required: true, meaning: "search text or source file for impact" }] } : {}) })),
|
|
125
115
|
...MEMORY_DESCRIPTORS.map(spec => ({ invocation: `memory ${spec.action}`, synopsis: spec.synopsis, audience: "agent", agentMayInvoke: true, mutation: spec.mutation, flags: spec.flags, ...(spec.takesQuery ? { positionals: [{ name: "query", required: true, meaning: "search text, a decision id, or the decision sentence" }] } : {}) })),
|
|
126
116
|
// Flow writes carry an approver's credential: an agent runs them only as the person asked, after showing the preview.
|
|
@@ -133,7 +123,7 @@ const GUIDE_ROWS = [
|
|
|
133
123
|
{ invocation: "integrations", synopsis: "every integration as Connected, Not set up or Broken, with its last success and error, what uses it and what to do; --saved skips new checks; never a secret", audience: "agent", agentMayInvoke: true, mutation: "none",
|
|
134
124
|
flags: [jsonFlag, dbFlag, { name: "saved", takesValue: false, meaning: "show the last checks without checking again" }] },
|
|
135
125
|
{ invocation: "ready", synopsis: "what could be dispatched right now (rows carry reservedFor)", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag] },
|
|
136
|
-
{ invocation: "brief", synopsis: "
|
|
126
|
+
{ invocation: "brief", synopsis: "the lead's catch-up from the local database; --history selects the older operational report", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag] },
|
|
137
127
|
{ invocation: "gaps", synopsis: "requirement gaps blocking dispatch", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag, repoFlag] },
|
|
138
128
|
{ invocation: "grants", synopsis: "list authority grants", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag] },
|
|
139
129
|
{ invocation: "audit", synopsis: "what people did on this server with their API tokens, newest first: when, who, which token, from the CLI (api) or an agent (mcp), the command or tool, the project and the outcome (ok, refused, error); an approver sees everyone in their projects, anyone else only themselves",
|
|
@@ -315,7 +305,7 @@ const GUIDE_ROWS = [
|
|
|
315
305
|
{ invocation: "heartbeat", synopsis: "still working; extends the lease", audience: "agent", agentMayInvoke: true, mutation: "identity-idempotent",
|
|
316
306
|
positionals: [{ name: "lease", required: true, meaning: "the lease id" }],
|
|
317
307
|
flags: [jsonFlag, dbFlag], notableReasons: ["not-leased", "fenced"] },
|
|
318
|
-
{ invocation: "release", synopsis: "done with it; fenced if superseded", audience: "agent", agentMayInvoke: true, mutation: "identity-idempotent",
|
|
308
|
+
{ invocation: "worker release", synopsis: "done with it; fenced if superseded", audience: "agent", agentMayInvoke: true, mutation: "identity-idempotent",
|
|
319
309
|
positionals: [{ name: "lease", required: true, meaning: "the lease id" }],
|
|
320
310
|
flags: [jsonFlag, dbFlag], notableReasons: ["not-leased", "fenced"] },
|
|
321
311
|
{ invocation: "reap", synopsis: "release every lease that ran out", audience: "agent", agentMayInvoke: true, mutation: "identity-idempotent", flags: [jsonFlag, dbFlag] },
|
|
@@ -428,15 +418,12 @@ const GUIDE_ROWS = [
|
|
|
428
418
|
const REMOTE_NO = [
|
|
429
419
|
// Answered by the local CLI, or a client of a central server itself.
|
|
430
420
|
"", "pulls", "graph", "repos", "repos add", "repos remove", "repos add-from-github", "contract", "skills list", "skills get", "skills install",
|
|
431
|
-
"link", "unlink", "update", "
|
|
432
|
-
"conversation list", "conversation create", "conversation show", "conversation member", "conversation edit", "conversation withdraw",
|
|
433
|
-
"conversation read", "conversation follow", "conversation stop",
|
|
434
|
-
"session capabilities", "session list", "session show", "session changes", "session start", "session send", "session stop", "session resume", "session recover",
|
|
421
|
+
"link", "unlink", "update", "release", "demo", "chat",
|
|
435
422
|
// This machine's checkout, saved profile, credentials and catch-up.
|
|
436
423
|
"project show", "project use", "brief", "lead token", "lead say", "health",
|
|
437
424
|
"assignment show", "assignment updates", "assignment claim", "assignment check", "assignment brief", "assignment inbox", "assignment ack",
|
|
438
425
|
// Workers, the loop and the services that run here.
|
|
439
|
-
"claim", "heartbeat", "release", "reap", "tick", "build", "reconcile",
|
|
426
|
+
"claim", "heartbeat", "worker release", "reap", "tick", "build", "reconcile",
|
|
440
427
|
"runner register", "runner retire", "runner bind", "runner capacity", "coordinator mint", "coordinator revoke", "mcp", "outbox deliver", "peek",
|
|
441
428
|
"serve", "serve check-public", "watch", "up", "onboard", "daemon", "bridge", "setup show", "setup clear",
|
|
442
429
|
// Provider keys and model tools on this machine.
|
package/dist/task-composer.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** UI choices translate into the same digest-bound schedules as the CLI. */
|
|
2
2
|
import { type Schedule } from "./flow-schedule.js";
|
|
3
|
+
import { type Html } from "./html.js";
|
|
3
4
|
export declare function composerSchedule(fields: URLSearchParams): {
|
|
4
5
|
ok: true;
|
|
5
6
|
schedule: string | null;
|
|
@@ -9,5 +10,5 @@ export declare function composerSchedule(fields: URLSearchParams): {
|
|
|
9
10
|
};
|
|
10
11
|
export declare function scheduleFields(schedule: Schedule): Record<string, string>;
|
|
11
12
|
/** A normal form works without JavaScript; enhancement only folds unused fields. */
|
|
12
|
-
export declare function scheduleEditorHtml(raw: string | null, submitted?: URLSearchParams):
|
|
13
|
+
export declare function scheduleEditorHtml(raw: string | null, submitted?: URLSearchParams): Html;
|
|
13
14
|
export declare function scheduleEditorScript(): string;
|
package/dist/task-composer.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** UI choices translate into the same digest-bound schedules as the CLI. */
|
|
2
2
|
import { parseSchedule, scheduleText, validTimezone } from "./flow-schedule.js";
|
|
3
|
+
import { html, joinHtml } from "./html.js";
|
|
3
4
|
export function composerSchedule(fields) {
|
|
4
5
|
const repeat = fields.get("repeat") ?? "once";
|
|
5
6
|
if (repeat === "once")
|
|
@@ -29,18 +30,17 @@ export function scheduleFields(schedule) {
|
|
|
29
30
|
}
|
|
30
31
|
return { repeat: schedule.kind, time: schedule.hhmm, timezone: schedule.timezone ?? "UTC", ...(schedule.kind === "weekly" ? { weekday: String(schedule.day) } : {}) };
|
|
31
32
|
}
|
|
32
|
-
const escape = (text) => text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33
33
|
/** A normal form works without JavaScript; enhancement only folds unused fields. */
|
|
34
34
|
export function scheduleEditorHtml(raw, submitted) {
|
|
35
35
|
const parsed = raw === null ? null : parseSchedule(raw);
|
|
36
36
|
const fields = submitted?.has("repeat") ? Object.fromEntries(submitted) : parsed === null ? {} : scheduleFields(parsed);
|
|
37
37
|
const repeat = fields.repeat ?? "daily";
|
|
38
|
-
const value = (name, fallback) =>
|
|
39
|
-
return `<fieldset data-schedule-editor${raw === null && submitted === undefined ?
|
|
40
|
-
`<label>Repeat<select name="repeat">${[["daily", "Daily"], ["weekly", "Weekly"], ["custom", "Custom interval"]].map(([id, label]) => `<option value="${id}"${repeat === id ?
|
|
41
|
-
`<div data-schedule-kind="weekly"><label>Day<select name="weekday">${["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].map((day, index) => `<option value="${index}"${String(index) === (fields.weekday ?? "1") ?
|
|
42
|
-
`<div data-schedule-kind="calendar"><label>Time<input type="time" name="time" value="${value("time", "09:00")}"></label><label>Timezone<input type="text" name="timezone" value="${value("timezone", "UTC")}" autocomplete="off" placeholder="America/Los_Angeles"></label><p class="meta">Daily and weekly times follow this timezone. A skipped clock time skips that occurrence; a repeated time runs once.</p></div
|
|
43
|
-
`<div data-schedule-kind="custom"><label>Every<input type="number" name="interval" min="1" value="${value("interval", "60")}"></label><label>Unit<select name="interval-unit">${["minutes", "hours", "days"].map(unit => `<option${unit === (fields["interval-unit"] ?? "minutes") ?
|
|
38
|
+
const value = (name, fallback) => fields[name] ?? fallback;
|
|
39
|
+
return joinHtml([html `<fieldset data-schedule-editor${raw === null && submitted === undefined ? html ` data-detect-timezone="true"` : ""}><legend>When to run</legend>`,
|
|
40
|
+
html `<label>Repeat<select name="repeat">${[["daily", "Daily"], ["weekly", "Weekly"], ["custom", "Custom interval"]].map(([id, label]) => html `<option value="${id}"${repeat === id ? html ` selected` : ""}>${label}</option>`)}</select></label>`,
|
|
41
|
+
html `<div data-schedule-kind="weekly"><label>Day<select name="weekday">${["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].map((day, index) => html `<option value="${index}"${String(index) === (fields.weekday ?? "1") ? html ` selected` : ""}>${day}</option>`)}</select></label></div>`,
|
|
42
|
+
html `<div data-schedule-kind="calendar"><label>Time<input type="time" name="time" value="${value("time", "09:00")}"></label><label>Timezone<input type="text" name="timezone" value="${value("timezone", "UTC")}" autocomplete="off" placeholder="America/Los_Angeles"></label><p class="meta">Daily and weekly times follow this timezone. A skipped clock time skips that occurrence; a repeated time runs once.</p></div>`,
|
|
43
|
+
html `<div data-schedule-kind="custom"><label>Every<input type="number" name="interval" min="1" value="${value("interval", "60")}"></label><label>Unit<select name="interval-unit">${["minutes", "hours", "days"].map(unit => html `<option${unit === (fields["interval-unit"] ?? "minutes") ? html ` selected` : ""}>${unit}</option>`)}</select></label><p class="meta">Intervals range from 5 minutes to 7 days.</p></div></fieldset>`]);
|
|
44
44
|
}
|
|
45
45
|
export function scheduleEditorScript() {
|
|
46
46
|
return `(function(){document.querySelectorAll('[data-schedule-editor]').forEach(function(root){
|
package/dist/task-status.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Html } from "./html.js";
|
|
1
2
|
import type { AssignmentSnapshot } from "./assignment.js";
|
|
2
3
|
import { type NeedAction, type NeedContext, type NeedKey, type WaitKey } from "./needs-you.js";
|
|
3
4
|
export type { NeedKey, WaitKey } from "./needs-you.js";
|
|
@@ -200,9 +201,9 @@ export declare function workToneOf(headline: Headline): "attention" | "problem"
|
|
|
200
201
|
export declare function statusDetailLines(status: TaskStatus): string[];
|
|
201
202
|
/** The headline's emoji for chat cards (colour is never the only signal: the words follow). */
|
|
202
203
|
export declare function headlineEmoji(headline: Headline): string;
|
|
203
|
-
export declare const statusIconSvg: (mark: DetailMark) =>
|
|
204
|
+
export declare const statusIconSvg: (mark: DetailMark) => Html;
|
|
204
205
|
/** The detail rows as server HTML: quiet rows, colour only on the icon. */
|
|
205
|
-
export declare function statusDetailsHtml(status: TaskStatus):
|
|
206
|
+
export declare function statusDetailsHtml(status: TaskStatus): Html;
|
|
206
207
|
/** The status card's fold of exact reasons: "More", never a third thing called Details. */
|
|
207
208
|
export declare const STATUS_MORE = "More";
|
|
208
209
|
/** The technical reasons, one tap away. */
|
|
@@ -210,7 +211,7 @@ export declare function statusWhyHtml(status: TaskStatus, extra?: readonly strin
|
|
|
210
211
|
token: string;
|
|
211
212
|
label: string;
|
|
212
213
|
detail: string;
|
|
213
|
-
}[]):
|
|
214
|
+
}[]): Html;
|
|
214
215
|
/** Shared CSS for the server-rendered status: neutral rows, coloured icons. */
|
|
215
216
|
export declare const TASK_STATUS_CSS = ".status-headline{display:flex;align-items:center;gap:.6rem;margin:0;font-size:1.125rem;font-weight:600;color:var(--foreground)}.status-headline i{width:.625rem;height:.625rem;border-radius:999px;flex-shrink:0;background:var(--muted-foreground)}[data-headline-tone=live] .status-headline i{background:var(--so-info,#0d74ce)}[data-headline-tone=attention] .status-headline i{background:var(--so-attention,var(--attention))}[data-headline-tone=ready] .status-headline i{background:transparent;box-shadow:inset 0 0 0 2px var(--so-success,#218358)}[data-headline-tone=success] .status-headline i{background:var(--so-success,#218358)}[data-headline-tone=danger] .status-headline i{background:var(--so-danger,#c4320a)}.status-sentence{margin:.35rem 0 0;color:var(--muted-foreground)}.status-details{list-style:none;margin:.75rem 0 0;padding:.25rem 0 0;border-top:1px solid var(--so-line,var(--border))}.status-detail{display:grid;grid-template-columns:14px 7.5rem minmax(0,1fr);align-items:center;gap:.6rem;padding:.4rem 0;font-size:.8125rem;color:var(--foreground)}.status-detail .status-icon{align-self:center;color:var(--muted-foreground)}.status-detail--ok .status-icon{color:var(--so-success,#218358)}.status-detail--running .status-icon{color:var(--so-info,#0d74ce)}.status-detail--note .status-icon{color:var(--so-warning,#ab6400)}.status-detail--failed .status-icon{color:var(--so-danger,#c4320a)}.status-detail-label{color:var(--muted-foreground)}.status-detail-text{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 .6rem;min-width:0;overflow-wrap:anywhere}.status-detail-text a{color:inherit}.status-detail-act{font-weight:600;white-space:nowrap}.status-detail--note .status-detail-act{color:var(--so-warning,#ab6400)}@media(max-width:480px){.status-detail{grid-template-columns:14px 6.5rem minmax(0,1fr);min-height:2.75rem;padding:.25rem 0}.status-detail-text a{display:inline-block;padding:.75rem 0;margin:-.75rem 0}}.status-why{border:0;padding:0;margin:.25rem 0 0;background:transparent;box-shadow:none}.status-why>summary{cursor:pointer;min-height:2.75rem;display:list-item;align-content:center;font-size:.8125rem;color:var(--muted-foreground)}.status-why p{margin:.25rem 0 .5rem}.receipt-note{display:flex;align-items:center;gap:.45rem;font-size:.8125rem;color:var(--foreground)}.receipt-note .status-icon{color:var(--so-warning,#ab6400)}";
|
|
216
217
|
/** A dispatch diagnosis as its stage, for the phone and CLI reads that hold
|
package/dist/task-status.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* output) is an amber note on its own row with one action; the exact
|
|
12
12
|
* technical reason stays one tap away in `why`. */
|
|
13
13
|
import { DEFAULT_LEAD_NAME } from "./lead-identity.js";
|
|
14
|
+
import { html } from "./html.js";
|
|
14
15
|
import { CODE_NEED, NEEDS, needSentence, waitSentence } from "./needs-you.js";
|
|
15
16
|
/** A cancelled task with a successor reads "Replaced by <id>" everywhere, never "Cancelled". */
|
|
16
17
|
export const replacedWords = (successor) => `Replaced by ${successor}`;
|
|
@@ -398,24 +399,23 @@ export function statusDetailLines(status) {
|
|
|
398
399
|
export function headlineEmoji(headline) {
|
|
399
400
|
return { Queued: "🕓", Planning: "📝", "Needs you": "👋", Waiting: "⏸", Building: "⏳", "Ready for review": "✅", Complete: "✅", Failed: "❌", Stopped: "⏹" }[headline];
|
|
400
401
|
}
|
|
401
|
-
const escapeHtml = (value) => value.replace(/[&<>"']/g, char => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[char]);
|
|
402
402
|
const ICON_PATHS = {
|
|
403
|
-
ok: `<path d="M20 6 9 17l-5-5"/>`,
|
|
404
|
-
running: `<circle cx="12" cy="12" r="4"/>`,
|
|
405
|
-
none: `<circle cx="12" cy="12" r="3"/>`,
|
|
406
|
-
note: `<path d="M12 8v5"/><path d="M12 16.5h.01"/><path d="M10.3 3.9 2.4 18a2 2 0 0 0 1.7 3h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/>`,
|
|
407
|
-
failed: `<path d="M18 6 6 18M6 6l12 12"/>`,
|
|
403
|
+
ok: html `<path d="M20 6 9 17l-5-5"/>`,
|
|
404
|
+
running: html `<circle cx="12" cy="12" r="4"/>`,
|
|
405
|
+
none: html `<circle cx="12" cy="12" r="3"/>`,
|
|
406
|
+
note: html `<path d="M12 8v5"/><path d="M12 16.5h.01"/><path d="M10.3 3.9 2.4 18a2 2 0 0 0 1.7 3h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/>`,
|
|
407
|
+
failed: html `<path d="M18 6 6 18M6 6l12 12"/>`,
|
|
408
408
|
};
|
|
409
|
-
export const statusIconSvg = (mark) => `<svg class="status-icon status-icon--${mark}" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${ICON_PATHS[mark]}</svg>`;
|
|
409
|
+
export const statusIconSvg = (mark) => html `<svg class="status-icon status-icon--${mark}" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${ICON_PATHS[mark]}</svg>`;
|
|
410
410
|
/** The detail rows as server HTML: quiet rows, colour only on the icon. */
|
|
411
411
|
export function statusDetailsHtml(status) {
|
|
412
412
|
if (status.details.length === 0)
|
|
413
|
-
return
|
|
414
|
-
return `<ul class="status-details" aria-label="Status"
|
|
415
|
-
const text = one.href === null ?
|
|
416
|
-
const action = one.action === null ? "" : one.action.href === null ? `<span class="status-detail-act">${
|
|
417
|
-
return `<li class="status-detail status-detail--${one.mark}" data-status-detail="${one.key}" data-mark="${one.mark}">${statusIconSvg(one.mark)}<span class="status-detail-label">${
|
|
418
|
-
})
|
|
413
|
+
return html ``;
|
|
414
|
+
return html `<ul class="status-details" aria-label="Status">${status.details.map(one => {
|
|
415
|
+
const text = one.href === null ? one.text : html `<a href="${one.href}">${one.text}</a>`;
|
|
416
|
+
const action = one.action === null ? "" : one.action.href === null ? html `<span class="status-detail-act">${one.action.label}</span>` : html `<a class="status-detail-act" href="${one.action.href}">${one.action.label}</a>`;
|
|
417
|
+
return html `<li class="status-detail status-detail--${one.mark}" data-status-detail="${one.key}" data-mark="${one.mark}">${statusIconSvg(one.mark)}<span class="status-detail-label">${one.label}</span><span class="status-detail-text"><span>${text}</span>${action}</span></li>`;
|
|
418
|
+
})}</ul>`;
|
|
419
419
|
}
|
|
420
420
|
/** The status card's fold of exact reasons: "More", never a third thing called Details. */
|
|
421
421
|
export const STATUS_MORE = "More";
|
|
@@ -423,9 +423,8 @@ export const STATUS_MORE = "More";
|
|
|
423
423
|
export function statusWhyHtml(status, extra = [], diagnostics = []) {
|
|
424
424
|
const lines = [...new Set([...status.details.flatMap(one => one.why === null ? [] : [`${one.label}: ${one.why}`]), ...status.why, ...extra])];
|
|
425
425
|
if (lines.length === 0 && diagnostics.length === 0)
|
|
426
|
-
return
|
|
427
|
-
return `<details class="status-why"><summary>${STATUS_MORE}</summary>${lines.map(one => `<p class="meta">${
|
|
428
|
-
diagnostics.map(one => `<p class="meta" data-work-diagnostic="${escapeHtml(one.token)}">${escapeHtml(one.label)} · ${escapeHtml(one.detail)}</p>`).join("") + `</details>`;
|
|
426
|
+
return html ``;
|
|
427
|
+
return html `<details class="status-why"><summary>${STATUS_MORE}</summary>${lines.map(one => html `<p class="meta">${one}</p>`)}${diagnostics.map(one => html `<p class="meta" data-work-diagnostic="${one.token}">${one.label} · ${one.detail}</p>`)}</details>`;
|
|
429
428
|
}
|
|
430
429
|
/** Shared CSS for the server-rendered status: neutral rows, coloured icons. */
|
|
431
430
|
export const TASK_STATUS_CSS = `.status-headline{display:flex;align-items:center;gap:.6rem;margin:0;font-size:1.125rem;font-weight:600;color:var(--foreground)}.status-headline i{width:.625rem;height:.625rem;border-radius:999px;flex-shrink:0;background:var(--muted-foreground)}[data-headline-tone=live] .status-headline i{background:var(--so-info,#0d74ce)}[data-headline-tone=attention] .status-headline i{background:var(--so-attention,var(--attention))}[data-headline-tone=ready] .status-headline i{background:transparent;box-shadow:inset 0 0 0 2px var(--so-success,#218358)}[data-headline-tone=success] .status-headline i{background:var(--so-success,#218358)}[data-headline-tone=danger] .status-headline i{background:var(--so-danger,#c4320a)}.status-sentence{margin:.35rem 0 0;color:var(--muted-foreground)}.status-details{list-style:none;margin:.75rem 0 0;padding:.25rem 0 0;border-top:1px solid var(--so-line,var(--border))}.status-detail{display:grid;grid-template-columns:14px 7.5rem minmax(0,1fr);align-items:center;gap:.6rem;padding:.4rem 0;font-size:.8125rem;color:var(--foreground)}.status-detail .status-icon{align-self:center;color:var(--muted-foreground)}.status-detail--ok .status-icon{color:var(--so-success,#218358)}.status-detail--running .status-icon{color:var(--so-info,#0d74ce)}.status-detail--note .status-icon{color:var(--so-warning,#ab6400)}.status-detail--failed .status-icon{color:var(--so-danger,#c4320a)}.status-detail-label{color:var(--muted-foreground)}.status-detail-text{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 .6rem;min-width:0;overflow-wrap:anywhere}.status-detail-text a{color:inherit}.status-detail-act{font-weight:600;white-space:nowrap}.status-detail--note .status-detail-act{color:var(--so-warning,#ab6400)}@media(max-width:480px){.status-detail{grid-template-columns:14px 6.5rem minmax(0,1fr);min-height:2.75rem;padding:.25rem 0}.status-detail-text a{display:inline-block;padding:.75rem 0;margin:-.75rem 0}}.status-why{border:0;padding:0;margin:.25rem 0 0;background:transparent;box-shadow:none}.status-why>summary{cursor:pointer;min-height:2.75rem;display:list-item;align-content:center;font-size:.8125rem;color:var(--muted-foreground)}.status-why p{margin:.25rem 0 .5rem}.receipt-note{display:flex;align-items:center;gap:.45rem;font-size:.8125rem;color:var(--foreground)}.receipt-note .status-icon{color:var(--so-warning,#ab6400)}`;
|
package/dist/team-cli.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export type TeamCliOptions = {
|
|
|
10
10
|
signal?: AbortSignal;
|
|
11
11
|
sleep?: (milliseconds: number, signal: AbortSignal) => Promise<void>;
|
|
12
12
|
};
|
|
13
|
+
/** D5: deprecated (deprecations.ts). Each still runs this release, hidden from help and the contract, with one warning on stderr. */
|
|
13
14
|
export declare const TEAM_CLI_ACTIONS: readonly ['connect', 'lead list', 'lead create', 'lead update', 'lead member', 'lead transfer', 'conversation list', 'conversation create', 'conversation show', 'conversation member', 'conversation edit', 'conversation withdraw', 'conversation read', 'conversation follow', 'conversation stop'];
|
|
14
15
|
export declare class UsageError extends Error {
|
|
15
16
|
}
|
package/dist/team-cli.js
CHANGED
|
@@ -9,6 +9,10 @@ import { sessionServiceOrigin } from './session-cli.js';
|
|
|
9
9
|
import { databasePath } from './store.js';
|
|
10
10
|
import { configBase, namedPath } from './names.js';
|
|
11
11
|
import { parseApiToken } from './api-tokens.js';
|
|
12
|
+
import { deprecationWarning } from './deprecations.js';
|
|
13
|
+
/** The central service's own lead verbs; every other `lead …` (token, say, or none) is the local lead's. */
|
|
14
|
+
const CENTRAL_LEAD_ACTIONS = ['list', 'create', 'update', 'member', 'transfer'];
|
|
15
|
+
/** D5: deprecated (deprecations.ts). Each still runs this release, hidden from help and the contract, with one warning on stderr. */
|
|
12
16
|
export const TEAM_CLI_ACTIONS = ['connect', 'lead list', 'lead create', 'lead update', 'lead member', 'lead transfer', 'conversation list', 'conversation create', 'conversation show', 'conversation member', 'conversation edit', 'conversation withdraw', 'conversation read', 'conversation follow', 'conversation stop'];
|
|
13
17
|
const HELP = `toolroll connect <HTTPS-origin> --as <account> --token-stdin
|
|
14
18
|
Pipe your API token (so_…, from Settings → API tokens) or use --token-file <private-file>;
|
|
@@ -335,8 +339,9 @@ function render(reply, listing) {
|
|
|
335
339
|
/** null means preserve the existing local command path. Nothing here opens a database. */
|
|
336
340
|
export async function maybeRunTeamCommand(argv, write, options = {}) {
|
|
337
341
|
const command = argv[0];
|
|
338
|
-
// `lead token`
|
|
339
|
-
|
|
342
|
+
// `lead token` and `lead say` are local: the credential a lead agent acts with on this computer, and its voice. A bare
|
|
343
|
+
// `lead` is the local lead's too ("lead" means only the lead); only the central service's verbs go on from here.
|
|
344
|
+
if (command === 'lead' && (argv[1] === 'token' || argv[1] === 'say' || !argv.some(arg => arg === '--profile' || CENTRAL_LEAD_ACTIONS.includes(arg))))
|
|
340
345
|
return null;
|
|
341
346
|
if (!['connect', 'lead', 'conversation', 'chat', 'brief'].includes(command ?? '') && !argv.includes('--profile'))
|
|
342
347
|
return null;
|
|
@@ -357,6 +362,11 @@ export async function maybeRunTeamCommand(argv, write, options = {}) {
|
|
|
357
362
|
return null;
|
|
358
363
|
}
|
|
359
364
|
const explicit = ['connect', 'lead', 'conversation'].includes(command) || argv.some(arg => ['--profile', '--lead', '--conversation', '--authorize', '--terms-digest', '--request-id'].includes(arg));
|
|
365
|
+
// D5: the central team service is deprecated. It still runs this release; each use says so once, on stderr.
|
|
366
|
+
const verb = command === 'lead' || command === 'conversation' ? `${command} ${argv.slice(1).find(arg => !arg.startsWith('--')) ?? ''}`.trim() : command === 'connect' ? command : `${command} --conversation`;
|
|
367
|
+
const warn = () => stderr(deprecationWarning(verb, 'team'));
|
|
368
|
+
if (explicit)
|
|
369
|
+
warn();
|
|
360
370
|
if (explicit && (argv.includes('--help') || ['lead', 'conversation'].includes(command) && argv.length === 1)) {
|
|
361
371
|
write(HELP);
|
|
362
372
|
return 0;
|
|
@@ -364,6 +374,8 @@ export async function maybeRunTeamCommand(argv, write, options = {}) {
|
|
|
364
374
|
const saved = profiles(options);
|
|
365
375
|
if (!explicit && !saved)
|
|
366
376
|
return null;
|
|
377
|
+
if (!explicit)
|
|
378
|
+
warn();
|
|
367
379
|
const parsed = parse(argv), { flags, action } = parsed;
|
|
368
380
|
if (flags.help || ((command === 'lead' || command === 'conversation') && !action)) {
|
|
369
381
|
write(HELP);
|
package/dist/team-http.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
|
2
2
|
import { type TeamActor, type TeamExecute } from './team-contract.js';
|
|
3
3
|
import { type Admission } from './request-budget.js';
|
|
4
4
|
export declare const TEAM_REQUEST_BYTES: number;
|
|
5
|
-
/** How long a password bearer's proof stands on a long
|
|
6
|
-
* The account, its revocation and its credential generation are still rechecked on every
|
|
5
|
+
/** How long a password bearer's proof stands on a long live team stream (GET /live?room=team) before its password is
|
|
6
|
+
* checked again. The account, its revocation and its credential generation are still rechecked on every signal. */
|
|
7
7
|
export declare const TEAM_PASSWORD_REVERIFY_MS: number;
|
|
8
8
|
/** Account role belongs to HTTP authentication; API tokens carry their own scope. */
|
|
9
9
|
export type TeamHttpActor = TeamActor & {
|
|
@@ -15,15 +15,11 @@ export type TeamHttpOptions = {
|
|
|
15
15
|
revalidate: (request: IncomingMessage, actor: TeamActor) => boolean;
|
|
16
16
|
authorizeMutation: (request: IncomingMessage, actor: TeamActor) => boolean;
|
|
17
17
|
execute: TeamExecute;
|
|
18
|
-
/**
|
|
19
|
-
cursor?: (actor: TeamActor, conversationId?: string) => number | null;
|
|
20
|
-
/** Source admission before credential verification. Streams are charged once when opened. */
|
|
18
|
+
/** Source admission before credential verification. */
|
|
21
19
|
admit?: (request: IncomingMessage) => Admission;
|
|
22
20
|
/** Proved account/token admission, before reading the body or executing any operation. */
|
|
23
21
|
admitAuthenticated?: (request: IncomingMessage, actor: TeamActor) => Admission;
|
|
24
|
-
streamIntervalMs?: number;
|
|
25
|
-
streams?: Set<ServerResponse>;
|
|
26
22
|
};
|
|
27
|
-
/** Authenticated browser and remote CLI share one operation boundary.
|
|
28
|
-
*
|
|
23
|
+
/** Authenticated browser and remote CLI share one operation boundary. Live
|
|
24
|
+
* updates come from GET /live?room=team (server/live.ts). */
|
|
29
25
|
export declare function handleTeamHttp(request: IncomingMessage, response: ServerResponse, options: TeamHttpOptions): Promise<boolean>;
|
package/dist/team-http.js
CHANGED
|
@@ -2,8 +2,8 @@ import { adapterPolicy } from "./server/route-policy.js";
|
|
|
2
2
|
import { TEAM_OPERATIONS, TEAM_MUTATIONS, teamScopeAllows } from './team-contract.js';
|
|
3
3
|
import { limitWords } from './request-budget.js';
|
|
4
4
|
export const TEAM_REQUEST_BYTES = 64 * 1024;
|
|
5
|
-
/** How long a password bearer's proof stands on a long
|
|
6
|
-
* The account, its revocation and its credential generation are still rechecked on every
|
|
5
|
+
/** How long a password bearer's proof stands on a long live team stream (GET /live?room=team) before its password is
|
|
6
|
+
* checked again. The account, its revocation and its credential generation are still rechecked on every signal. */
|
|
7
7
|
export const TEAM_PASSWORD_REVERIFY_MS = 5 * 60_000;
|
|
8
8
|
const failure = (code, message) => ({ version: 1, ok: false, code, message });
|
|
9
9
|
function send(response, status, value, headers = {}) {
|
|
@@ -33,11 +33,11 @@ function valid(value) {
|
|
|
33
33
|
!!row.args && typeof row.args === 'object' && !Array.isArray(row.args) &&
|
|
34
34
|
!['actor', 'generation', 'authenticatedActor'].some(key => key in row.args);
|
|
35
35
|
}
|
|
36
|
-
/** Authenticated browser and remote CLI share one operation boundary.
|
|
37
|
-
*
|
|
36
|
+
/** Authenticated browser and remote CLI share one operation boundary. Live
|
|
37
|
+
* updates come from GET /live?room=team (server/live.ts). */
|
|
38
38
|
export async function handleTeamHttp(request, response, options) {
|
|
39
39
|
const url = new URL(request.url ?? '/', 'http://standing-orders.local');
|
|
40
|
-
if (url.pathname !== '/api/team'
|
|
40
|
+
if (url.pathname !== '/api/team')
|
|
41
41
|
return false;
|
|
42
42
|
const reject = (status, code, message) => { send(response, status, failure(code, message)); request.resume(); return true; };
|
|
43
43
|
if ([...url.searchParams.keys()].some(key => /token|password|credential|authorization/i.test(key)))
|
|
@@ -71,64 +71,6 @@ export async function handleTeamHttp(request, response, options) {
|
|
|
71
71
|
if (!adapterPolicy(policyPrincipal()).ok)
|
|
72
72
|
return reject(403, 'read-only', 'Your token reads only. Use an act token for this.');
|
|
73
73
|
const conversationId = url.searchParams.get('conversation') ?? undefined;
|
|
74
|
-
if (url.pathname === '/api/team/events') {
|
|
75
|
-
if (request.method !== 'GET')
|
|
76
|
-
return reject(405, 'method-not-allowed', 'Use GET for conversation updates.');
|
|
77
|
-
let initial;
|
|
78
|
-
try {
|
|
79
|
-
initial = await options.execute(actor, { operation: conversationId ? 'show' : 'list', args: conversationId ? { conversationId } : {} });
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
return reject(503, 'unavailable', 'Conversation updates are unavailable.');
|
|
83
|
-
}
|
|
84
|
-
if (!initial.ok || !initial.snapshot) {
|
|
85
|
-
send(response, 403, initial);
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
response.writeHead(200, { 'content-type': 'text/event-stream', 'cache-control': 'no-store', 'x-content-type-options': 'nosniff', 'x-accel-buffering': 'no' });
|
|
89
|
-
options.streams?.add(response);
|
|
90
|
-
let cursor = initial.snapshot.cursor;
|
|
91
|
-
response.write(`id: ${cursor}\nevent: change\ndata: {"cursor":${cursor}}\n\n`);
|
|
92
|
-
let active = false;
|
|
93
|
-
const close = () => { clearInterval(timer); options.streams?.delete(response); response.end(); };
|
|
94
|
-
const revoked = () => { response.write('event: revoked\ndata: {}\n\n'); close(); };
|
|
95
|
-
const tick = async () => {
|
|
96
|
-
if (active || response.destroyed || response.writableEnded)
|
|
97
|
-
return;
|
|
98
|
-
active = true;
|
|
99
|
-
try {
|
|
100
|
-
if (!options.revalidate(request, actor))
|
|
101
|
-
return revoked();
|
|
102
|
-
let next;
|
|
103
|
-
if (options.cursor)
|
|
104
|
-
next = options.cursor(actor, conversationId);
|
|
105
|
-
else {
|
|
106
|
-
const reply = await options.execute(actor, { operation: conversationId ? 'show' : 'list', args: conversationId ? { conversationId } : {} });
|
|
107
|
-
next = reply.ok ? reply.snapshot?.cursor ?? null : null;
|
|
108
|
-
}
|
|
109
|
-
if (next === null)
|
|
110
|
-
return revoked();
|
|
111
|
-
if (next !== cursor) {
|
|
112
|
-
cursor = next;
|
|
113
|
-
// A slow client receives a fresh scoped snapshot on reconnect, never an unbounded replay buffer.
|
|
114
|
-
if (!response.write(`id: ${cursor}\nevent: change\ndata: {"cursor":${cursor}}\n\n`))
|
|
115
|
-
close();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
response.write('event: unavailable\ndata: {}\n\n');
|
|
120
|
-
close();
|
|
121
|
-
}
|
|
122
|
-
finally {
|
|
123
|
-
active = false;
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
const timer = setInterval(() => { void tick(); }, options.streamIntervalMs ?? 1_000);
|
|
127
|
-
timer.unref();
|
|
128
|
-
request.once('close', close);
|
|
129
|
-
response.once('close', close);
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
74
|
let input;
|
|
133
75
|
if (request.method === 'GET')
|
|
134
76
|
input = { operation: conversationId ? 'show' : 'list', args: conversationId ? { conversationId } : {} };
|
package/dist/team-leads.js
CHANGED
|
@@ -185,7 +185,7 @@ export class TeamLeads {
|
|
|
185
185
|
}
|
|
186
186
|
const selected = conversationId ? this.access(actor, conversationId).conversation : conversations[0] ?? null;
|
|
187
187
|
const access = selected ? this.access(actor, selected.id) : null;
|
|
188
|
-
const messages = selected ? this.db.prepare(`SELECT * FROM (SELECT m.*,q.author,q.request_id,q.status,q.revision AS message_revision,q.error FROM
|
|
188
|
+
const messages = selected ? this.db.prepare(`SELECT * FROM (SELECT m.*,q.author,q.request_id,q.status,q.revision AS message_revision,q.error FROM lead_message m LEFT JOIN team_message q ON q.message=m.id WHERE m.thread=? ORDER BY m.id DESC LIMIT 201) ORDER BY id`).all(selected.threadId).map(r => ({ id: Number(r['id']), author: r['role'] === 'assistant' ? access.lead.name : String(r['author'] ?? selected.createdBy), role: String(r['role']), text: String(r['text']), status: (r['status'] ?? 'answered'), revision: Number(r['message_revision'] ?? 1), createdAt: String(r['created_at']), requestId: r['request_id'] == null ? null : String(r['request_id']), turnId: r['turn'] == null ? null : Number(r['turn']), error: r['error'] == null ? null : String(r['error']) })) : [];
|
|
189
189
|
const participants = selected ? this.db.prepare('SELECT account,role,active FROM team_participant WHERE conversation=? ORDER BY account').all(selected.id).map(r => ({ account: String(r['account']), role: String(r['role']), active: Number(r['active']) === 1 })) : [];
|
|
190
190
|
const canManage = account.role === 'approver' && (access ? access.role === 'manager' : leadId ? this.leadAccess(actor, leadId).role === 'manager' : false);
|
|
191
191
|
return { leads, conversations, selected, participants, messages: messages.slice(-200), canManage, canCreateLead: account.role === 'approver' && this.enrolled().some(p => projectAccessAllows(account.projects, p)), canSend: account.role === 'approver' && access !== null && rank(access.role) >= 1 && access.lead.status === 'active', cursor: this.cursor(actor, selected?.id) ?? 0, truncated: messages.length > 200, projects: this.enrolled().filter(p => projectAccessAllows(account.projects, p)), accounts: canManage ? this.store.accountFacts().filter(a => a.revokedAt === null && (selected?.projects ?? []).every(p => projectAccessAllows(a.projects, p))).map(a => a.name) : [] };
|
|
@@ -345,14 +345,14 @@ export class TeamLeads {
|
|
|
345
345
|
return ok('Message already saved.', { messageId: Number(seen['message']), status: String(seen['status']) });
|
|
346
346
|
}
|
|
347
347
|
const revisions = this.memberRevisions(conversationId, actor.name);
|
|
348
|
-
const messageId = this.store.
|
|
348
|
+
const messageId = this.store.appendLeadMessage({ thread: conversation.threadId, turn: null, role: 'operator', text }, now);
|
|
349
349
|
this.db.prepare("INSERT INTO team_message(message,conversation,author,author_generation,lead_member_revision,participant_revision,request_id,payload_hash,status) VALUES(?,?,?,?,?,?,?,?,'queued')").run(messageId, conversationId, actor.name, actor.generation, revisions.lead, revisions.participant, requestId, digest);
|
|
350
350
|
this.event(lead.id, conversationId, 'message-queued', actor.name, now);
|
|
351
351
|
return ok('Message saved.', { messageId, status: 'queued' });
|
|
352
352
|
}
|
|
353
353
|
if (request.operation === 'read') {
|
|
354
354
|
const id = integer(a['messageId'], 'Message');
|
|
355
|
-
if (id > 0 && !this.db.prepare('SELECT 1 FROM
|
|
355
|
+
if (id > 0 && !this.db.prepare('SELECT 1 FROM lead_message WHERE id=? AND thread=?').get(id, conversation.threadId))
|
|
356
356
|
refuse('not-found', 'Message not available.');
|
|
357
357
|
this.db.prepare('INSERT INTO team_read(conversation,account,message) VALUES(?,?,?) ON CONFLICT(conversation,account) DO UPDATE SET message=MAX(team_read.message,excluded.message)').run(conversationId, actor.name, id);
|
|
358
358
|
return ok('Read position saved.');
|
|
@@ -374,9 +374,9 @@ export class TeamLeads {
|
|
|
374
374
|
if (message['status'] === 'running') {
|
|
375
375
|
this.db.prepare('UPDATE team_message SET stop_requested=1 WHERE message=?').run(id);
|
|
376
376
|
if (message['turn_id'] !== null) {
|
|
377
|
-
const turn = this.store.
|
|
377
|
+
const turn = this.store.getLeadTurn(Number(message['turn_id']));
|
|
378
378
|
if (turn)
|
|
379
|
-
this.store.
|
|
379
|
+
this.store.finalizeLeadTurn(turn.id, turn.generation, { state: 'failed', settledMicrousd: turn.reservedMicrousd, unknownSpend: true, tokensIn: 0, tokensOut: 0, failureReason: 'stopped' }, now);
|
|
380
380
|
}
|
|
381
381
|
}
|
|
382
382
|
else if (message['status'] === 'queued' || message['status'] === 'uncertain')
|
|
@@ -393,7 +393,7 @@ export class TeamLeads {
|
|
|
393
393
|
refuse('conflict', 'This message changed or has started. Send a follow-up instead.');
|
|
394
394
|
if (request.operation === 'edit') {
|
|
395
395
|
const text = messageText(a['text']);
|
|
396
|
-
this.db.prepare('UPDATE
|
|
396
|
+
this.db.prepare('UPDATE lead_message SET text=? WHERE id=?').run(text, id);
|
|
397
397
|
this.db.prepare('UPDATE team_message SET revision=revision+1 WHERE message=?').run(id);
|
|
398
398
|
}
|
|
399
399
|
else
|
|
@@ -404,9 +404,9 @@ export class TeamLeads {
|
|
|
404
404
|
refuse('unsupported', 'This action is not available here.');
|
|
405
405
|
}
|
|
406
406
|
revokeMemberSessions(leadId, conversationId, account, now) {
|
|
407
|
-
this.db.prepare(`UPDATE
|
|
407
|
+
this.db.prepare(`UPDATE lead_session SET ended_at=?,ended_by='membership-changed' WHERE approver=? AND ended_at IS NULL
|
|
408
408
|
AND EXISTS(SELECT 1 FROM team_mate_session ms JOIN team_conversation c ON c.thread=ms.thread
|
|
409
|
-
WHERE ms.session=
|
|
409
|
+
WHERE ms.session=lead_session.id AND c.lead=? AND (? IS NULL OR c.id=?))`).run(now.toISOString(), account, leadId, conversationId, conversationId);
|
|
410
410
|
}
|
|
411
411
|
memberRevisions(conversationId, account) {
|
|
412
412
|
const row = this.db.prepare(`SELECT lm.revision AS lr,p.revision AS pr FROM team_conversation c JOIN team_lead_member lm ON lm.lead=c.lead AND lm.account=? AND lm.active=1 JOIN team_participant p ON p.conversation=c.id AND p.account=lm.account AND p.active=1 WHERE c.id=?`).get(account, conversationId);
|
|
@@ -427,7 +427,7 @@ export class TeamLeads {
|
|
|
427
427
|
claimNext(runner, now = new Date(), eligible) {
|
|
428
428
|
str(runner, 'Runner', 180);
|
|
429
429
|
return this.store.transact(() => {
|
|
430
|
-
const candidates = this.db.prepare(`SELECT q.*,m.text,c.lead,c.thread FROM team_message q JOIN
|
|
430
|
+
const candidates = this.db.prepare(`SELECT q.*,m.text,c.lead,c.thread FROM team_message q JOIN lead_message m ON m.id=q.message JOIN team_conversation c ON c.id=q.conversation JOIN team_lead l ON l.id=c.lead AND l.status='active'
|
|
431
431
|
WHERE q.status='queued' AND NOT EXISTS(SELECT 1 FROM team_message live WHERE live.conversation=q.conversation AND live.status IN ('running','uncertain'))
|
|
432
432
|
AND NOT EXISTS(SELECT 1 FROM team_message earlier WHERE earlier.conversation=q.conversation AND earlier.status='queued' AND earlier.message<q.message)
|
|
433
433
|
AND (SELECT COUNT(*) FROM team_message running JOIN team_conversation other ON other.id=running.conversation WHERE running.status='running' AND other.lead=c.lead)<2
|
|
@@ -453,7 +453,7 @@ export class TeamLeads {
|
|
|
453
453
|
current(claim) { const row = this.claimed(claim); return row !== undefined && Number(row['stop_requested']) === 0 && this.authorStillAllowed(row); }
|
|
454
454
|
bindTurn(claim, turnId) {
|
|
455
455
|
return this.store.transact(() => { if (!this.current(claim))
|
|
456
|
-
return false; const turn = this.store.
|
|
456
|
+
return false; const turn = this.store.getLeadTurn(turnId); if (!turn || turn.thread !== claim.threadId || turn.approver !== claim.actor.name)
|
|
457
457
|
return false; const changed = this.db.prepare('UPDATE team_message SET turn_id=? WHERE message=? AND turn_id IS NULL').run(turnId, claim.messageId); return Number(changed.changes) === 1; });
|
|
458
458
|
}
|
|
459
459
|
finish(claim, result, now = new Date()) {
|
|
@@ -467,7 +467,7 @@ export class TeamLeads {
|
|
|
467
467
|
return false;
|
|
468
468
|
this.db.prepare('UPDATE team_message SET status=?,error=?,turn_id=COALESCE(turn_id,?),revision=revision+1 WHERE message=?').run(status, result.error ?? (!allowed ? 'Access changed while this message was running.' : stopped ? 'Stopped.' : null), result.turnId ?? null, claim.messageId);
|
|
469
469
|
if (allowed && !stopped && result.text)
|
|
470
|
-
this.store.
|
|
470
|
+
this.store.appendLeadMessage({ thread: claim.threadId, turn: result.turnId ?? (row['turn_id'] === null ? null : Number(row['turn_id'])), role: 'assistant', text: result.text }, now);
|
|
471
471
|
this.event(claim.leadId, claim.conversationId, 'message-finished', claim.actor.name, now);
|
|
472
472
|
return true;
|
|
473
473
|
});
|
|
@@ -478,7 +478,7 @@ export class TeamLeads {
|
|
|
478
478
|
const row = this.claimed(claim);
|
|
479
479
|
if (!row || row['turn_id'] !== null || !this.current(claim))
|
|
480
480
|
return false;
|
|
481
|
-
if (this.db.prepare('SELECT turn FROM
|
|
481
|
+
if (this.db.prepare('SELECT turn FROM lead_message WHERE id=?').get(claim.messageId)?.['turn'] !== null)
|
|
482
482
|
return false;
|
|
483
483
|
const changed = this.db.prepare("UPDATE team_message SET status='queued',generation=generation+1,revision=revision+1,runner=NULL,claimed_at=NULL,error=? WHERE message=? AND status='running' AND turn_id IS NULL AND generation=?").run(error, claim.messageId, claim.generation);
|
|
484
484
|
if (Number(changed.changes) !== 1)
|
|
@@ -520,7 +520,7 @@ export class TeamLeads {
|
|
|
520
520
|
return this.store.transact(() => {
|
|
521
521
|
const rows = this.db.prepare("SELECT q.*,c.lead FROM team_message q JOIN team_conversation c ON c.id=q.conversation WHERE runner=? AND status='running'").all(runner);
|
|
522
522
|
for (const row of rows) {
|
|
523
|
-
const turn = row['turn_id'] === null ? null : this.store.
|
|
523
|
+
const turn = row['turn_id'] === null ? null : this.store.getLeadTurn(Number(row['turn_id']));
|
|
524
524
|
const status = turn?.state === 'answered' ? 'answered' : turn?.state === 'failed' && !this.deliveryUncertain(turn.id) ? 'failed' : 'uncertain';
|
|
525
525
|
const error = status === 'uncertain' ? 'Delivery unconfirmed after the previous worker stopped. Inspect activity before continuing.' : status === 'failed' ? savedFailure(turn?.failureReason) : null;
|
|
526
526
|
this.db.prepare('UPDATE team_message SET status=?,generation=generation+1,revision=revision+1,error=? WHERE message=?').run(status, error, Number(row['message']));
|
package/dist/team-runtime.d.ts
CHANGED
|
@@ -2,14 +2,14 @@ import type { Store } from './store.js';
|
|
|
2
2
|
import type { WorkspaceRevision } from './workspace-revision.js';
|
|
3
3
|
import { TeamLeads } from './team-leads.js';
|
|
4
4
|
import { type TeamActor, type TeamExecute } from './team-contract.js';
|
|
5
|
-
import { type
|
|
5
|
+
import { type LeadTurnInput } from './lead.js';
|
|
6
6
|
import { type TeamChatProviderResolver } from './team-chat-authorization.js';
|
|
7
7
|
export type TeamRuntimeOptions = {
|
|
8
8
|
store: Store;
|
|
9
9
|
repos: () => readonly string[];
|
|
10
10
|
evidenceRoot: string;
|
|
11
11
|
provider: TeamChatProviderResolver;
|
|
12
|
-
subscriptionRunner?:
|
|
12
|
+
subscriptionRunner?: LeadTurnInput['subscriptionRunner'];
|
|
13
13
|
fetcher?: typeof fetch;
|
|
14
14
|
clock?: () => Date;
|
|
15
15
|
capacity?: number;
|