toolroll 0.9.55 → 0.9.57
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 +18 -0
- package/README.md +24 -8
- package/dist/action-ledger.d.ts +2 -4
- package/dist/action-ledger.js +2 -10
- package/dist/approval-policy.d.ts +5 -5
- package/dist/approval-policy.js +4 -4
- package/dist/approval-rules-ui.js +2 -2
- package/dist/assignment-adapters.d.ts +5 -0
- package/dist/assignment.d.ts +24 -3
- package/dist/assignment.js +36 -10
- package/dist/browser/workspace.js +5 -5
- package/dist/browser-workspace.d.ts +12 -12
- package/dist/browser-workspace.js +1 -1
- 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 +30 -37
- 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-rooms.js +3 -3
- package/dist/chat-voice.js +1 -1
- package/dist/chat-warmth.d.ts +2 -2
- package/dist/check-levels.d.ts +3 -0
- package/dist/check-levels.js +5 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +6 -7
- 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/console-api.d.ts +6 -6
- package/dist/contracts/console-api.js +7 -7
- 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/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/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/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/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/dispose.js +0 -5
- package/dist/envelope.js +0 -1
- package/dist/export-ui.js +1 -1
- package/dist/export.js +7 -7
- package/dist/flow-engine.d.ts +2 -2
- package/dist/flow-engine.js +21 -21
- package/dist/flow-insights.d.ts +1 -1
- package/dist/flow-share.js +13 -8
- package/dist/flow-steps.d.ts +5 -5
- package/dist/flow-steps.js +19 -19
- package/dist/flow-triggers.d.ts +1 -1
- package/dist/flow-triggers.js +1 -1
- package/dist/flows-cli.js +1 -1
- package/dist/flows-ui.js +20 -20
- package/dist/flows.js +19 -19
- package/dist/guides.js +4 -3
- package/dist/invoke.js +1 -1
- package/dist/kits-ui.js +5 -5
- package/dist/kits.d.ts +12 -12
- package/dist/kits.js +31 -31
- 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 +2 -2
- package/dist/lead-context.js +9 -9
- 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/lead-status.d.ts +1 -1
- package/dist/lead-status.js +2 -2
- 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/limits-ui.d.ts +1 -1
- package/dist/limits-ui.js +1 -1
- package/dist/mcp-connect.d.ts +1 -1
- package/dist/mcp-connect.js +3 -3
- package/dist/mcp-core.js +1 -1
- package/dist/memory-pass.d.ts +2 -2
- package/dist/memory-pass.js +7 -7
- package/dist/notification-rows.d.ts +2 -2
- package/dist/operate.d.ts +3 -3
- package/dist/operate.js +52 -42
- 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.js +1 -1
- 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/proof.d.ts +9 -0
- package/dist/proof.js +12 -0
- package/dist/recipe-ui.js +1 -1
- package/dist/release-coverage.d.ts +16 -0
- package/dist/release-coverage.js +92 -0
- 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.js +40 -45
- package/dist/server/chat.d.ts +4 -4
- package/dist/server/chat.js +105 -103
- package/dist/server/chrome.js +3 -3
- package/dist/server/flows.js +69 -62
- package/dist/server/guards.js +3 -3
- package/dist/server/http.d.ts +3 -3
- package/dist/server/http.js +1 -1
- package/dist/server/live.js +6 -6
- package/dist/server/people-tokens.js +1 -1
- package/dist/server/remote.js +12 -10
- package/dist/server/render-chat.d.ts +30 -30
- package/dist/server/render-chat.js +33 -33
- package/dist/server/render-pages.js +2 -2
- package/dist/server/render-results.d.ts +4 -1
- package/dist/server/render-results.js +23 -9
- package/dist/server/render-settings.d.ts +7 -0
- package/dist/server/render-settings.js +3 -0
- package/dist/server/route-table.js +9 -7
- package/dist/server/runtime.d.ts +13 -13
- package/dist/server/settings.js +14 -13
- package/dist/server/tasks.js +34 -30
- package/dist/setup-guide.d.ts +2 -2
- package/dist/slack-chat.d.ts +2 -2
- package/dist/slack-chat.js +6 -6
- package/dist/spend-ui.d.ts +3 -3
- package/dist/spend-ui.js +9 -9
- package/dist/spend.d.ts +14 -14
- package/dist/spend.js +31 -31
- package/dist/store-baseline.d.ts +19 -0
- package/dist/store-baseline.js +2873 -0
- package/dist/store.d.ts +200 -254
- package/dist/store.js +830 -3152
- 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/{teammates-ui.js → subagents-ui.js} +45 -45
- 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 +7 -31
- package/dist/task-outcome-cli.js +3 -1
- package/dist/task-status.d.ts +59 -7
- package/dist/task-status.js +132 -16
- package/dist/team-cli.d.ts +1 -0
- package/dist/team-cli.js +14 -2
- package/dist/team-leads.js +13 -13
- package/dist/team-runtime.d.ts +2 -2
- package/dist/team-runtime.js +9 -9
- package/dist/teams-chat.js +6 -6
- 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-status.d.ts +11 -4
- package/dist/telegram-status.js +18 -11
- 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 +13 -34
- package/dist/text-limits.d.ts +18 -18
- package/dist/text-limits.js +18 -18
- package/dist/toolroll-update.d.ts +8 -0
- package/dist/toolroll-update.js +45 -8
- package/dist/work-index.d.ts +6 -1
- package/dist/work-index.js +50 -8
- package/dist/workspace-ui.js +2 -1
- package/package.json +1 -2
- package/dist/teammate-admin.d.ts +0 -53
- package/dist/teammates-ui.d.ts +0 -21
package/dist/limits-ui.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export declare function limitsView(windows: readonly {
|
|
|
20
20
|
observedAt: string;
|
|
21
21
|
}[], budgets: readonly BudgetState[], names: {
|
|
22
22
|
project: (repo: string) => string;
|
|
23
|
-
|
|
23
|
+
subagent: (id: number) => string;
|
|
24
24
|
}, now: Date): BrowserLimits | null;
|
|
25
25
|
/** The same tiles for the page without scripts. */
|
|
26
26
|
export declare function limitsHtml(limits: BrowserLimits | null): Html;
|
package/dist/limits-ui.js
CHANGED
|
@@ -38,7 +38,7 @@ export function limitsView(windows, budgets, names, now) {
|
|
|
38
38
|
for (const budget of budgets) {
|
|
39
39
|
const over = budget.spentMicrousd >= budget.limitMicrousd;
|
|
40
40
|
const name = budget.scope === "installation" ? "Everything" : budget.scope === "project" ? names.project(budget.key)
|
|
41
|
-
: budget.scope === "
|
|
41
|
+
: budget.scope === "subagent" ? names.subagent(Number(budget.key)) : budget.key;
|
|
42
42
|
tiles.push({
|
|
43
43
|
key: `budget:${budget.id}`, name, window: "Budget", value: usd(budget.spentMicrousd), unit: `of ${usd(budget.limitMicrousd)}`,
|
|
44
44
|
percent: budget.percent, tone: over ? (budget.hardStop ? "danger" : "warning") : budget.percent >= 80 ? "warning" : "neutral", marks: [50, 80], href: "/spend",
|
package/dist/mcp-connect.d.ts
CHANGED
|
@@ -159,7 +159,7 @@ export declare function finishConnect(store: Store, visit: ConnectVisit, code: s
|
|
|
159
159
|
ok: false;
|
|
160
160
|
said: string;
|
|
161
161
|
}>;
|
|
162
|
-
/** Keep connected services signed in: any token expiring within ten minutes is refreshed (the worker's pass, and before a
|
|
162
|
+
/** Keep connected services signed in: any token expiring within ten minutes is refreshed (the worker's pass, and before a subagent's call). */
|
|
163
163
|
export declare function refreshConnections(store: Store, repos: readonly string[], now: Date, options?: {
|
|
164
164
|
fetcher?: Fetch;
|
|
165
165
|
home?: string;
|
package/dist/mcp-connect.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* with this console's callback, and sends the person to the service to sign
|
|
9
9
|
* in. The callback trades the code for tokens, which live in the tool's own
|
|
10
10
|
* secrets file (never the database, never a log), and the tool joins the
|
|
11
|
-
* project like any other: tested, listed, and given to
|
|
11
|
+
* project like any other: tested, listed, and given to subagents under rules.
|
|
12
12
|
* The worker refreshes tokens before they expire.
|
|
13
13
|
*/
|
|
14
14
|
import { createHash, randomBytes } from "node:crypto";
|
|
@@ -382,10 +382,10 @@ export async function finishConnect(store, visit, code, now, options = {}) {
|
|
|
382
382
|
if (options.test === false)
|
|
383
383
|
return { ok: true, said: `${service.label} is connected to ${to}.` };
|
|
384
384
|
const tested = await testToolOf(store, visit.repo, spec.name, now, { home, ...(options.omitEnv === undefined ? {} : { omitEnv: options.omitEnv }) });
|
|
385
|
-
return tested?.ok ? { ok: true, said: `${service.label} is connected to ${to}: ${tested.tools.length} action${tested.tools.length === 1 ? "" : "s"}. Let a
|
|
385
|
+
return tested?.ok ? { ok: true, said: `${service.label} is connected to ${to}: ${tested.tools.length} action${tested.tools.length === 1 ? "" : "s"}. Let a subagent use it from its page.` }
|
|
386
386
|
: { ok: true, said: `${service.label} is signed in for ${to}, but its test didn't pass yet: ${tested?.problem ?? "no answer"}.` };
|
|
387
387
|
}
|
|
388
|
-
/** Keep connected services signed in: any token expiring within ten minutes is refreshed (the worker's pass, and before a
|
|
388
|
+
/** Keep connected services signed in: any token expiring within ten minutes is refreshed (the worker's pass, and before a subagent's call). */
|
|
389
389
|
export async function refreshConnections(store, repos, now, options = {}) {
|
|
390
390
|
const fetcher = options.fetcher ?? fetch, home = options.home ?? homedir();
|
|
391
391
|
const report = { refreshed: 0, problems: [] };
|
package/dist/mcp-core.js
CHANGED
|
@@ -17,7 +17,7 @@ import { GATEWAY_TOOL_INPUTS, GATEWAY_TOOL_OUTPUTS } from "./contracts/gateway-t
|
|
|
17
17
|
import { reportToolOutput } from "./contracts/lead-tools.js";
|
|
18
18
|
import { PACKAGE_VERSION } from "./version.js";
|
|
19
19
|
import { authenticateCoordinator, fileCoordinatorProposal, statusFor, listTasksFor, taskDetailFor, } from "./coordinator.js";
|
|
20
|
-
import { ISO_STAMP_RULE, decisionOver, decisionsOver, labelRepos, queueOver, recapOver } from "./
|
|
20
|
+
import { ISO_STAMP_RULE, decisionOver, decisionsOver, labelRepos, queueOver, recapOver } from "./lead-tools.js";
|
|
21
21
|
import { proposeAsCoordinator } from "./coordinator-proposals.js";
|
|
22
22
|
export const MODERN = "2026-07-28";
|
|
23
23
|
export const LEGACY = "2025-11-25";
|
package/dist/memory-pass.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Store } from './store.js';
|
|
2
|
-
import {
|
|
2
|
+
import { performSubscriptionLeadRequest } from './subscription-chat.js';
|
|
3
3
|
import { type MemoryProposal, type Verdict } from './contracts/memory-pass.js';
|
|
4
4
|
export type { MemoryProposal, Verdict };
|
|
5
5
|
/** One session's trace, in characters (TEXT_LIMITS.memoryTrace). */
|
|
@@ -66,7 +66,7 @@ export declare function defaultAnalyzer(store: Store, options: {
|
|
|
66
66
|
env?: NodeJS.ProcessEnv;
|
|
67
67
|
fetcher?: typeof fetch;
|
|
68
68
|
timeoutMs?: number;
|
|
69
|
-
runner?: Parameters<typeof
|
|
69
|
+
runner?: Parameters<typeof performSubscriptionLeadRequest>[1];
|
|
70
70
|
}): MemoryAnalyzer;
|
|
71
71
|
/**
|
|
72
72
|
* Read the analyser's answer with the tolerant parse-side schema, then keep only claims whose quote
|
package/dist/memory-pass.js
CHANGED
|
@@ -17,8 +17,8 @@ import { basename, join } from 'node:path';
|
|
|
17
17
|
import { scanForSecrets, readVerifiedArtifact } from './evidence.js';
|
|
18
18
|
import { changeKnowledge, knowledgeView } from './project-knowledge.js';
|
|
19
19
|
import { listDecisions, recordDecision } from './project-memory.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
20
|
+
import { composeLeadRequest, performLeadRequest, isDirectChatProvider, CHAT_KEY_ENV } from './converse.js';
|
|
21
|
+
import { performSubscriptionLeadRequest } from './subscription-chat.js';
|
|
22
22
|
import { TEXT_LIMITS } from './text-limits.js';
|
|
23
23
|
import { contractError, parseContract } from './contracts/contract.js';
|
|
24
24
|
import { MEMORY_VERDICT_MODEL_SCHEMA, MEMORY_VERDICT_VERSION, memoryEvidenceSchema, memoryProposalSchema, memoryVerdictReadSchema, readSavedVerdict, savedVerdictSchema } from './contracts/memory-pass.js';
|
|
@@ -138,11 +138,11 @@ function fileSources(repo, kind, home) {
|
|
|
138
138
|
/** The plane's own sessions: lead threads that touched the project, and finished crew runs with their handoff and check output. */
|
|
139
139
|
function planeSources(store, repo, evidenceRoot) {
|
|
140
140
|
const out = [];
|
|
141
|
-
const threads = store.handle.prepare(`SELECT c.thread AS thread, c.id AS conversation, MAX(m.id) AS last, MAX(m.created_at) AS at FROM team_conversation c JOIN
|
|
141
|
+
const threads = store.handle.prepare(`SELECT c.thread AS thread, c.id AS conversation, MAX(m.id) AS last, MAX(m.created_at) AS at FROM team_conversation c JOIN lead_message m ON m.thread=c.thread
|
|
142
142
|
WHERE EXISTS (SELECT 1 FROM json_each(c.projects_json) WHERE value=?) GROUP BY c.thread`).all(repo);
|
|
143
143
|
for (const row of threads) {
|
|
144
144
|
const thread = Number(row['thread']);
|
|
145
|
-
out.push({ id: `lead:${thread}:${Number(row['last'])}`, repo, kind: 'lead', source: `conversation:${String(row['conversation'])}`, at: String(row['at']), trace: () => redact(store.handle.prepare('SELECT role,text FROM
|
|
145
|
+
out.push({ id: `lead:${thread}:${Number(row['last'])}`, repo, kind: 'lead', source: `conversation:${String(row['conversation'])}`, at: String(row['at']), trace: () => redact(store.handle.prepare('SELECT role,text FROM lead_message WHERE thread=? ORDER BY id LIMIT 400').all(thread).map(m => `${m['role']}: ${clip(String(m['text']), 4000)}`).join('\n')) });
|
|
146
146
|
}
|
|
147
147
|
const runs = store.handle.prepare(`SELECT r.id, r.role, r.finished_at, r.handoff, t.external_id FROM run r JOIN task_ref t ON t.id=r.task_ref WHERE t.repo=? AND r.role IN ('builder','repair') AND r.outcome IS NOT NULL ORDER BY r.id DESC LIMIT 100`).all(repo);
|
|
148
148
|
for (const row of runs) {
|
|
@@ -207,12 +207,12 @@ export function defaultAnalyzer(store, options) {
|
|
|
207
207
|
}
|
|
208
208
|
if (!key)
|
|
209
209
|
return { ok: false, problem: `No ${config.provider} key is available for the backward pass.` };
|
|
210
|
-
const request =
|
|
211
|
-
const answer = await
|
|
210
|
+
const request = composeLeadRequest({ provider: config.provider, model: config.model, key, system, dataDocument, history, tools: [] });
|
|
211
|
+
const answer = await performLeadRequest(request, config.provider, AbortSignal.timeout(options.timeoutMs ?? 120_000), options.fetcher);
|
|
212
212
|
return answer.ok ? { ok: true, text: answer.answer.text } : { ok: false, problem: answer.problem };
|
|
213
213
|
}
|
|
214
214
|
// The verdict's own schema is the harness's structured output, so the answer is the verdict itself.
|
|
215
|
-
const answer = await
|
|
215
|
+
const answer = await performSubscriptionLeadRequest({ provider: config.provider, model: config.model, system, dataDocument, history, tools: [], outputSchema: MEMORY_VERDICT_MODEL_SCHEMA, timeoutMs: options.timeoutMs ?? 180_000 }, options.runner);
|
|
216
216
|
return answer.ok ? { ok: true, text: answer.answer.text } : { ok: false, problem: answer.problem };
|
|
217
217
|
};
|
|
218
218
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/** Saved notifications, read and told apart without a store: the row readers, the lifecycle key and the predicates
|
|
2
2
|
* the store and the chat core (chat-messages.ts) share. A leaf: it imports types only. */
|
|
3
|
-
import type {
|
|
3
|
+
import type { LeadProposal, Notification, NotificationReceipt } from "./store.js";
|
|
4
4
|
/** The one task a card is about: a task its confirmation created (a new
|
|
5
5
|
* task, a revision), else the task it names (and, for feedback on a result,
|
|
6
6
|
* that result). Null for a card about no single task. A pointer for
|
|
7
7
|
* replies, never an authority. */
|
|
8
|
-
export declare function proposalTaskOf(proposal:
|
|
8
|
+
export declare function proposalTaskOf(proposal: LeadProposal | null): {
|
|
9
9
|
task: string;
|
|
10
10
|
run: number | null;
|
|
11
11
|
} | null;
|
package/dist/operate.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { FetchLike } from "./flow-share.js";
|
|
|
7
7
|
import { type Store } from "./store.js";
|
|
8
8
|
import { type DispatchAdapter } from "./sync.js";
|
|
9
9
|
import { type TelegramTransport } from "./telegram.js";
|
|
10
|
-
import { type
|
|
10
|
+
import { type LeadCliSeams } from "./lead-cli.js";
|
|
11
11
|
import { type Principal, type RemoteSource } from "./operate-remote.js";
|
|
12
12
|
import { type PublishExec } from "./publish.js";
|
|
13
13
|
import { type Runner as CommandRunner } from "./builder.js";
|
|
@@ -71,8 +71,8 @@ export type OperateOptions = {
|
|
|
71
71
|
flowFetch?: FetchLike;
|
|
72
72
|
/** Injected by tests: how `integrations` checks reach services (fetch, gh, sign-in checks, mail servers). */
|
|
73
73
|
integrationIo?: Partial<IntegrationIo>;
|
|
74
|
-
/** Injected by tests: the
|
|
75
|
-
|
|
74
|
+
/** Injected by tests: the lead's provider fetch, key environment, and stdin lines. */
|
|
75
|
+
leadSeams?: LeadCliSeams;
|
|
76
76
|
/** Test seam for the short indexed wait loop. */
|
|
77
77
|
waitSleep?: (milliseconds: number) => Promise<void>;
|
|
78
78
|
/** Injected by tests: `onboard`'s home folder, terminal and probes. */
|
package/dist/operate.js
CHANGED
|
@@ -22,7 +22,7 @@ import { checkoutPlan, cleanCheckouts, discardCheckout, finishedCheckouts, slimK
|
|
|
22
22
|
import { closeOutCheckouts, closeOutRuns, stoppedWords } from "./run-closeout.js";
|
|
23
23
|
import { MIN_DAYS, RETENTION_KINDS, countWords, dailyRetention, isRetentionKind, lastSweepAt, parsePeriod, periodLabel, periodWords, retentionPlan, sweepWords } from "./retention.js";
|
|
24
24
|
import { checkPolicy, parseList, policyParts } from "./policy.js";
|
|
25
|
-
import { billingOf, budgetHoldWords, budgetLabel, budgetStates, monthNamed, monthOf, spendItems,
|
|
25
|
+
import { billingOf, budgetHoldWords, budgetLabel, budgetStates, monthNamed, monthOf, spendItems, subagentNames, usd as spendUsd } from "./spend.js";
|
|
26
26
|
import { spendCsv } from "./spend-ui.js";
|
|
27
27
|
import { buildExport, exportSummary, exportZip, writeExportFolder } from "./export.js";
|
|
28
28
|
import { startBudgetAlerts } from "./budget-alerts.js";
|
|
@@ -43,8 +43,8 @@ import { origin, readMonitoring } from "./monitoring-settings.js";
|
|
|
43
43
|
import { logEvent } from "./log.js";
|
|
44
44
|
import { FLOW_EVERY_MS, flowHousekeeping, moveCards, moveCardsAfter } from "./flow-cadence.js";
|
|
45
45
|
import { readHooksBase, scheduleFromWords } from "./flow-triggers.js";
|
|
46
|
-
import {
|
|
47
|
-
import { runRequestedUndos,
|
|
46
|
+
import { sendSubagentSummaries } from "./subagent-admin.js";
|
|
47
|
+
import { runRequestedUndos, sendSubagentWeeklies } from "./subagent-week.js";
|
|
48
48
|
import { refreshConnections } from "./mcp-connect.js";
|
|
49
49
|
import { followDiscord } from "./discord.js";
|
|
50
50
|
import { followTeams } from "./teams.js";
|
|
@@ -156,8 +156,8 @@ import { bridgePass, clearBotToken, createTransport, followBridge, hashPairingCo
|
|
|
156
156
|
import { scanRepo } from "./capscan.js";
|
|
157
157
|
import { computeGaps, describeCapability } from "./gaps.js";
|
|
158
158
|
import { ask as promptAsk, askHidden as promptHidden, confirm as promptConfirm, interactive as promptInteractive, underAgent } from "./prompt.js";
|
|
159
|
-
import {
|
|
160
|
-
import { confirmCoordinatorProposal, dismissCoordinatorProposal } from "./
|
|
159
|
+
import { runLeadCli, answerContextLines } from "./lead-cli.js";
|
|
160
|
+
import { confirmCoordinatorProposal, dismissCoordinatorProposal } from "./lead-doors.js";
|
|
161
161
|
import { verifyApproverByPassword as approverByPassword } from "./principal.js";
|
|
162
162
|
import { activeRemote, REMOTE_MESSAGES, REMOTE_REFUSED_FLAGS, REMOTE_SCOPES, RemoteRefusal, remoteAllows, remoteLensOf, remoteProjectOf, remoteRowOf, remoteSecret, reproveRemote, withRemote } from "./operate-remote.js";
|
|
163
163
|
import { projectAuthority } from "./project-access.js";
|
|
@@ -179,7 +179,7 @@ import { CHAT_APPROVE_ALL, presetTerms, modeTermsJson, modeDigestOf, modeTermsFr
|
|
|
179
179
|
import { WorktreePool } from "./worktree.js";
|
|
180
180
|
import { requestTaskStop, resumeTaskStop, taskControlOf } from "./task-control.js";
|
|
181
181
|
import { worktreeAdoptionNotice } from "./worktree-notices.js";
|
|
182
|
-
import { workIndexPage, WorkIndexCursorError } from "./work-index.js";
|
|
182
|
+
import { workIndexPage, workIndexTask, WorkIndexCursorError } from "./work-index.js";
|
|
183
183
|
import { readExecutorOf } from "./read-executor.js";
|
|
184
184
|
import { parseWorkView } from "./workspace-ui.js";
|
|
185
185
|
import { taskWorkSummaryOf } from "./work-summary.js";
|
|
@@ -256,9 +256,9 @@ export const OPERATE_HELP = `toolroll — operating the queue
|
|
|
256
256
|
toolroll integrations [--json] which integrations work: Connected, Not set up or Broken, and what to do (--saved: no new checks)
|
|
257
257
|
toolroll monitoring where the audit stream and traces go, and how each destination is doing
|
|
258
258
|
toolroll check-progress <run> current or final approved check progress
|
|
259
|
-
toolroll spend [--month YYYY-MM] [--csv] what agent work cost, by project, person,
|
|
259
|
+
toolroll spend [--month YYYY-MM] [--csv] what agent work cost, by project, person, subagent and model
|
|
260
260
|
toolroll export --out <path> [--zip] everything Toolroll knows, in a folder or .zip (no secrets)
|
|
261
|
-
toolroll budget list|set|remove monthly budgets (--all | --project <p> | --person <name> | --
|
|
261
|
+
toolroll budget list|set|remove monthly budgets (--all | --project <p> | --person <name> | --subagent <id>) --usd <n> [--alerts-only]
|
|
262
262
|
toolroll notifications [quiet|all] how chats reach you: only when you're needed (the default), or every step
|
|
263
263
|
toolroll notifications digest <HH:MM>|off one evening message: what finished, what waits, what failed
|
|
264
264
|
toolroll notifications mute|unmute --repo <p> no pings for a project; the console and digest keep it
|
|
@@ -477,7 +477,7 @@ Agents — which provider and model each phase runs on
|
|
|
477
477
|
toolroll chat --as <you> [--repo <path>…] [--say "…"] [--end]
|
|
478
478
|
[--ceiling-usd <n>] [--json] (password at the prompt;
|
|
479
479
|
--token <t> only for scripts — it lands in shell history)
|
|
480
|
-
|
|
480
|
+
your lead: one conversation across your projects, the same thread the
|
|
481
481
|
console shows; the password mints a spending session once; it reads
|
|
482
482
|
and proposes, you confirm cards (confirm N / dismiss N / open N;
|
|
483
483
|
confirm N yes for an irreversible answer)
|
|
@@ -625,7 +625,7 @@ export const OPERATE_VALUE_FLAGS = new Set([
|
|
|
625
625
|
// v103: the ledger chain and evidence packs.
|
|
626
626
|
"checkpoint", "out", "from", "to",
|
|
627
627
|
// v105: spend and budgets.
|
|
628
|
-
"month", "usd", "person", "teammate",
|
|
628
|
+
"month", "usd", "person", "subagent", "teammate",
|
|
629
629
|
// Sprint 8: the organisation policy.
|
|
630
630
|
"providers", "models", "tools",
|
|
631
631
|
"project-root", "schedule", "ceiling", "require",
|
|
@@ -869,7 +869,7 @@ async function dispatchOn(command, positional, flags, repoList, base, options, e
|
|
|
869
869
|
...(options.flowFetch === undefined ? {} : { flowFetch: options.flowFetch }),
|
|
870
870
|
...(options.integrationIo === undefined ? {} : { integrationIo: options.integrationIo }),
|
|
871
871
|
...(options.shouldStop === undefined ? {} : { shouldStop: options.shouldStop }),
|
|
872
|
-
...(options.
|
|
872
|
+
...(options.leadSeams === undefined ? {} : { leadSeams: options.leadSeams }),
|
|
873
873
|
...(options.waitSleep === undefined ? {} : { waitSleep: options.waitSleep }),
|
|
874
874
|
...(options.releaseIo === undefined ? {} : { releaseIo: options.releaseIo }),
|
|
875
875
|
...(options.installBin === undefined ? {} : { installBin: options.installBin }),
|
|
@@ -1023,7 +1023,7 @@ function telegramCanDeliver(context, token) {
|
|
|
1023
1023
|
function telegramConversation(context, options = {}) {
|
|
1024
1024
|
return {
|
|
1025
1025
|
evidenceRoot: context.evidenceRoot,
|
|
1026
|
-
...(context.
|
|
1026
|
+
...(context.leadSeams?.subscriptionRunner === undefined ? {} : { subscriptionRunner: context.leadSeams.subscriptionRunner }),
|
|
1027
1027
|
// Re-read on every card and every `/task`: the same console-url chat
|
|
1028
1028
|
// links use, held to an https origin, and — inside `up`, where this
|
|
1029
1029
|
// process also serves the console — equal to that console's own
|
|
@@ -2273,25 +2273,25 @@ async function tickCommand(flags, context) {
|
|
|
2273
2273
|
const replyPass = housekeeping?.replies ?? { read: 0, taken: 0, problem: null };
|
|
2274
2274
|
const stepPass = housekeeping?.steps ?? { ran: 0, problems: [] };
|
|
2275
2275
|
const flowPass = housekeeping?.flows ?? { moved: 0, filed: [], problems: [] };
|
|
2276
|
-
// Each
|
|
2276
|
+
// Each subagent's daily summary to its manager (v92), once, after 5 pm; its weekly report (v97), Monday mornings.
|
|
2277
2277
|
if (!buildsOnly)
|
|
2278
2278
|
try {
|
|
2279
|
-
|
|
2280
|
-
|
|
2279
|
+
sendSubagentSummaries(store, repo, clock());
|
|
2280
|
+
sendSubagentWeeklies(store, repo, clock());
|
|
2281
2281
|
}
|
|
2282
2282
|
catch (error) {
|
|
2283
|
-
flowPass.problems.push(`
|
|
2283
|
+
flowPass.problems.push(`subagent summaries: ${error instanceof Error ? error.message : "could not send"}`);
|
|
2284
2284
|
}
|
|
2285
|
-
// Undoing a
|
|
2285
|
+
// Undoing a subagent's tool call asked for in chat (v97): made here, as the person who asked.
|
|
2286
2286
|
if (!buildsOnly && context.shouldStop?.() !== true) {
|
|
2287
2287
|
try {
|
|
2288
2288
|
await runRequestedUndos(store, {}, clock());
|
|
2289
2289
|
}
|
|
2290
2290
|
catch (error) {
|
|
2291
|
-
flowPass.problems.push(`
|
|
2291
|
+
flowPass.problems.push(`subagent undo: ${error instanceof Error ? error.message : "could not run"}`);
|
|
2292
2292
|
}
|
|
2293
2293
|
}
|
|
2294
|
-
// Tools connected by signing in: a sign-in that runs out within ten minutes is renewed here, so a build or a
|
|
2294
|
+
// Tools connected by signing in: a sign-in that runs out within ten minutes is renewed here, so a build or a subagent's call starts with a fresh one.
|
|
2295
2295
|
if (!buildsOnly && context.shouldStop?.() !== true) {
|
|
2296
2296
|
try {
|
|
2297
2297
|
flowPass.problems.push(...(await refreshConnections(store, [repo], clock(), context.flowStepIo?.fetch === undefined ? {} : { fetcher: context.flowStepIo.fetch })).problems);
|
|
@@ -6050,19 +6050,19 @@ async function runWatchLoop(args) {
|
|
|
6050
6050
|
: startTelegramFollower({ context, publicUrl: text(flags, "public-url"), signal: followController.signal, progress, label: "watch: bridge", died: { prefix: "watch: ", then: "taps wait for the next watch" } });
|
|
6051
6051
|
const slackFollower = followSlack({ store, dir: dirname(context.databaseFile), signal: followController.signal,
|
|
6052
6052
|
readProjects: telegramReadProjects(context), evidenceRoot: context.evidenceRoot,
|
|
6053
|
-
...(context.
|
|
6053
|
+
...(context.leadSeams?.subscriptionRunner ? { subscriptionRunner: context.leadSeams.subscriptionRunner } : {}),
|
|
6054
6054
|
origin: () => phoneOrigin(process.env, dirname(context.databaseFile), { serverOrigin: text(flags, "public-url") ?? null }),
|
|
6055
6055
|
notifications: () => effectivePrimary(process.env, dirname(context.databaseFile), loadBotToken(process.env, context.telegramTokenFile) !== null).channel === "slack",
|
|
6056
6056
|
}).catch(() => progress("watch: Slack stopped. Check Slack settings before reconnecting."));
|
|
6057
6057
|
const teamsFollower = followTeams({ store, dir: dirname(context.databaseFile), signal: followController.signal,
|
|
6058
6058
|
readProjects: telegramReadProjects(context), evidenceRoot: context.evidenceRoot,
|
|
6059
|
-
...(context.
|
|
6059
|
+
...(context.leadSeams?.subscriptionRunner ? { subscriptionRunner: context.leadSeams.subscriptionRunner } : {}),
|
|
6060
6060
|
origin: () => phoneOrigin(process.env, dirname(context.databaseFile), { serverOrigin: text(flags, "public-url") ?? null }),
|
|
6061
6061
|
notifications: () => effectivePrimary(process.env, dirname(context.databaseFile), loadBotToken(process.env, context.telegramTokenFile) !== null).channel === "teams",
|
|
6062
6062
|
}).catch(() => progress("watch: Teams stopped. Check Teams settings before reconnecting."));
|
|
6063
6063
|
const discordFollower = followDiscord({ store, dir: dirname(context.databaseFile), signal: followController.signal,
|
|
6064
6064
|
readProjects: telegramReadProjects(context), evidenceRoot: context.evidenceRoot,
|
|
6065
|
-
...(context.
|
|
6065
|
+
...(context.leadSeams?.subscriptionRunner ? { subscriptionRunner: context.leadSeams.subscriptionRunner } : {}),
|
|
6066
6066
|
origin: () => phoneOrigin(process.env, dirname(context.databaseFile), { serverOrigin: text(flags, "public-url") ?? null }),
|
|
6067
6067
|
notifications: () => effectivePrimary(process.env, dirname(context.databaseFile), loadBotToken(process.env, context.telegramTokenFile) !== null).channel === "discord",
|
|
6068
6068
|
}).catch(() => progress("watch: Discord stopped. Check Discord settings before reconnecting."));
|
|
@@ -8307,10 +8307,10 @@ async function statusCommand(positional, flags, context) {
|
|
|
8307
8307
|
// that belongs to the installation or other projects (updates, integrations, builds by project, unsent replies).
|
|
8308
8308
|
const lens = context.principal?.lens ?? null;
|
|
8309
8309
|
if (lens !== null) {
|
|
8310
|
-
const status = installationStatus(context.store, context.clock(), viewer, lens);
|
|
8310
|
+
const status = installationStatus(context.store, context.clock(), viewer, lens, context.evidenceRoot);
|
|
8311
8311
|
return succeed(context.write, context.json, command, { ...status, projects: [] }, () => renderInstallationStatus(status, true));
|
|
8312
8312
|
}
|
|
8313
|
-
const status = installationStatus(context.store, context.clock(), viewer);
|
|
8313
|
+
const status = installationStatus(context.store, context.clock(), viewer, null, context.evidenceRoot);
|
|
8314
8314
|
// One line, only when a newer Toolroll exists; offline or switched off says nothing.
|
|
8315
8315
|
const current = PACKAGE_VERSION;
|
|
8316
8316
|
const method = installMethod(context.installBin);
|
|
@@ -8927,6 +8927,7 @@ function listTasks(flags, context) {
|
|
|
8927
8927
|
view: parseWorkView(rawView ?? null), limit, cursor: text(flags, 'cursor') ?? null,
|
|
8928
8928
|
...(wanted === undefined ? {} : { state: wanted }),
|
|
8929
8929
|
...(text(flags, 'repo') === undefined ? {} : { project: text(flags, 'repo') }),
|
|
8930
|
+
root: context.evidenceRoot,
|
|
8930
8931
|
};
|
|
8931
8932
|
const refused = (error) => {
|
|
8932
8933
|
if (!(error instanceof WorkIndexCursorError))
|
|
@@ -8990,10 +8991,18 @@ function showTask(positional, context) {
|
|
|
8990
8991
|
const repo = store.lookupRef(blocker)?.repo;
|
|
8991
8992
|
return repo != null && lens.includes(repo);
|
|
8992
8993
|
});
|
|
8994
|
+
const work = taskWorkSummaryOf(store, id, now, access);
|
|
8995
|
+
const current = assignmentOf(store, id, now, access, context.evidenceRoot);
|
|
8996
|
+
// Read the same saved facts and statusOf path as task list. File health remains
|
|
8997
|
+
// in the assignment diagnostics and action-time guards; it cannot rewrite history.
|
|
8998
|
+
const listed = workIndexTask(store, id, now, access, context.evidenceRoot);
|
|
8999
|
+
const shared = listed === null ? null : { headline: listed.status.label, sentence: listed.status.detail };
|
|
9000
|
+
const primaryAction = listed === null ? work?.primaryAction ?? null : listed.primaryAction;
|
|
8993
9001
|
const detail = {
|
|
8994
9002
|
task,
|
|
8995
|
-
work:
|
|
8996
|
-
|
|
9003
|
+
work: work === null || listed === null ? work : { ...work, status: { ...work.status, label: listed.status.label, detail: listed.status.detail, tone: listed.status.tone }, primaryAction },
|
|
9004
|
+
status: shared === null ? null : { headline: shared.headline, sentence: shared.sentence },
|
|
9005
|
+
assignment: assignmentBrief(current),
|
|
8997
9006
|
ref: ref.id,
|
|
8998
9007
|
// One phrase for every inaccessible blocker, so even their number stays private.
|
|
8999
9008
|
blockedBy: visibleBlockers.length === blockers.length ? visibleBlockers : [...visibleBlockers, "a task in another project"],
|
|
@@ -9033,8 +9042,8 @@ function showTask(positional, context) {
|
|
|
9033
9042
|
`${task.id} ${task.state}${ref.deliverable === "report" ? " (scout — delivers a report)" : ""}`,
|
|
9034
9043
|
` ${task.title}`,
|
|
9035
9044
|
...(detail.work === null ? [] : [
|
|
9036
|
-
` status: ${detail.work.status.label}`,
|
|
9037
|
-
...(
|
|
9045
|
+
` status: ${shared?.headline ?? detail.work.status.label}${shared === null ? "" : ` — ${shared.sentence}`}`,
|
|
9046
|
+
...(primaryAction === null ? [] : [` next: ${primaryAction.label}${primaryAction.target.decisionId === null ? "" : ` — decision #${primaryAction.target.decisionId}`}`]),
|
|
9038
9047
|
]),
|
|
9039
9048
|
// The closed machine-authored verdict (Priority 2), computed once at
|
|
9040
9049
|
// completion — never re-derived here. Same words `verdictWords`
|
|
@@ -9042,7 +9051,7 @@ function showTask(positional, context) {
|
|
|
9042
9051
|
...(task.state !== "done" || detail.proofVerdict === null
|
|
9043
9052
|
? []
|
|
9044
9053
|
: [
|
|
9045
|
-
` proof: ${proofVerdictWords(detail.proofVerdict, detail.proofReasons).word}${detail.proofAccepted ? " (accepted)" : ""}`,
|
|
9054
|
+
` proof: ${proofVerdictWords(current?.receipt?.runId === latestFinished?.id ? current?.readiness?.verdict ?? detail.proofVerdict : detail.proofVerdict, detail.proofReasons).word}${detail.proofAccepted ? " (accepted)" : ""}`,
|
|
9046
9055
|
...(detail.proofReasons.length > 0 ? [` ${detail.proofReasons.join("; ")}`] : []),
|
|
9047
9056
|
...matrixWords(detail.proofMatrix),
|
|
9048
9057
|
...(detail.semanticCoverage === null ? [] : coverageWords(detail.semanticCoverage).map(line => ` ${line}`)),
|
|
@@ -9987,7 +9996,7 @@ function describeApproveFailure(reason, id) {
|
|
|
9987
9996
|
if (reason === "requester")
|
|
9988
9997
|
return `you filed ${id}, and this project needs someone else to approve it`;
|
|
9989
9998
|
if (reason === "person-required")
|
|
9990
|
-
return `${id} is protected work: a person has to approve it, not an operating mode, a schedule or
|
|
9999
|
+
return `${id} is protected work: a person has to approve it, not an operating mode, a schedule or a subagent`;
|
|
9991
10000
|
if (reason === "second-approver")
|
|
9992
10001
|
return `your approval of ${id} is recorded; it is protected work, so a second person needs to approve it (toolroll task approve ${id} as them)`;
|
|
9993
10002
|
if (reason === "no-approvers") {
|
|
@@ -10104,7 +10113,7 @@ async function chatCommand(flags, context) {
|
|
|
10104
10113
|
return fail(write, json, "chat", "usage", "Choose --follow or --no-follow.", EXIT.usage);
|
|
10105
10114
|
const credentials = await askCredentials(flags, context);
|
|
10106
10115
|
if (credentials === null) {
|
|
10107
|
-
return fail(write, json, "chat", "usage", "the
|
|
10116
|
+
return fail(write, json, "chat", "usage", "the lead takes your name and password — `--as <you>` and the hidden prompt; `--token <t>` only where a script must (it lands in shell history)", EXIT.usage);
|
|
10108
10117
|
}
|
|
10109
10118
|
const ceilingGiven = text(flags, "ceiling-usd");
|
|
10110
10119
|
// The ceiling: the `--repo` list, or the ENROLLED registry beside the
|
|
@@ -10120,7 +10129,7 @@ async function chatCommand(flags, context) {
|
|
|
10120
10129
|
return fail(write, json, "chat", "registry", "the enrolled-project registry could not be read — name projects with --repo", EXIT.refused);
|
|
10121
10130
|
repos = loaded.repos;
|
|
10122
10131
|
}
|
|
10123
|
-
const result = await
|
|
10132
|
+
const result = await runLeadCli({
|
|
10124
10133
|
store,
|
|
10125
10134
|
databaseFile: context.databaseFile,
|
|
10126
10135
|
write,
|
|
@@ -10131,7 +10140,7 @@ async function chatCommand(flags, context) {
|
|
|
10131
10140
|
end: flags.has("end"),
|
|
10132
10141
|
...(flags.has("follow") || flags.has("no-follow") ? { follow: flags.has("follow") && !flags.has("no-follow") } : {}),
|
|
10133
10142
|
ceilingUsd: ceilingGiven === undefined ? undefined : Number(ceilingGiven),
|
|
10134
|
-
...(context.
|
|
10143
|
+
...(context.leadSeams === undefined ? {} : { seams: { ...context.leadSeams, clock: context.leadSeams.clock ?? context.clock } }),
|
|
10135
10144
|
...(context.evidenceRoot === undefined ? {} : { evidenceRoot: context.evidenceRoot }),
|
|
10136
10145
|
// The console's own address (and its public one): links there read as "the task", "the result", "Settings → Lead".
|
|
10137
10146
|
appOrigin: [loadConsoleUrl(process.env, dirname(context.databaseFile)), phoneOrigin(process.env, dirname(context.databaseFile))],
|
|
@@ -10698,7 +10707,7 @@ async function projectDeleteCommand(positional, flags, context) {
|
|
|
10698
10707
|
`Deleted ${repo}: ${holdingsWords(done.removed)}.`, ...done.left.map(one => `Git kept ${one}.`), `The ledger records it as entry #${done.ledgerId}.`,
|
|
10699
10708
|
]);
|
|
10700
10709
|
}
|
|
10701
|
-
/** `spend [--month YYYY-MM] [--csv]` (v105): what agent work cost in a month, by project, person,
|
|
10710
|
+
/** `spend [--month YYYY-MM] [--csv]` (v105): what agent work cost in a month, by project, person, subagent and model. */
|
|
10702
10711
|
function spendCommand(flags, context) {
|
|
10703
10712
|
const command = "spend";
|
|
10704
10713
|
for (const name of flags.keys())
|
|
@@ -10708,7 +10717,7 @@ function spendCommand(flags, context) {
|
|
|
10708
10717
|
if (month === null)
|
|
10709
10718
|
return fail(context.write, context.json, command, "usage", "Use spend --month YYYY-MM.", EXIT.usage);
|
|
10710
10719
|
const items = spendItems(context.store.handle, month.from, month.to);
|
|
10711
|
-
const names =
|
|
10720
|
+
const names = subagentNames(context.store.handle);
|
|
10712
10721
|
if (flags.has("csv")) {
|
|
10713
10722
|
context.write(spendCsv(items, names).replace(/^\ufeff/, "").trimEnd());
|
|
10714
10723
|
return EXIT.ok;
|
|
@@ -10722,7 +10731,7 @@ function spendCommand(flags, context) {
|
|
|
10722
10731
|
byProject.set(item.project, (byProject.get(item.project) ?? 0) + (item.microusd ?? 0));
|
|
10723
10732
|
// v105: subscription work is $0; what binds it is its plan's windows, as the provider last said.
|
|
10724
10733
|
const limits = context.store.providerLimits();
|
|
10725
|
-
const windows = limitsView(limits, [], { project: repo => basename(repo),
|
|
10734
|
+
const windows = limitsView(limits, [], { project: repo => basename(repo), subagent: id => String(id) }, context.clock())?.tiles ?? [];
|
|
10726
10735
|
// Sized routing: each tier's tasks, time to a result and plan use, and what the tiers saved.
|
|
10727
10736
|
const tiers = tierReport(context.store.handle, month.from, month.to, items);
|
|
10728
10737
|
return succeed(context.write, context.json, command, { month: month.name, totalMicrousd: total, unpriced, items: items.length, budgets, limits, tiers: { rows: tiers.rows, saved: tiers.saved } }, () => [
|
|
@@ -10825,21 +10834,22 @@ async function budgetCommand(positional, flags, context) {
|
|
|
10825
10834
|
const store = context.store;
|
|
10826
10835
|
if (action === undefined || action === "list") {
|
|
10827
10836
|
const budgets = store.monthSpend(context.clock()).budgets;
|
|
10828
|
-
return succeed(context.write, context.json, command, { budgets }, () => budgets.length === 0 ? ["No budgets. `budget set --all|--project <path>|--person <name>|--
|
|
10837
|
+
return succeed(context.write, context.json, command, { budgets }, () => budgets.length === 0 ? ["No budgets. `budget set --all|--project <path>|--person <name>|--subagent <id> --usd <n>` makes one."]
|
|
10829
10838
|
: budgets.map(one => `#${one.id} ${budgetLabel(one).replace(/'s$/, "")}: ${spendUsd(one.spentMicrousd)} of ${spendUsd(one.limitMicrousd)} this month (${one.percent}%)${one.hardStop ? ", stops API work at 100%" : ", alerts only"}`));
|
|
10830
10839
|
}
|
|
10831
10840
|
if (action !== "set" && action !== "remove")
|
|
10832
10841
|
return fail(context.write, context.json, command, "usage", "Use budget list, budget set or budget remove.", EXIT.usage);
|
|
10833
|
-
|
|
10842
|
+
// --teammate: the flag's name before D5, still read this release.
|
|
10843
|
+
const allowed = new Set(["all", "project", "person", "subagent", "teammate", "usd", "alerts-only", "as", "token", "token-file", "token-env", "db", "json"]);
|
|
10834
10844
|
for (const name of flags.keys())
|
|
10835
10845
|
if (!allowed.has(name))
|
|
10836
10846
|
return fail(context.write, context.json, command, "usage", `--${name} is not a budget option.`, EXIT.usage);
|
|
10837
10847
|
const chosen = [flags.has("all") ? { scope: "installation", key: "*" } : null,
|
|
10838
10848
|
text(flags, "project") === undefined ? null : { scope: "project", key: resolve(text(flags, "project")) },
|
|
10839
10849
|
text(flags, "person") === undefined ? null : { scope: "person", key: text(flags, "person") },
|
|
10840
|
-
text(flags, "teammate") === undefined ? null : { scope: "
|
|
10850
|
+
(text(flags, "subagent") ?? text(flags, "teammate")) === undefined ? null : { scope: "subagent", key: (text(flags, "subagent") ?? text(flags, "teammate")) }].filter(one => one !== null);
|
|
10841
10851
|
if (chosen.length !== 1)
|
|
10842
|
-
return fail(context.write, context.json, command, "usage", "Name one of --all, --project <path>, --person <name> or --
|
|
10852
|
+
return fail(context.write, context.json, command, "usage", "Name one of --all, --project <path>, --person <name> or --subagent <id>.", EXIT.usage);
|
|
10843
10853
|
const target = chosen[0];
|
|
10844
10854
|
const acting = await askCredentials(flags, context);
|
|
10845
10855
|
const verified = acting === null ? null : authenticateApprover(store, acting.name, acting.token);
|
|
@@ -10848,9 +10858,9 @@ async function budgetCommand(positional, flags, context) {
|
|
|
10848
10858
|
}
|
|
10849
10859
|
const known = target.scope === "installation" || (target.scope === "project" ? store.knownRepos().includes(target.key)
|
|
10850
10860
|
: target.scope === "person" ? store.accountFacts().some(one => one.name === target.key && one.revokedAt === null)
|
|
10851
|
-
: store.handle.prepare("SELECT 1 FROM
|
|
10861
|
+
: store.handle.prepare("SELECT 1 FROM subagent WHERE id = ?").get(Number(target.key)) !== undefined);
|
|
10852
10862
|
if (!known)
|
|
10853
|
-
return fail(context.write, context.json, command, "not-found", "That isn't a project, person or
|
|
10863
|
+
return fail(context.write, context.json, command, "not-found", "That isn't a project, person or subagent here.", EXIT.refused);
|
|
10854
10864
|
if (action === "remove") {
|
|
10855
10865
|
const existing = store.budgets().find(one => one.scope === target.scope && one.key === target.key);
|
|
10856
10866
|
if (existing === undefined || !store.removeBudget(existing.id, acting.name, context.clock()))
|
package/dist/policy.d.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* (lowered), or, when there is none, doesn't run (refused); the words say which.
|
|
16
16
|
*
|
|
17
17
|
* Every road that admits work asks here: scope approval, the tick before a
|
|
18
|
-
* run starts (and build() as the last look), the lead and project chats,
|
|
18
|
+
* run starts (and build() as the last look), the lead and project chats, subagents and flow steps.
|
|
19
19
|
*/
|
|
20
20
|
import type { Database } from "./store.js";
|
|
21
21
|
import type { ExecutionProfile } from "./scope.js";
|
package/dist/principal.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export type VerifiedApprover = {
|
|
|
9
9
|
readonly repos: readonly string[];
|
|
10
10
|
readonly ceilingDigest: string;
|
|
11
11
|
};
|
|
12
|
-
/** The
|
|
12
|
+
/** The lead's ceiling digest: the admitted repos IN ORDER, hashed — `rN`
|
|
13
13
|
* is an index, so two surfaces naming the same repos in a different order
|
|
14
14
|
* hold different ceilings (slice-2 review, finding 3). */
|
|
15
15
|
export declare function ceilingDigestOf(repos: readonly string[]): string;
|
package/dist/principal.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The branded approver principal (mate arc, ruling 3).
|
|
3
3
|
*
|
|
4
|
-
* Every act the
|
|
4
|
+
* Every act the lead proposes and every confirmation an operator taps
|
|
5
5
|
* runs under a principal that PROVES it was authenticated — a password
|
|
6
6
|
* ceremony, or a cookie session the edge already proved (csrf, role,
|
|
7
7
|
* generation) and this module re-proves against the approver row. The
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
17
|
import { authenticateAccount } from "./scope.js";
|
|
18
|
-
/** The
|
|
18
|
+
/** The lead's ceiling digest: the admitted repos IN ORDER, hashed — `rN`
|
|
19
19
|
* is an index, so two surfaces naming the same repos in a different order
|
|
20
20
|
* hold different ceilings (slice-2 review, finding 3). */
|
|
21
21
|
export function ceilingDigestOf(repos) {
|
|
@@ -49,7 +49,7 @@ export function projectDeleteConfirmHtml(view, problem) {
|
|
|
49
49
|
"The checkouts and branches Toolroll made",
|
|
50
50
|
...(h.chats > 0 ? [count(h.chats, "chat")] : []),
|
|
51
51
|
...(h.flows > 0 ? [`${count(h.flows, "flow")} and ${count(h.cards, "card")}`] : []),
|
|
52
|
-
...(h.
|
|
52
|
+
...(h.subagents > 0 ? [count(h.subagents, "subagent")] : []),
|
|
53
53
|
"Its budgets, settings and knowledge",
|
|
54
54
|
];
|
|
55
55
|
return html `<section class="project-delete">${problem === null ? "" : html `<p class="problem" role="alert">${problem}</p>`}<p>This removes:</p><ul class="removes">${items.map(one => html `<li>${one}</li>`)}</ul><p>The repository at <span class="path">${view.repo}</span> and its own branches stay. The ledger keeps its history. There's no undo.</p>${postForm("/settings/project/delete", html `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label><div class="actions"><button type="submit" class="danger">Delete project</button><a href="/settings/project?repo=${encodeURIComponent(view.repo)}">Cancel</a></div>`, { hidden: { repo: view.repo, name: view.name, step: "delete" } })}</section>`;
|