toolroll 0.9.86 → 0.9.87
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 +59 -0
- package/dist/agents-board.d.ts +12 -0
- package/dist/agents-board.js +26 -0
- package/dist/approval-rules-ui.d.ts +4 -1
- package/dist/approval-rules-ui.js +31 -15
- package/dist/assignment-ui.js +1 -1
- package/dist/backup-ui.d.ts +5 -4
- package/dist/backup-ui.js +65 -32
- package/dist/browser/terminal.css +1 -1
- package/dist/browser/terminal.js +57 -54
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +35 -70
- package/dist/browser-crew.js +1 -1
- package/dist/browser-workspace.d.ts +329 -183
- package/dist/browser-workspace.js +10 -9
- package/dist/chat-controls.d.ts +1 -1
- package/dist/chat-controls.js +1 -1
- package/dist/chat-settings-page.d.ts +29 -9
- package/dist/chat-settings-page.js +59 -28
- package/dist/check-levels-ui.d.ts +2 -1
- package/dist/check-levels-ui.js +67 -58
- package/dist/contracts/cli.d.ts +43 -0
- package/dist/contracts/cli.js +4 -0
- package/dist/contracts/console-api.d.ts +1 -1
- package/dist/contracts/console-api.js +1 -1
- package/dist/credentials-ui.d.ts +5 -3
- package/dist/credentials-ui.js +58 -31
- package/dist/design/kit.css +685 -0
- package/dist/design/kit.d.ts +208 -0
- package/dist/design/kit.js +177 -0
- package/dist/design/tokens.css +19 -1
- package/dist/discord-settings.js +8 -4
- package/dist/export-ui.d.ts +6 -4
- package/dist/export-ui.js +18 -8
- package/dist/flow-changed.d.ts +14 -0
- package/dist/flow-changed.js +53 -0
- package/dist/flow-gallery-ui.d.ts +41 -4
- package/dist/flow-gallery-ui.js +95 -63
- package/dist/flow-starters-ui.d.ts +3 -9
- package/dist/flow-starters-ui.js +12 -23
- package/dist/flow-unattended-words.d.ts +20 -0
- package/dist/flow-unattended-words.js +24 -0
- package/dist/flow-unattended.d.ts +9 -5
- package/dist/flow-unattended.js +45 -23
- package/dist/flows-cli.js +7 -3
- package/dist/flows-ui.d.ts +12 -6
- package/dist/flows-ui.js +141 -30
- package/dist/integrations-ui.d.ts +6 -4
- package/dist/integrations-ui.js +34 -40
- package/dist/integrations.d.ts +2 -2
- package/dist/integrations.js +4 -4
- package/dist/kits-ui.d.ts +8 -10
- package/dist/kits-ui.js +29 -33
- package/dist/kits.js +1 -1
- package/dist/knowledge-ui.js +76 -19
- package/dist/ledger-view.d.ts +2 -0
- package/dist/ledger-view.js +41 -38
- package/dist/models-ui.d.ts +8 -3
- package/dist/models-ui.js +82 -59
- package/dist/monitoring-ui.d.ts +4 -2
- package/dist/monitoring-ui.js +44 -13
- package/dist/needs-you.d.ts +1 -1
- package/dist/needs-you.js +8 -0
- package/dist/operate-remote-arguments.js +1 -0
- package/dist/operate-remote.js +1 -1
- package/dist/operate.d.ts +1 -1
- package/dist/operate.js +38 -4
- package/dist/passwordless.d.ts +1 -1
- package/dist/passwordless.js +1 -1
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +25 -23
- package/dist/policy-ui.d.ts +3 -2
- package/dist/policy-ui.js +27 -21
- package/dist/policy.d.ts +3 -0
- package/dist/policy.js +14 -1
- package/dist/project-delete-ui.d.ts +4 -2
- package/dist/project-delete-ui.js +135 -126
- package/dist/project-knowledge.d.ts +10 -10
- package/dist/publish.d.ts +11 -0
- package/dist/publish.js +16 -3
- package/dist/pull-request-ui.d.ts +2 -1
- package/dist/pull-request-ui.js +39 -28
- package/dist/recipe-ui.d.ts +4 -2
- package/dist/recipe-ui.js +14 -4
- package/dist/release-adapters.d.ts +3 -0
- package/dist/release-adapters.js +22 -2
- package/dist/release-cli.js +81 -9
- package/dist/release.d.ts +21 -0
- package/dist/release.js +40 -4
- package/dist/releases.js +1 -1
- package/dist/request-budget-ui.d.ts +4 -2
- package/dist/request-budget-ui.js +30 -19
- package/dist/retention-ui.d.ts +4 -3
- package/dist/retention-ui.js +15 -12
- package/dist/scope.d.ts +3 -0
- package/dist/scope.js +6 -0
- package/dist/serve.d.ts +0 -1
- package/dist/serve.js +51 -7
- package/dist/server/agents-computers.d.ts +9 -0
- package/dist/server/agents-computers.js +67 -0
- package/dist/server/chat.js +16 -16
- package/dist/server/chrome.d.ts +1 -1
- package/dist/server/chrome.js +19 -9
- package/dist/server/console.css +2 -2
- package/dist/server/flows.js +64 -36
- package/dist/server/home.d.ts +35 -0
- package/dist/server/home.js +104 -0
- package/dist/server/http.d.ts +3 -0
- package/dist/server/http.js +5 -0
- package/dist/server/kit-standalone.d.ts +22 -0
- package/dist/server/kit-standalone.js +69 -0
- package/dist/server/kit.d.ts +405 -0
- package/dist/server/kit.js +361 -0
- package/dist/server/pages.d.ts +2 -1
- package/dist/server/pages.js +213 -174
- package/dist/server/people-tokens.js +26 -85
- package/dist/server/render-history.d.ts +51 -0
- package/dist/server/render-history.js +228 -0
- package/dist/server/render-new-task.d.ts +29 -0
- package/dist/server/render-new-task.js +96 -0
- package/dist/server/render-next.d.ts +63 -0
- package/dist/server/render-next.js +109 -0
- package/dist/server/render-pages.d.ts +22 -190
- package/dist/server/render-pages.js +123 -575
- package/dist/server/render-people.d.ts +24 -3
- package/dist/server/render-people.js +93 -72
- package/dist/server/render-projects.d.ts +103 -0
- package/dist/server/render-projects.js +247 -0
- package/dist/server/render-results.d.ts +5 -24
- package/dist/server/render-results.js +48 -185
- package/dist/server/render-settings.d.ts +5 -74
- package/dist/server/render-settings.js +102 -493
- package/dist/server/render-tasks.d.ts +35 -5
- package/dist/server/render-tasks.js +114 -85
- package/dist/server/route-table.js +20 -5
- package/dist/server/settings.js +276 -255
- package/dist/server/task-views.d.ts +8 -0
- package/dist/server/task-views.js +85 -2
- package/dist/server/tasks.d.ts +8 -0
- package/dist/server/tasks.js +95 -40
- package/dist/server/terminals.js +1 -1
- package/dist/server/welcome.d.ts +22 -0
- package/dist/server/welcome.js +69 -0
- package/dist/settings-groups-ui.d.ts +279 -0
- package/dist/settings-groups-ui.js +615 -0
- package/dist/settings-kit.d.ts +42 -6
- package/dist/settings-kit.js +69 -7
- package/dist/setup-guide.d.ts +2 -2
- package/dist/skills-ui.js +59 -7
- package/dist/slack-settings.js +12 -5
- package/dist/spend-ui.d.ts +45 -26
- package/dist/spend-ui.js +124 -56
- package/dist/sso-ui.d.ts +5 -2
- package/dist/sso-ui.js +63 -31
- package/dist/storage-ui.d.ts +3 -2
- package/dist/storage-ui.js +56 -50
- package/dist/store.d.ts +112 -3
- package/dist/store.js +292 -20
- package/dist/surface.js +5 -1
- package/dist/teams-settings.d.ts +2 -1
- package/dist/teams-settings.js +24 -41
- package/dist/telegram-settings.d.ts +0 -4
- package/dist/telegram-settings.js +52 -25
- package/dist/toolroll-update-ui.d.ts +8 -4
- package/dist/toolroll-update-ui.js +55 -45
- package/dist/tools-ui.d.ts +5 -3
- package/dist/tools-ui.js +107 -42
- package/dist/work-index.js +11 -7
- package/dist/workspace-ui.d.ts +1 -1
- package/dist/workspace-ui.js +7 -4
- package/package.json +1 -1
package/dist/integrations.js
CHANGED
|
@@ -327,7 +327,7 @@ function targets(io) {
|
|
|
327
327
|
const list = [];
|
|
328
328
|
list.push({
|
|
329
329
|
key: "telegram", group: "chat", name: "Telegram", configured: telegram !== null, account: null,
|
|
330
|
-
setup: place("/settings#telegram-token"), fix: place("/settings#telegram-token"), usedBy: chatUses("telegram"), activity: telegramActivity(store),
|
|
330
|
+
setup: place("/settings/alerts#telegram-token"), fix: place("/settings/alerts#telegram-token"), usedBy: chatUses("telegram"), activity: telegramActivity(store),
|
|
331
331
|
probe: telegram === null ? null : check => probeTelegram(check, telegram.token),
|
|
332
332
|
});
|
|
333
333
|
list.push({
|
|
@@ -371,7 +371,7 @@ function targets(io) {
|
|
|
371
371
|
: { okAt: str(mailWatch["updated_at"]), error: null, errorAt: null, failing: false };
|
|
372
372
|
list.push({
|
|
373
373
|
key: "email", group: "mail", name: "Email", configured: email !== null || google !== null, account: email?.from ?? google?.address ?? null,
|
|
374
|
-
setup: place("/settings#email"), fix: place("/settings#email"), usedBy: [...flowWords(emailUses)], activity: merge(triggerActivity(emailUses), watchActivity),
|
|
374
|
+
setup: place("/settings/alerts#email"), fix: place("/settings/alerts#email"), usedBy: [...flowWords(emailUses)], activity: merge(triggerActivity(emailUses), watchActivity),
|
|
375
375
|
probe: email === null ? null : check => probeEmail(check, { host: email.host, port: email.port, secure: email.secure }, email.imap),
|
|
376
376
|
});
|
|
377
377
|
// Each project's MCP tools: the server starts and lists its tools.
|
|
@@ -432,7 +432,7 @@ function targets(io) {
|
|
|
432
432
|
for (const provider of AGENTS) {
|
|
433
433
|
list.push({
|
|
434
434
|
key: `agent:${provider}`, group: "agents", name: providerName(provider), configured: true, account: null,
|
|
435
|
-
setup: place("/settings#providers"), fix: place("/settings#providers"), usedBy: ["Tasks"], activity: NO_ACTIVITY,
|
|
435
|
+
setup: place("/settings/agents#providers"), fix: place("/settings/agents#providers"), usedBy: ["Tasks"], activity: NO_ACTIVITY,
|
|
436
436
|
probe: check => probeAgent(check, provider),
|
|
437
437
|
});
|
|
438
438
|
}
|
|
@@ -458,7 +458,7 @@ function combine(target, row) {
|
|
|
458
458
|
if (failing !== null) {
|
|
459
459
|
return { ...base, ...common, state: "broken", action: { kind: "fix", label: "Fix", words: scrubIntegrationText(failing ?? "The last check failed."), ...target.fix } };
|
|
460
460
|
}
|
|
461
|
-
return { ...base, ...common, state: "connected", action: { kind: "test", label: "
|
|
461
|
+
return { ...base, ...common, state: "connected", action: { kind: "test", label: "Check connection" } };
|
|
462
462
|
}
|
|
463
463
|
/**
|
|
464
464
|
* youiyoux change requests, one row per project that uses youiyoux (youiyoux-intake.ts): Connected with how many of
|
package/dist/kits-ui.d.ts
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Starter kits
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Starter kits: the "With an agent" rows of New flow (each kit's promise, what it sets up, one button to its page)
|
|
3
|
+
* and a kit's own page, a reading page: what it sets up, then its checklist with the next step on each line
|
|
4
|
+
* (connect email, connect a tool, try a sample card).
|
|
5
5
|
*/
|
|
6
6
|
import type { Store } from "./store.js";
|
|
7
7
|
import { type Kit } from "./kits.js";
|
|
8
8
|
import { type Html } from "./html.js";
|
|
9
9
|
export declare const KITS_CSS: string;
|
|
10
|
-
/**
|
|
11
|
-
export declare function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
/** A kit's own page: what's set up, and the next step on each line. */
|
|
15
|
-
export declare function kitPageHtml(store: Store, kit: Kit, repo: string, dir: string | null, canSetUp: boolean, notice: {
|
|
10
|
+
/** "With an agent": every kit as a row; Set it up (or Open, once it's there) goes to the kit's page for `repo`. */
|
|
11
|
+
export declare function kitRowsHtml(store: Store, repo: string | null): Html;
|
|
12
|
+
/** A kit's own page: what it sets up, Set up (once), then the next step on each line. */
|
|
13
|
+
export declare function kitPageHtml(store: Store, kit: Kit, repo: string, dir: string | null, canSetUp: boolean, notice_: {
|
|
16
14
|
said?: string | null;
|
|
17
15
|
problem?: string | null;
|
|
18
|
-
}): Html;
|
|
16
|
+
}, projectName?: (repo: string) => string): Html;
|
package/dist/kits-ui.js
CHANGED
|
@@ -1,46 +1,42 @@
|
|
|
1
1
|
import { kitChecklist, kitInstalled, KITS } from "./kits.js";
|
|
2
2
|
import { SUBAGENT_TEMPLATES } from "./subagents.js";
|
|
3
3
|
import { html, postForm, reauth } from "./html.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export const KITS_CSS = `.
|
|
7
|
-
`.kit{display:flex;
|
|
8
|
-
`.kit
|
|
9
|
-
`.kit
|
|
10
|
-
|
|
11
|
-
`.kit-steps svg{flex:none;width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}.kit-steps li[data-done="true"] svg{color:var(--so-success)}.kit-steps li[data-done="false"] svg{color:var(--so-muted)}` +
|
|
12
|
-
`.kit-steps .kit-step-said{flex:1;min-width:0}.kit-steps li[data-done="true"] .kit-step-said{color:var(--so-muted)}.kit-steps form{margin:0}.kit-steps button,.kit-steps .kit-step-go{min-height:40px;white-space:nowrap}` +
|
|
13
|
-
`.kit-steps .kit-step-go{display:inline-flex;align-items:center;padding:0 12px;border:1px solid var(--so-line);border-radius:8px;text-decoration:none;font-size:.9rem}` +
|
|
14
|
-
`@media(max-width:600px){.kit-steps li{flex-wrap:wrap}.kit-steps .kit-step-said{flex-basis:calc(100% - 40px)}.kit form select{font-size:16px}}`;
|
|
4
|
+
import { templateRow } from "./flow-gallery-ui.js";
|
|
5
|
+
import { acts, btn, count, doc, docHeader, dock, facts, group, icon, infoLine, input, note, notice, phoneHeader } from "./server/kit.js";
|
|
6
|
+
export const KITS_CSS = `.fl-kit-steps{list-style:none;padding:0;margin:0;display:grid;border-top:1px solid var(--so-line)}` +
|
|
7
|
+
`.fl-kit-steps li{display:flex;align-items:center;gap:12px;min-height:48px;padding:8px 0;border-bottom:1px solid var(--so-line);min-width:0}` +
|
|
8
|
+
`.fl-kit-steps li>.k-i{flex:none;color:var(--so-muted)}.fl-kit-steps li[data-done="true"]>.k-i{color:var(--so-done-ink)}.fl-kit-ring{flex:none;width:14px;height:14px;margin:0 1px;border:1.5px solid var(--so-field-line);border-radius:50%;box-sizing:border-box}` +
|
|
9
|
+
`.fl-kit-said{flex:1;min-width:0;font-size:13px;overflow-wrap:anywhere}.fl-kit-steps li[data-done="true"] .fl-kit-said{color:var(--so-muted)}.fl-kit-steps form{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:0}.fl-kit-steps .k-input{width:180px}` +
|
|
10
|
+
`@media(max-width:760px){.fl-kit-steps li{flex-wrap:wrap}.fl-kit-said{flex-basis:calc(100% - 40px)}.fl-kit-steps form,.fl-kit-steps .k-input{width:100%}}`;
|
|
15
11
|
const subagentWords = (kit) => { const template = SUBAGENT_TEMPLATES.find(one => one.id === kit.subagent.template); return template === undefined ? kit.subagent.handle : template.label.toLowerCase(); };
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
const gets = `${
|
|
23
|
-
|
|
24
|
-
:
|
|
25
|
-
: postForm(`/kits/${kit.id}/setup`, html `${projects.length === 1 ? ""
|
|
26
|
-
: html `<label>Project<select name="repo">${projects.map(repo => html `<option value="${repo}">${projectName(repo)}${here.includes(repo) ? " (set up)" : ""}</option>`)}</select></label>`}<button>Set it up</button>`, { hidden: { repo: projects.length === 1 ? projects[0] : null } });
|
|
27
|
-
return html `<article class="kit" data-kit="${kit.id}"><h2>${kit.name}</h2><p class="kit-promise">${kit.promise}</p><p class="kit-gets">${gets}</p>${action}</article>`;
|
|
12
|
+
const agentName = (kit) => kit.subagent.handle.charAt(0).toUpperCase() + kit.subagent.handle.slice(1);
|
|
13
|
+
const kitHref = (kit, repo) => `/kits/${kit.id}?repo=${encodeURIComponent(repo)}`;
|
|
14
|
+
/** "With an agent": every kit as a row; Set it up (or Open, once it's there) goes to the kit's page for `repo`. */
|
|
15
|
+
export function kitRowsHtml(store, repo) {
|
|
16
|
+
const rows = KITS.map(kit => {
|
|
17
|
+
const here = repo !== null && kitInstalled(store, kit, repo) !== null;
|
|
18
|
+
const gets = `${agentName(kit)} (${subagentWords(kit)}) and the ${kit.flowName} flow${kit.tools.length === 0 ? "" : ` · works with ${kit.tools.map(one => one.label).join(" and ")}`}`;
|
|
19
|
+
return templateRow({ name: kit.name, promise: kit.promise, line: gets, attrs: html ` data-kit="${kit.id}"`,
|
|
20
|
+
action: repo === null ? "" : btn(here ? "Open" : "Set it up", { sm: true, href: kitHref(kit, repo), attrs: { "aria-label": `${here ? "Open" : "Set up"} ${kit.name}` } }) });
|
|
28
21
|
});
|
|
29
|
-
return html
|
|
22
|
+
return html `${group("With an agent", count(KITS.length))}<div data-group="kits">${rows}</div>`;
|
|
30
23
|
}
|
|
31
|
-
/** A kit's own page: what
|
|
32
|
-
export function kitPageHtml(store, kit, repo, dir, canSetUp,
|
|
24
|
+
/** A kit's own page: what it sets up, Set up (once), then the next step on each line. */
|
|
25
|
+
export function kitPageHtml(store, kit, repo, dir, canSetUp, notice_, projectName = one => one) {
|
|
33
26
|
const steps = kitChecklist(store, kit, repo, dir);
|
|
34
27
|
const set = kitInstalled(store, kit, repo);
|
|
28
|
+
const back = `/flows/new?group=kits&repo=${encodeURIComponent(repo)}`;
|
|
35
29
|
const rows = steps.map(step => {
|
|
36
|
-
const go = step.done ? (step.href === null ? "" :
|
|
30
|
+
const go = step.done ? (step.href === null ? "" : btn("Open", { sm: true, href: step.href }))
|
|
37
31
|
: step.action === "sample" || step.action === "github"
|
|
38
|
-
? (canSetUp ? postForm(`/kits/${kit.id}/${step.action}`, step.action === "sample" ?
|
|
32
|
+
? (canSetUp ? postForm(`/kits/${kit.id}/${step.action}`, step.action === "sample" ? btn("Try it", { sm: true, type: "submit" })
|
|
39
33
|
// Issues from anyone come in: it takes your password (an ordinary step-up; a session does under Passwordless).
|
|
40
|
-
: html `${reauth(
|
|
41
|
-
: step.href === null ? "" :
|
|
42
|
-
return html `<li data-step="${step.id}" data-done="${String(step.done)}">${step.done ?
|
|
34
|
+
: html `${reauth(input({ id: `fl-kit-${step.id}-password`, name: "password", type: "password", attrs: { autocomplete: "current-password", "aria-label": "Your password", placeholder: "Your password" } }))}${btn("Bring them in", { sm: true, type: "submit" })}`, { hidden: { repo } }) : "")
|
|
35
|
+
: step.href === null ? "" : btn(step.action === "connect" ? "Connect" : "Set up", { sm: true, href: step.href });
|
|
36
|
+
return html `<li data-step="${step.id}" data-done="${String(step.done)}">${step.done ? icon("check", true) : html `<span class="fl-kit-ring" aria-hidden="true"></span>`}<span class="fl-kit-said">${step.said}</span>${go}</li>`;
|
|
43
37
|
});
|
|
44
|
-
const setUp = set === null && canSetUp ? postForm(`/kits/${kit.id}/setup`,
|
|
45
|
-
|
|
38
|
+
const setUp = set === null && canSetUp ? postForm(`/kits/${kit.id}/setup`, acts(btn(`Set up ${kit.name}`, { variant: "primary", type: "submit", docked: true })), { hidden: { repo }, attrs: { id: "fl-kit-setup" } }) : "";
|
|
39
|
+
const about = facts([["Project", projectName(repo)], ["Agent", `${agentName(kit)} (${subagentWords(kit)})`], ["Flow", kit.flowName], ...(kit.tools.length === 0 ? [] : [["Works with", kit.tools.map(one => one.label).join(" and ")]])]);
|
|
40
|
+
return html `<div class="fl-kit" data-kit-page data-kit="${kit.id}">${phoneHeader(kit.name, { back })}${doc(docHeader({ title: kit.name, back: [back, "New flow"], meta: kit.promise, same: true }), notice_.problem ? notice(notice_.problem) : "", notice_.said ? infoLine(notice_.said) : "", about, set === null ? note("Nothing goes out without you approving it.") : "", setUp, rows.length === 0 ? "" : html `<section class="k-sec" aria-labelledby="fl-kit-next"><h3 id="fl-kit-next">Next steps</h3><ol class="fl-kit-steps">${rows}</ol></section>`)}\
|
|
41
|
+
${set === null && canSetUp ? dock(btn(`Set up ${kit.name}`, { variant: "primary", type: "submit", attrs: { form: "fl-kit-setup" } })) : ""}</div>`;
|
|
46
42
|
}
|
package/dist/kits.js
CHANGED
|
@@ -171,7 +171,7 @@ export function kitChecklist(store, kit, repo, dir) {
|
|
|
171
171
|
if (kit.email === true) {
|
|
172
172
|
// (flow-actions' sendingReady, without its imports: kits load beside the chat actions.)
|
|
173
173
|
const ready = (googleConnected(dir) !== null || readEmailSettings(dir) !== null) && mailboxReady(dir);
|
|
174
|
-
steps.push({ id: "email", done: ready, said: ready ? "Email is connected" : "Connect your email so replies go out and answers come back", href: "/settings#email" });
|
|
174
|
+
steps.push({ id: "email", done: ready, said: ready ? "Email is connected" : "Connect your email so replies go out and answers come back", href: "/settings/alerts#email" });
|
|
175
175
|
}
|
|
176
176
|
if (kit.github === true) {
|
|
177
177
|
const github = githubRepoOf(repo);
|
package/dist/knowledge-ui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { STALE_KNOWLEDGE } from './project-knowledge.js';
|
|
2
|
-
import { html, postForm } from './html.js';
|
|
2
|
+
import { html, joinHtml, postForm } from './html.js';
|
|
3
|
+
import { acts, btn, codeLine, disclose, formRow, input, note, notice, settingsLink, settingsRecord, settingsSection, textarea } from './server/kit.js';
|
|
3
4
|
// Hidden fields as they always were: a missing value is an empty field.
|
|
4
5
|
const fields = (data) => Object.fromEntries(Object.entries(data).map(([k, v]) => [k, String(v ?? '')]));
|
|
5
6
|
/** A section as a frame (after ReUI's Frame, MIT): its heading on the raised well, its body one paper panel. The
|
|
@@ -12,18 +13,46 @@ export function knowledgeHtml(view, csrf, canManage, draft, error) {
|
|
|
12
13
|
const manage = canManage && !!csrf;
|
|
13
14
|
const base = { repo: view.repo, identity: view.identity, revision: view.revision };
|
|
14
15
|
const form = (action, body, extra = {}) => postForm('/settings/knowledge/change', body, { hidden: fields({ ...base, action, ...extra }) });
|
|
15
|
-
const referenceFields = (d) =>
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const referenceFields = (d, key) => joinHtml([
|
|
17
|
+
formRow('Name', null, input({ id: `ref-${key}-title`, name: 'title', value: d.title ?? '', attrs: { maxlength: 120, required: true, 'aria-label': 'Name' } }), 'wide'),
|
|
18
|
+
formRow('Reference text', null, textarea({ id: `ref-${key}-content`, name: 'content', rows: 5, value: d.content ?? '', attrs: { maxlength: 12000, 'aria-label': 'Reference text' } }), 'top'),
|
|
19
|
+
disclose('Use a project document', formRow('Committed .md or .txt path', 'Uses the committed file instead of the text above. Save again to refresh it.', input({ id: `ref-${key}-path`, name: 'path', value: d.path ?? '', attrs: { placeholder: 'docs/design-guide.md', 'aria-label': 'Committed .md or .txt path' } }), 'wide'), Boolean(d.path)),
|
|
20
|
+
acts(btn('Save reference', { sm: true, type: 'submit' })),
|
|
21
|
+
]);
|
|
22
|
+
const refs = view.knowledge.references.map(ref => settingsRecord({
|
|
23
|
+
title: ref.title,
|
|
24
|
+
sub: ref.path ? html `<span class="k-mono">${ref.path} · ${ref.sourceRevision?.slice(0, 7)}</span>` : '',
|
|
25
|
+
more: joinHtml([
|
|
26
|
+
disclose('Read reference', html `<pre class="k-scode">${ref.content}</pre>`, draft?.id === ref.id),
|
|
27
|
+
manage ? disclose('Edit reference', joinHtml([
|
|
28
|
+
form('save', referenceFields(draft?.id === ref.id ? draft : { title: ref.title, content: ref.path ? '' : ref.content, path: ref.path ?? '' }, String(ref.id)), { id: ref.id }),
|
|
29
|
+
disclose('Remove reference', form('remove', joinHtml([note('Remove from future tasks. Previous run context stays available.'), acts(btn('Remove reference', { sm: true, variant: 'danger', type: 'submit' }))]), { id: ref.id })),
|
|
30
|
+
]), draft?.id === ref.id) : '',
|
|
31
|
+
]),
|
|
32
|
+
}));
|
|
33
|
+
const history = view.history.map(h => settingsLink({ href: `/settings/knowledge?repo=${encodeURIComponent(view.repo)}&version=${h.revision}`, title: `Version ${h.revision}`, status: `${h.actor} · ${h.at.slice(0, 16).replace('T', ' ')} UTC` }));
|
|
34
|
+
const problem = error ? notice(error) : '';
|
|
18
35
|
if (view.stale) {
|
|
19
36
|
// One notice, the saved knowledge on demand, one approver action. Editing waits until it is applied.
|
|
20
37
|
const saved = view.stale.knowledge;
|
|
21
|
-
const review =
|
|
22
|
-
return
|
|
38
|
+
const review = disclose('Review saved knowledge', joinHtml([html `<pre class="k-scode">${saved.instructions || 'No project instructions.'}</pre>`, ...saved.references.map(ref => disclose(ref.title, html `<pre class="k-scode">${ref.content}</pre>`))]));
|
|
39
|
+
return joinHtml([problem, settingsSection({ id: 'knowledge-stale', title: 'Saved knowledge', body: joinHtml([
|
|
40
|
+
html `<p class="k-notice info" role="status">${STALE_KNOWLEDGE}.</p>`, review,
|
|
41
|
+
manage ? form('apply', acts(btn('Apply saved knowledge', { variant: 'primary', type: 'submit' }))) : '',
|
|
42
|
+
]) })]);
|
|
23
43
|
}
|
|
24
|
-
const instructions = html `<pre class="
|
|
25
|
-
const editor = manage ?
|
|
26
|
-
|
|
44
|
+
const instructions = html `<pre class="k-scode">${view.knowledge.instructions || 'No project instructions yet.'}</pre>`;
|
|
45
|
+
const editor = manage ? disclose(view.knowledge.instructions ? 'Edit instructions' : 'Add instructions', form('instructions', joinHtml([
|
|
46
|
+
textarea({ id: 'knowledge-instructions', name: 'instructions', rows: 5, value: draft?.instructions ?? view.knowledge.instructions, attrs: { 'aria-label': 'Project instructions', maxlength: 4000, placeholder: 'Goals, preferences, and what good work looks like…' } }),
|
|
47
|
+
acts(btn('Save instructions', { sm: true, type: 'submit' })),
|
|
48
|
+
])), draft?.instructions !== undefined) : '';
|
|
49
|
+
const add = manage ? disclose('Add reference', form('save', referenceFields(draft?.id ? {} : draft ?? {}, 'new')), Boolean(draft?.title && !draft.id)) : '';
|
|
50
|
+
return joinHtml([
|
|
51
|
+
problem,
|
|
52
|
+
settingsSection({ id: 'instructions', title: 'Instructions', lead: 'What every task in this project reads first.', body: joinHtml([instructions, editor]) }),
|
|
53
|
+
settingsSection({ id: 'references', title: 'References', body: joinHtml([refs.length ? joinHtml(refs) : note('Add a spec, design guide, or useful project document.'), add]) }),
|
|
54
|
+
history.length ? settingsSection({ id: 'knowledge-history', title: 'Change history', body: html `<div class="k-slinks">${history}</div>` }) : '',
|
|
55
|
+
]);
|
|
27
56
|
}
|
|
28
57
|
export function knowledgeContextHtml(snapshot) {
|
|
29
58
|
if (!snapshot)
|
|
@@ -35,19 +64,47 @@ export function decisionsHtml(repo, decisions, csrf, canManage, draft, error) {
|
|
|
35
64
|
const manage = canManage && !!csrf;
|
|
36
65
|
const base = { repo };
|
|
37
66
|
const form = (action, body, extra = {}) => postForm('/settings/knowledge/decision', body, { hidden: fields({ ...base, action, ...extra }) });
|
|
38
|
-
const rows = decisions.map(d =>
|
|
39
|
-
|
|
40
|
-
|
|
67
|
+
const rows = decisions.map(d => settingsRecord({
|
|
68
|
+
title: d.claim, sub: d.why, when: html `<span class="k-num">#${d.id}</span> · ${d.decidedBy} · ${d.decidedAt.slice(0, 10)}`, attrs: { id: `decision-${d.id}` },
|
|
69
|
+
more: joinHtml([
|
|
70
|
+
note(`${d.sourceKind}${d.sourceRef ? ` · ${d.sourceRef}` : ''}${d.supersedes === null ? '' : ` · replaces #${d.supersedes}`}`),
|
|
71
|
+
manage ? disclose('Retire', form('retire', joinHtml([
|
|
72
|
+
formRow('Why it no longer holds', null, input({ id: `decision-${d.id}-reason`, name: 'reason', attrs: { maxlength: 500, required: true, 'aria-label': 'Why it no longer holds' } }), 'wide'),
|
|
73
|
+
acts(btn('Retire', { sm: true, variant: 'danger', type: 'submit' })),
|
|
74
|
+
]), { decision: d.id })) : '',
|
|
75
|
+
]),
|
|
76
|
+
}));
|
|
77
|
+
const add = manage ? disclose('Record a decision', form('record', joinHtml([
|
|
78
|
+
formRow('The choice, in one sentence', null, input({ id: 'decision-claim', name: 'claim', value: draft?.claim ?? '', attrs: { maxlength: 240, required: true, 'aria-label': 'The choice, in one sentence' } }), 'wide'),
|
|
79
|
+
formRow('Why', null, textarea({ id: 'decision-why', name: 'why', rows: 3, value: draft?.why ?? '', attrs: { maxlength: 2000, required: true, 'aria-label': 'Why' } }), 'top'),
|
|
80
|
+
acts(btn('Record', { sm: true, type: 'submit' })),
|
|
81
|
+
])), draft?.claim !== undefined) : '';
|
|
82
|
+
return settingsSection({ id: 'decisions', title: 'Decisions', body: joinHtml([error ? notice(error) : '', rows.length ? joinHtml(rows) : note('No decisions yet. The lead suggests one when a conversation settles a choice.'), add]) });
|
|
41
83
|
}
|
|
42
84
|
export function memorySearchHtml(repo, query, hits) {
|
|
43
|
-
const kind = (h) => h.kind === 'decision' ? html `<a href="#decision-${h.ref}">
|
|
44
|
-
const results = hits === null ? '' : hits.length === 0 ?
|
|
45
|
-
return
|
|
85
|
+
const kind = (h) => h.kind === 'decision' ? html `<a class="k-link" href="#decision-${h.ref}">Decision #${h.ref}</a>` : h.kind === 'conversation' ? 'Conversation' : h.kind.charAt(0).toUpperCase() + h.kind.slice(1);
|
|
86
|
+
const results = hits === null ? '' : hits.length === 0 ? note('Nothing in project memory matches.') : joinHtml(hits.map(h => settingsRecord({ title: html `${kind(h)} · ${h.title}`, sub: h.snippet })));
|
|
87
|
+
return settingsSection({ id: 'memory-search', title: 'Search project memory', body: joinHtml([
|
|
88
|
+
html `<form method="get" action="/settings/knowledge" class="k-acts k-picker" role="search"><input type="hidden" name="repo" value="${repo}">${input({ id: 'memory-query', name: 'memory', type: 'search', value: query, attrs: { maxlength: 300, placeholder: 'Search decisions, references, lessons…', autocomplete: 'off', 'aria-label': 'Search project memory' } })}${btn('Search', { sm: true, type: 'submit' })}</form>`,
|
|
89
|
+
results,
|
|
90
|
+
]) });
|
|
46
91
|
}
|
|
47
92
|
export function proposalsHtml(repo, proposals, status, csrf, canManage) {
|
|
48
93
|
const manage = canManage && !!csrf;
|
|
49
|
-
const line = status === null ? '' :
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
94
|
+
const line = status === null ? '' : joinHtml([
|
|
95
|
+
note(`${status.sessions.analyzed}/${status.sessions.total} sessions read${status.sessions.failed ? ` · ${status.sessions.failed} failed` : ''} · ${status.openGaps} open gap${status.openGaps === 1 ? '' : 's'} · Instructions ${status.instructionBytes}/${status.budgetBytes} bytes`),
|
|
96
|
+
disclose('Read new sessions', joinHtml([note('Run this on this computer:'), codeLine(`toolroll memory propose --repo ${repo}`)])),
|
|
97
|
+
]);
|
|
98
|
+
const decide = (p, decision, label) => postForm('/settings/knowledge/proposal', btn(label, { sm: true, variant: decision === 'accept' ? 'outline' : 'ghost', type: 'submit' }), { hidden: fields({ repo, proposal: p.id, decision }) });
|
|
99
|
+
const cards = proposals.map(p => settingsRecord({
|
|
100
|
+
title: p.title, sub: html `<span class="k-num">#${p.id}</span> · ${p.kind} · ${p.sessions} sessions`,
|
|
101
|
+
action: manage ? html `${decide(p, 'accept', 'Accept')}${decide(p, 'reject', 'Reject')}` : '',
|
|
102
|
+
more: joinHtml([
|
|
103
|
+
note(p.rationale),
|
|
104
|
+
p.beforeText ? html `<pre class="k-scode">- ${p.beforeText}</pre>` : '',
|
|
105
|
+
p.afterText ? html `<pre class="k-scode">+ ${p.afterText}</pre>` : '',
|
|
106
|
+
html `<ul class="k-note">${p.evidence.map(ev => html `<li>“${ev.quote.slice(0, 200)}” · ${ev.session.split(':')[0] ?? ''}</li>`)}</ul>`,
|
|
107
|
+
]),
|
|
108
|
+
}));
|
|
109
|
+
return settingsSection({ id: 'proposals', title: 'Proposed from sessions', body: joinHtml([line, cards.length ? joinHtml(cards) : note('Nothing to review. Suggestions appear when the same mistake shows up in two sessions.')]) });
|
|
53
110
|
}
|
package/dist/ledger-view.d.ts
CHANGED
|
@@ -22,4 +22,6 @@ export type LedgerChainView = {
|
|
|
22
22
|
/** Today (UTC, YYYY-MM-DD): the audit export's default range ends here. */
|
|
23
23
|
today: string;
|
|
24
24
|
};
|
|
25
|
+
/** The audit log (`/ledger`): what people and tokens did, newest first, as quiet timed rows, with the filters, the CSV
|
|
26
|
+
* and the sealed export. A kit list page: the top bar, then rows between hairlines. */
|
|
25
27
|
export declare function ledgerBody(rows: LedgerEntry[], projects: readonly string[], params: URLSearchParams, chain?: LedgerChainView): Html;
|
package/dist/ledger-view.js
CHANGED
|
@@ -1,57 +1,60 @@
|
|
|
1
1
|
import { projectName } from "./project.js";
|
|
2
2
|
import { exactWhenHtml } from "./when-html.js";
|
|
3
|
-
import { html, postForm
|
|
3
|
+
import { html, postForm } from "./html.js";
|
|
4
|
+
import { acts, btn, disclose, empty, infoLine, note, notice, pageHeader, select } from "./server/kit.js";
|
|
4
5
|
/** The ledger's kinds of event, as the filter names them. */
|
|
5
6
|
const EVENT_KINDS = [["work", "Work"], ["request", "Requests"], ["access", "Access"], ["sign-in", "Sign-ins"], ["policy", "Policy changes"]];
|
|
6
7
|
function chainHtml(chain) {
|
|
7
8
|
const status = chain.ok
|
|
8
|
-
? html `<
|
|
9
|
-
: html `<
|
|
10
|
-
const latest = chain.latest === null ? "" : html
|
|
11
|
-
const make = chain.csrf === null ? "" : postForm("/ledger/checkpoint",
|
|
9
|
+
? infoLine(html `<span data-ledger-chain="ok">Chain verified · ${chain.entries} entries through #${chain.through ?? 0} · head <span class="k-mono">${chain.head.slice(0, 16)}…</span>${chain.checkedAt === null ? "" : ` · checked in full ${chain.checkedAt.slice(11, 16)} UTC`}</span>`)
|
|
10
|
+
: notice(html `<span data-ledger-chain="broken">Chain broken: ${chain.problem?.what ?? "the chain doesn't verify"}</span>`);
|
|
11
|
+
const latest = chain.latest === null ? "" : note(html `Latest checkpoint (${chain.latest.at.slice(0, 16).replace("T", " ")} UTC). Copy it somewhere outside this machine: <span class="k-mono h-select">${chain.latest.through}:${chain.latest.hash}</span>`);
|
|
12
|
+
const make = chain.csrf === null ? "" : postForm("/ledger/checkpoint", btn("Make a checkpoint", { sm: true, type: "submit", attrs: { "data-k-busy": "Making…" } }), { attrs: { class: "h-inline" } });
|
|
12
13
|
const start = new Date(Date.parse(`${chain.today}T00:00:00Z`) - 29 * 86_400_000).toISOString().slice(0, 10);
|
|
13
|
-
const exportForm =
|
|
14
|
-
|
|
14
|
+
const exportForm = disclose("Audit export", html `<form method="get" action="/ledger/export" class="h-filters h-export" aria-label="Audit export">\
|
|
15
|
+
<div class="k-field"><label class="k-label" for="ledger-from">From</label><input class="k-input" id="ledger-from" type="date" name="from" value="${start}" required></div>\
|
|
16
|
+
<div class="k-field"><label class="k-label" for="ledger-to">To</label><input class="k-input" id="ledger-to" type="date" name="to" value="${chain.today}" required></div>\
|
|
17
|
+
<div class="k-acts">${btn("Download", { sm: true, type: "submit" })}</div></form>${note("Every entry in the range with its seal, and a full record for each task it names. JSON.")}`);
|
|
18
|
+
return html `<section class="h-chain" aria-label="Audit log integrity">${status}${latest}${make}${exportForm}</section>`;
|
|
15
19
|
}
|
|
16
|
-
|
|
17
|
-
.
|
|
18
|
-
.ledger-filter-panel{margin-bottom:12px}.ledger-filter-panel summary{font-size:13px;padding:6px 0;cursor:pointer}.ledger-filters{display:grid;grid-template-columns:repeat(5,minmax(0,1fr)) auto auto;gap:8px;align-items:end;margin:0 0 12px}.ledger-filters label{display:grid;gap:3px;min-width:0;font-size:12px}.ledger-filters input,.ledger-filters select{width:100%;min-width:0;box-sizing:border-box;margin:0;padding:6px 8px;font-size:13px}.ledger-filters button{padding:7px 12px}.ledger-filters>a{padding:8px 0;font-size:13px}
|
|
19
|
-
.ledger-detail{display:block;color:var(--muted-foreground);font-size:12px}.ledger-list{border:1px solid var(--border);border-radius:8px;overflow:hidden}.ledger-event{display:grid;grid-template-columns:140px minmax(90px,1fr) minmax(160px,2fr) minmax(100px,1fr) minmax(100px,1fr);gap:8px;align-items:baseline;padding:7px 10px;border-bottom:1px solid var(--border);font-size:13px;line-height:1.4;overflow-wrap:anywhere}.ledger-event:last-child{border-bottom:0}.ledger-event .actor{color:inherit;font-weight:600;text-decoration:none}.ledger-time,.ledger-place,.ledger-result small{font-size:11px;color:var(--muted-foreground)}.ledger-time time{font-variant-numeric:tabular-nums}.ledger-place a{display:block}.ledger-result small{display:block}.ledger-labels{font-size:11px;color:var(--muted-foreground);font-weight:600}.ledger-empty{padding:12px}
|
|
20
|
-
@media(max-width:1000px){.ledger-filters{grid-template-columns:repeat(3,minmax(0,1fr)) auto}.ledger-event{grid-template-columns:122px minmax(80px,1fr) minmax(130px,2fr) minmax(85px,1fr)}.ledger-place{grid-column:2/4}.ledger-result{grid-column:4;grid-row:1/3}.ledger-labels{display:none}}
|
|
21
|
-
@media(max-width:600px){.ledger-filters{grid-template-columns:repeat(2,minmax(0,1fr))}.ledger-event{grid-template-columns:minmax(0,1fr) auto;gap:2px 8px;padding:8px 10px}.ledger-actor{grid-column:1;grid-row:1}.ledger-action{grid-column:1;grid-row:2}.ledger-result{grid-column:2;grid-row:1/3;text-align:right}.ledger-time{grid-column:1;grid-row:3}.ledger-place{grid-column:2;grid-row:3;text-align:right}.ledger-place a{display:inline}.ledger-heading>a{font-size:13px}}
|
|
22
|
-
.ledger-chain-panel{margin:0 0 12px}.ledger-chain{margin:0 0 4px;font-size:13px}.ledger-chain.ok strong{color:var(--success)}.ledger-checkpoint code{overflow-wrap:anywhere;user-select:all}.ledger-checkpoint-form{margin:6px 0 0}.ledger-export{grid-template-columns:repeat(2,minmax(0,180px)) auto;margin-bottom:4px}
|
|
23
|
-
`;
|
|
20
|
+
/** The audit log (`/ledger`): what people and tokens did, newest first, as quiet timed rows, with the filters, the CSV
|
|
21
|
+
* and the sealed export. A kit list page: the top bar, then rows between hairlines. */
|
|
24
22
|
export function ledgerBody(rows, projects, params, chain) {
|
|
25
|
-
const selected = (key, value) => params.get(key) === value ? html ` selected` : "";
|
|
26
23
|
const more = rows.length > 50;
|
|
27
24
|
const shown = rows.slice(0, 50);
|
|
28
|
-
const
|
|
25
|
+
const kept = new URLSearchParams();
|
|
29
26
|
for (const key of ["project", "actor", "source", "outcome", "task"]) {
|
|
30
27
|
const value = params.get(key);
|
|
31
28
|
if (value)
|
|
32
|
-
|
|
29
|
+
kept.set(key, value);
|
|
33
30
|
}
|
|
34
|
-
const next = new URLSearchParams(
|
|
31
|
+
const next = new URLSearchParams(kept);
|
|
35
32
|
if (shown.length)
|
|
36
33
|
next.set("before", String(shown.at(-1).id));
|
|
37
|
-
const csv = new URLSearchParams(
|
|
34
|
+
const csv = new URLSearchParams(kept);
|
|
38
35
|
csv.set("format", "csv");
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
const text = (id, label, name, placeholder) => html `<div class="k-field"><label class="k-label" for="${id}">${label}</label><input class="k-input" id="${id}" type="text" name="${name}" value="${params.get(name) ?? ""}" placeholder="${placeholder}"></div>`;
|
|
37
|
+
const filters = disclose(`Filters · ${kept.size === 0 ? "all actions" : `${kept.size} active`}`, html `<form method="get" action="/ledger" class="h-filters" aria-label="Filter the audit log">\
|
|
38
|
+
<div class="k-field"><label class="k-label" for="ledger-project">Project</label>${select({ id: "ledger-project", name: "project", wide: true, current: params.get("project") ?? "", items: [["", "All your projects"], ...projects.map(repo => [repo, projectName(repo)])] })}</div>\
|
|
39
|
+
${text("ledger-actor", "Person or worker", "actor", "Anyone")}\
|
|
40
|
+
<div class="k-field"><label class="k-label" for="ledger-source">Events</label>${select({ id: "ledger-source", name: "source", wide: true, current: params.get("source") ?? "", items: [["", "All events"], ...EVENT_KINDS] })}</div>\
|
|
41
|
+
${text("ledger-outcome", "Outcome", "outcome", "Any outcome")}${text("ledger-task", "Task", "task", "Any task")}\
|
|
42
|
+
<div class="k-acts">${btn("Filter", { sm: true, type: "submit" })}${btn("Clear", { sm: true, variant: "ghost", href: "/ledger" })}</div></form>`, kept.size > 0);
|
|
43
|
+
const list = shown.length === 0
|
|
44
|
+
? empty({ title: kept.size === 0 ? "Nothing yet." : "No actions match these filters.", text: kept.size === 0 ? "Approvals, invites, tokens and sign-ins appear here." : "Clear the filters to see every action." })
|
|
45
|
+
: html `<div class="h-audit-list" aria-label="Action history">${shown.map(row => {
|
|
46
|
+
const subject = row.runId !== null ? html `<a class="k-link" href="/r/${row.runId}">Run #${row.runId}</a>` : row.taskId !== null ? html `<a class="k-link k-mono" href="/t/${encodeURIComponent(row.taskId)}">${row.taskId}</a>` : "";
|
|
47
|
+
const byActor = new URLSearchParams(kept);
|
|
48
|
+
byActor.set("actor", row.actor);
|
|
49
|
+
return html `<article class="h-audit" data-ledger-id="${row.id}"><span class="h-audit-time k-num">${exactWhenHtml(row.at)}</span>\
|
|
50
|
+
<span class="h-audit-what"><a class="h-actor" href="/ledger?${byActor.toString()}" title="Only this actor's actions">${row.actor}</a> ${row.action}${row.detail === null ? "" : html `<span class="h-audit-detail">${row.detail}</span>`}</span>\
|
|
51
|
+
<span class="h-audit-place">${row.repo === null ? "Instance" : projectName(row.repo)} ${subject}</span><span class="h-audit-out">${row.outcome} · ${row.source}</span></article>`;
|
|
52
|
+
})}</div>`;
|
|
53
|
+
const paging = kept.has("before") || params.has("before") || more
|
|
54
|
+
? acts(params.has("before") ? btn("Newest actions", { sm: true, variant: "ghost", href: `/ledger?${kept.toString()}` }) : "", more ? btn("Older actions", { sm: true, variant: "ghost", href: `/ledger?${next.toString()}`, attrs: { rel: "next" } }) : "")
|
|
55
|
+
: "";
|
|
56
|
+
return html `<div class="h-page h-ledger" data-kit-page>${pageHeader("Audit log", {
|
|
57
|
+
ctx: "What people and tokens did, newest first. Times in UTC.",
|
|
58
|
+
right: btn("Export CSV", { sm: true, variant: "ghost", href: `/ledger?${csv.toString()}`, attrs: { download: true } }),
|
|
59
|
+
})}<div class="h-tools-row">${chain === undefined ? "" : chainHtml(chain)}${filters}</div>${list}<div class="h-foot-row">${paging}${note("Accepted requests record acceptance; worker events record results. History starts from the upgrade that added it. Review evidence is on each task or run. The CSV holds every matching action.")}</div></div>`;
|
|
57
60
|
}
|
package/dist/models-ui.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
/** Settings → Models
|
|
2
|
-
*
|
|
1
|
+
/** Settings → Models, in the kit's Settings frame (a sub-page of "Agents and models"): what is in use and the one
|
|
2
|
+
* choice (a preset, previewed before it applies), then the model for each role behind a disclosure, the CLIs on
|
|
3
|
+
* this computer and the models that just arrived. Saving is an instance operator's step-up. */
|
|
3
4
|
import { type Html } from "./html.js";
|
|
5
|
+
import { type ApprovalFacts } from "./design/kit.js";
|
|
4
6
|
import type { ModelOption, RuntimeState, SeenModel, WatchState } from "./model-catalog.js";
|
|
5
|
-
|
|
7
|
+
/** The page's own layout on the kit: one-column preset cards, the role pickers in the form rows' control column. */
|
|
8
|
+
export declare const MODELS_CSS: string;
|
|
6
9
|
/** One row of the editor: a role at the scope being edited. */
|
|
7
10
|
export type RoleView = {
|
|
8
11
|
/** The slot's form field (model-choices.ts slotKey). */
|
|
@@ -93,6 +96,8 @@ export type ModelsView = {
|
|
|
93
96
|
taskId: string;
|
|
94
97
|
title: string;
|
|
95
98
|
}[];
|
|
99
|
+
/** What this request's approval shows (approvalFactsNow): a step-up asks for the password unless Passwordless is on. */
|
|
100
|
+
facts?: ApprovalFacts;
|
|
96
101
|
};
|
|
97
102
|
export declare function modelsHtml(view: ModelsView): Html;
|
|
98
103
|
/** Filters one long picker as you type; the saved choice always stays listed. */
|