@desplega.ai/agent-swarm 1.145.0 → 1.147.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/{acp-adapter-580t41c0.js → acp-adapter-9n319wqc.js} +61 -6
- package/dist/{actions-m662tjng.js → actions-2vxqvpr9.js} +9 -8
- package/dist/{app-zb3rndm8.js → app-w066xfy0.js} +6 -5
- package/dist/assistant-kt31dj2h.js +236 -0
- package/dist/{boot-reembed-072x00vn.js → boot-reembed-az5rassp.js} +7 -6
- package/dist/{boot-reembed-65zz2smt.js → boot-reembed-j3mm3rfz.js} +8 -7
- package/dist/{boot-scrub-logs-yz0ams04.js → boot-scrub-logs-b6h54817.js} +4 -4
- package/dist/{claude-adapter-paj270y2.js → claude-adapter-w1z04ann.js} +8 -6
- package/dist/{claude-managed-setup-w619jncn.js → claude-managed-setup-f5pmsyrp.js} +24 -3
- package/dist/{claude-sdk-session-swt80j9z.js → claude-sdk-session-f0cc1kec.js} +8 -6
- package/dist/{cli-dt553ktb.js → cli-0b6y7kxm.js} +1 -1
- package/dist/{cli-bxdhw615.js → cli-12fz972k.js} +4 -4
- package/dist/{cli-s2f20r5w.js → cli-1th1728g.js} +2 -2
- package/dist/{cli-rs6ec3b9.js → cli-3tgwnf43.js} +3 -3
- package/dist/{cli-gxnzc6wh.js → cli-4nr988h6.js} +1 -1
- package/dist/{cli-axs8e6d4.js → cli-53s590z8.js} +1 -1
- package/dist/{cli-ygbjp3z8.js → cli-54wwve05.js} +5 -4
- package/dist/{cli-v0asr5yv.js → cli-719k9j2c.js} +2 -2
- package/dist/{cli-anktweqr.js → cli-89xfd7f9.js} +21 -47
- package/dist/{cli-q34a0e10.js → cli-8v0g1yc8.js} +1 -1
- package/dist/cli-9d8ntetj.js +42 -0
- package/dist/{cli-z9fprcrf.js → cli-atcve9y8.js} +881 -738
- package/dist/{cli-jmb7g47h.js → cli-b5bq9crk.js} +14 -31
- package/dist/cli-d8brzxjb.js +190 -0
- package/dist/{cli-gzky0gkr.js → cli-de14znh8.js} +2 -2
- package/dist/{cli-xytwff7f.js → cli-dttph1bw.js} +2 -2
- package/dist/cli-ep19k3mb.js +19 -0
- package/dist/{cli-m1xa8be7.js → cli-f146mn5s.js} +7 -50
- package/dist/{cli-1fj0chdk.js → cli-f7dsy61y.js} +5 -3
- package/dist/{cli-f567d5c1.js → cli-ftht3zzj.js} +2782 -2589
- package/dist/{cli-a0g1gbt5.js → cli-hbv0kq6w.js} +2 -2
- package/dist/{cli-fhsz3twr.js → cli-jsp14b6c.js} +171 -1
- package/dist/{cli-7fnkj1hj.js → cli-kpv03zhj.js} +21 -17
- package/dist/{cli-m4j6trn4.js → cli-m8yrsg97.js} +2 -2
- package/dist/cli-m9sxbkhm.js +779 -0
- package/dist/cli-mmemxxdc.js +823 -0
- package/dist/{cli-tqtvj5pt.js → cli-n8508nre.js} +1 -1
- package/dist/{cli-z96t0thj.js → cli-p1d5b073.js} +37 -2
- package/dist/{cli-gh8y8f36.js → cli-rw51bq3j.js} +13 -10
- package/dist/{cli-59ej1c07.js → cli-smby5m17.js} +7 -6
- package/dist/{cli-65vqzz3v.js → cli-tzvk9haz.js} +94 -372
- package/dist/{cli-dc9k2ba9.js → cli-w9kb3bk1.js} +1 -1
- package/dist/{cli-kpev657q.js → cli-y6b6fb76.js} +25 -3
- package/dist/{cli-123q2get.js → cli-yz3djrm0.js} +9 -9
- package/dist/{cli-wvp6bvy4.js → cli-zhjmqxzh.js} +1 -1
- package/dist/cli.js +13 -13
- package/dist/{codex-adapter-k98vaw2r.js → codex-adapter-zw4dwsx7.js} +2 -2
- package/dist/{codex-hook-9pf19cks.js → codex-hook-bw8p5nh4.js} +2 -2
- package/dist/{codex-session-runner-tngtphx7.js → codex-session-runner-k981s65v.js} +2 -2
- package/dist/{commands-y8nbr3fv.js → commands-sykrxx7e.js} +4 -4
- package/dist/{db-30p4h2t1.js → db-sfbsc8wt.js} +6 -4
- package/dist/handlers-0aspcejm.js +603 -0
- package/dist/{hook-dcw4jfbj.js → hook-4nvqj2sb.js} +7 -5
- package/dist/{hook-21jexvfx.js → hook-hxccs7m5.js} +24 -49
- package/dist/{http-r4kq5g8d.js → http-y06z517d.js} +230 -94
- package/dist/{index-q3qja6ta.js → index-hssww7kj.js} +15 -14
- package/dist/{index-gay66b9w.js → index-k8znfx0z.js} +13 -12
- package/dist/{index-53zyht4z.js → index-tce1rss4.js} +371 -110
- package/dist/{index-nqvf26za.js → index-x5j894zf.js} +14 -13
- package/dist/{keepalive-xs8fa55y.js → keepalive-w733ax66.js} +6 -6
- package/dist/{lead-d9m2t4s0.js → lead-75bjqa9d.js} +29 -27
- package/dist/{maintenance-3zh82g6z.js → maintenance-w4f1zjck.js} +8 -7
- package/dist/{oauth-refresh-sweep-03snsye5.js → oauth-refresh-sweep-wdetky26.js} +5 -5
- package/dist/{onboard-0cg1925x.js → onboard-bb5net8s.js} +2 -2
- package/dist/{otel-impl-0ab95z27.js → otel-impl-0w7c14ap.js} +1 -1
- package/dist/{pi-mono-adapter-dtkz4e7j.js → pi-mono-adapter-2has4gnp.js} +12 -2
- package/dist/{pricing-refresh-e5jhzz4j.js → pricing-refresh-9nzsrgcq.js} +6 -6
- package/dist/{rbac-roles-p1mf40z3.js → rbac-roles-r3hqjp09.js} +5 -5
- package/dist/{rbac-roles-2w3cmrkc.js → rbac-roles-z1jrffbt.js} +4 -4
- package/dist/{registry-9kdck5ye.js → registry-v5wytg0s.js} +1 -2
- package/dist/{render-v2-xhawry3k.js → render-v2-vbr89fnb.js} +6 -5
- package/dist/{seed-pricing-t223sw91.js → seed-pricing-g62hy1pk.js} +7 -5
- package/dist/{setup-zcs0rce7.js → setup-gnfqnptp.js} +2 -2
- package/dist/{worker-qnp2ka62.js → worker-kznxp4qm.js} +29 -27
- package/openapi.json +263 -12
- package/package.json +1 -1
- package/plugin/commands/start-worker.md +4 -9
- package/plugin/pi-skills/start-worker/SKILL.md +4 -9
- package/src/be/db/agents.ts +556 -0
- package/src/be/db/context-versions.ts +117 -0
- package/src/be/db/runtime.ts +406 -0
- package/src/be/db/tasks/read.ts +1167 -0
- package/src/be/db/tasks/write.ts +953 -0
- package/src/be/db.ts +584 -3429
- package/src/be/migrations/147_scheduled_tasks_parent_task.sql +7 -0
- package/src/be/migrations/148_pages_svg.sql +123 -0
- package/src/be/migrations/149_session_tokens.sql +24 -0
- package/src/be/scripts/typecheck.ts +1 -0
- package/src/be/seed-pricing.ts +13 -8
- package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
- package/src/be/seed-scripts/catalog/star-history-refresh.ts +101 -0
- package/src/be/seed-scripts/catalog/star-history-renderer.ts +119 -0
- package/src/be/seed-scripts/index.ts +17 -0
- package/src/be/seed-skills/index.ts +14 -0
- package/src/be/swarm-config-guard.ts +5 -2
- package/src/be/task-attachment-store.ts +70 -0
- package/src/be/users.ts +77 -0
- package/src/commands/attachments-section.ts +37 -0
- package/src/commands/claude-managed-setup.ts +45 -3
- package/src/commands/claude-md-session.ts +408 -0
- package/src/commands/context-preamble.ts +15 -3
- package/src/commands/profile-sync.ts +205 -5
- package/src/commands/provider-credentials.ts +60 -27
- package/src/commands/runner.ts +63 -58
- package/src/commands/templates.ts +25 -2
- package/src/hooks/hook.ts +26 -67
- package/src/http/agents.ts +40 -1
- package/src/http/auth.ts +13 -1
- package/src/http/fs.ts +21 -51
- package/src/http/index.ts +2 -0
- package/src/http/mcp.ts +32 -0
- package/src/http/pages-public.ts +20 -4
- package/src/http/pages.ts +11 -3
- package/src/http/poll.ts +4 -0
- package/src/http/repos.ts +3 -3
- package/src/http/sessions.ts +82 -0
- package/src/http/tasks.ts +10 -2
- package/src/http/utils.ts +79 -1
- package/src/prompts/session-templates.ts +12 -8
- package/src/providers/acp-adapter.ts +62 -8
- package/src/providers/pi-mono-adapter.ts +23 -6
- package/src/providers/pricing-sources.md +11 -0
- package/src/scheduler/scheduler.test.ts +49 -2
- package/src/scheduler/scheduler.ts +4 -0
- package/src/scripts-runtime/sdk-allowlist.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +8 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +8 -0
- package/src/server.ts +2 -0
- package/src/slack/assistant.ts +87 -46
- package/src/slack/handlers.test.ts +1 -3
- package/src/slack/handlers.ts +102 -87
- package/src/slack/inbound-files.ts +466 -0
- package/src/slack/templates.ts +14 -0
- package/src/tasks/task-terminal-effects.ts +158 -0
- package/src/tests/acp-adapter.test.ts +369 -117
- package/src/tests/budget-claim-gate.test.ts +1 -0
- package/src/tests/build-pi-skills.test.ts +5 -7
- package/src/tests/claude-managed-setup.test.ts +52 -4
- package/src/tests/claude-md-session.test.ts +603 -0
- package/src/tests/codex-skill-resolver.test.ts +19 -0
- package/src/tests/context-versioning.test.ts +107 -0
- package/src/tests/cors-allowlist.test.ts +309 -0
- package/src/tests/credential-check.test.ts +157 -14
- package/src/tests/db-agents.test.ts +91 -0
- package/src/tests/db-context-versions.test.ts +37 -0
- package/src/tests/db-extraction-contract.test.ts +45 -0
- package/src/tests/db-runtime.test.ts +70 -0
- package/src/tests/db-task-read-contract.test.ts +624 -0
- package/src/tests/db-task-write-contract.test.ts +653 -0
- package/src/tests/db-tasks-read.test.ts +183 -0
- package/src/tests/db-tasks-write.test.ts +230 -0
- package/src/tests/defer-task.test.ts +389 -0
- package/src/tests/docs-index-footprint.test.js +2 -2
- package/src/tests/e2e-visuals-stage.test.ts +151 -0
- package/src/tests/file-lock.test.ts +144 -0
- package/src/tests/fixtures/file-lock-holder.ts +13 -0
- package/src/tests/fixtures/hold-file-lock.ts +25 -0
- package/src/tests/heartbeat-expiry.test.ts +188 -0
- package/src/tests/http-api-integration.test.ts +78 -1
- package/src/tests/pages-public-html.test.ts +43 -0
- package/src/tests/pages-svg-migration.test.ts +42 -0
- package/src/tests/preload.ts +4 -1
- package/src/tests/profile-sync-warning.test.ts +16 -0
- package/src/tests/profile-sync.test.ts +126 -0
- package/src/tests/prompt-template-session.test.ts +20 -4
- package/src/tests/provider-registration.test.ts +93 -0
- package/src/tests/rbac-e2e-helpers.test.ts +53 -0
- package/src/tests/rbac-e2e-helpers.ts +19 -2
- package/src/tests/reload-config.test.ts +26 -0
- package/src/tests/routing-affinity-inventory.test.ts +1 -1
- package/src/tests/runner-attachments-section.test.ts +22 -2
- package/src/tests/runner-context-preamble.test.ts +30 -0
- package/src/tests/runner-deployment-resume.test.ts +107 -0
- package/src/tests/runner-repo-autostash.test.ts +12 -0
- package/src/tests/script-connections.test.ts +4 -0
- package/src/tests/seed-scripts.test.ts +2 -2
- package/src/tests/session-tokens.test.ts +279 -0
- package/src/tests/slack-file-tools-attachments.test.ts +408 -0
- package/src/tests/slack-inbound-files.test.ts +847 -0
- package/src/tests/star-history-refresh.test.ts +102 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +21 -0
- package/src/tests/swarm-repos.test.ts +20 -0
- package/src/tests/tool-annotations.test.ts +4 -3
- package/src/tests/ui-logs-parser.test.ts +176 -0
- package/src/tools/create-page.ts +4 -2
- package/src/tools/defer-task.ts +239 -0
- package/src/tools/repos/update-repo.ts +2 -2
- package/src/tools/schedules/create-schedule.ts +1 -0
- package/src/tools/schedules/list-schedules.ts +1 -0
- package/src/tools/schedules/patch-schedule.ts +1 -0
- package/src/tools/schedules/update-schedule.ts +1 -0
- package/src/tools/slack-download-file.ts +60 -29
- package/src/tools/slack-read.ts +73 -32
- package/src/tools/store-progress.ts +16 -146
- package/src/tools/tool-config.ts +1 -0
- package/src/tools/utils.ts +21 -0
- package/src/types.ts +37 -4
- package/src/utils/acp-session-token.ts +56 -0
- package/src/utils/file-lock.ts +111 -0
- package/src/utils/heartbeat-expiry.ts +78 -0
- package/src/utils/request-auth-context.ts +2 -0
- package/src/utils/task-attachment-links.ts +22 -0
- package/templates/skills/code-quality/content.md +8 -5
- package/templates/skills/download-task-attachment/content.md +2 -1
- package/{plugin/pi-skills → templates/skills}/review-offered-task/SKILL.md +5 -5
- package/templates/skills/review-offered-task/config.json +14 -0
- package/{plugin/commands/review-offered-task.md → templates/skills/review-offered-task/content.md} +3 -8
- package/templates/skills/scheduling/content.md +4 -0
- package/templates/skills/slack-interaction/content.md +2 -2
- package/templates/skills/work-on-task/SKILL.md +16 -0
- package/templates/skills/work-on-task/config.json +14 -0
- package/templates/skills/work-on-task/content.md +11 -0
- package/dist/assistant-0qt42nzg.js +0 -212
- package/dist/cli-fs1kkqgr.js +0 -317
- package/dist/cli-jnf5zghe.js +0 -269
- package/dist/cli-n1q8q14d.js +0 -177
- package/dist/handlers-yfp1qn81.js +0 -592
- package/plugin/commands/work-on-task.md +0 -39
- package/plugin/pi-skills/work-on-task/SKILL.md +0 -39
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- Link a one-off schedule back to the task it continues.
|
|
2
|
+
-- `defer-task` completes the current task and creates a wake-up schedule for
|
|
3
|
+
-- the same agent; the task that schedule creates carries this column as its
|
|
4
|
+
-- `parentTaskId`, so the wake-up run receives the deferred task's context
|
|
5
|
+
-- preamble (src/commands/context-preamble.ts).
|
|
6
|
+
-- Nullable: every schedule created by any other path leaves it NULL.
|
|
7
|
+
ALTER TABLE scheduled_tasks ADD COLUMN parentTaskId TEXT;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
-- Allow SVG images while preserving page IDs, versions, audit fields, and asset keys.
|
|
2
|
+
-- The migration runner disables foreign keys around the transactional rebuild.
|
|
3
|
+
CREATE TABLE pages_new (
|
|
4
|
+
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
|
|
5
|
+
agentId TEXT NOT NULL,
|
|
6
|
+
slug TEXT NOT NULL,
|
|
7
|
+
title TEXT NOT NULL,
|
|
8
|
+
description TEXT,
|
|
9
|
+
contentType TEXT NOT NULL CHECK (contentType IN ('text/html','application/json','image/svg+xml')),
|
|
10
|
+
authMode TEXT NOT NULL DEFAULT 'authed' CHECK (authMode IN ('public','authed','password')),
|
|
11
|
+
passwordHash TEXT,
|
|
12
|
+
body TEXT NOT NULL,
|
|
13
|
+
needsCredentials TEXT,
|
|
14
|
+
createdAt TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
15
|
+
updatedAt TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
16
|
+
view_count INTEGER NOT NULL DEFAULT 0,
|
|
17
|
+
created_by TEXT REFERENCES users(id),
|
|
18
|
+
updated_by TEXT REFERENCES users(id),
|
|
19
|
+
"key" TEXT NOT NULL DEFAULT 'shared/',
|
|
20
|
+
UNIQUE (agentId, slug)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
INSERT INTO pages_new (
|
|
24
|
+
id,
|
|
25
|
+
agentId,
|
|
26
|
+
slug,
|
|
27
|
+
title,
|
|
28
|
+
description,
|
|
29
|
+
contentType,
|
|
30
|
+
authMode,
|
|
31
|
+
passwordHash,
|
|
32
|
+
body,
|
|
33
|
+
needsCredentials,
|
|
34
|
+
createdAt,
|
|
35
|
+
updatedAt,
|
|
36
|
+
view_count,
|
|
37
|
+
created_by,
|
|
38
|
+
updated_by,
|
|
39
|
+
"key"
|
|
40
|
+
)
|
|
41
|
+
SELECT
|
|
42
|
+
id,
|
|
43
|
+
agentId,
|
|
44
|
+
slug,
|
|
45
|
+
title,
|
|
46
|
+
description,
|
|
47
|
+
contentType,
|
|
48
|
+
authMode,
|
|
49
|
+
passwordHash,
|
|
50
|
+
body,
|
|
51
|
+
needsCredentials,
|
|
52
|
+
createdAt,
|
|
53
|
+
updatedAt,
|
|
54
|
+
view_count,
|
|
55
|
+
created_by,
|
|
56
|
+
updated_by,
|
|
57
|
+
"key"
|
|
58
|
+
FROM pages;
|
|
59
|
+
|
|
60
|
+
DROP TABLE pages;
|
|
61
|
+
ALTER TABLE pages_new RENAME TO pages;
|
|
62
|
+
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_pages_agentId ON pages(agentId);
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_pages_updatedAt ON pages(updatedAt DESC);
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_pages_created_by ON pages(created_by) WHERE created_by IS NOT NULL;
|
|
66
|
+
|
|
67
|
+
CREATE INDEX idx_pages_asset_key ON pages("key");
|
|
68
|
+
CREATE TRIGGER validate_pages_asset_key_insert
|
|
69
|
+
BEFORE INSERT ON pages
|
|
70
|
+
WHEN NEW."key" IS NULL
|
|
71
|
+
OR length(NEW."key") = 0
|
|
72
|
+
OR NEW."key" != trim(NEW."key")
|
|
73
|
+
OR length(NEW."key") > 255
|
|
74
|
+
OR substr(NEW."key", -1, 1) != '/'
|
|
75
|
+
OR instr(NEW."key", char(0)) > 0
|
|
76
|
+
OR instr(NEW."key", char(92)) > 0
|
|
77
|
+
OR instr(NEW."key", '//') > 0
|
|
78
|
+
OR instr(NEW."key", '/../') > 0
|
|
79
|
+
OR instr(NEW."key", '/./') > 0
|
|
80
|
+
OR NEW."key" != lower(NEW."key")
|
|
81
|
+
OR NOT (
|
|
82
|
+
NEW."key" = 'shared/'
|
|
83
|
+
OR NEW."key" LIKE 'shared/%'
|
|
84
|
+
OR (
|
|
85
|
+
NEW."key" LIKE 'personal/%/%'
|
|
86
|
+
AND EXISTS (
|
|
87
|
+
SELECT 1 FROM users
|
|
88
|
+
WHERE id = substr(NEW."key", 10, instr(substr(NEW."key", 10), '/') - 1)
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
BEGIN
|
|
93
|
+
SELECT RAISE(ABORT, 'invalid asset namespace key');
|
|
94
|
+
END;
|
|
95
|
+
|
|
96
|
+
CREATE TRIGGER validate_pages_asset_key_update
|
|
97
|
+
BEFORE UPDATE OF "key" ON pages
|
|
98
|
+
WHEN NEW."key" IS NULL
|
|
99
|
+
OR length(NEW."key") = 0
|
|
100
|
+
OR NEW."key" != trim(NEW."key")
|
|
101
|
+
OR length(NEW."key") > 255
|
|
102
|
+
OR substr(NEW."key", -1, 1) != '/'
|
|
103
|
+
OR instr(NEW."key", char(0)) > 0
|
|
104
|
+
OR instr(NEW."key", char(92)) > 0
|
|
105
|
+
OR instr(NEW."key", '//') > 0
|
|
106
|
+
OR instr(NEW."key", '/../') > 0
|
|
107
|
+
OR instr(NEW."key", '/./') > 0
|
|
108
|
+
OR NEW."key" != lower(NEW."key")
|
|
109
|
+
OR NOT (
|
|
110
|
+
NEW."key" = 'shared/'
|
|
111
|
+
OR NEW."key" LIKE 'shared/%'
|
|
112
|
+
OR (
|
|
113
|
+
NEW."key" LIKE 'personal/%/%'
|
|
114
|
+
AND EXISTS (
|
|
115
|
+
SELECT 1 FROM users
|
|
116
|
+
WHERE id = substr(NEW."key", 10, instr(substr(NEW."key", 10), '/') - 1)
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
BEGIN
|
|
121
|
+
SELECT RAISE(ABORT, 'invalid asset namespace key');
|
|
122
|
+
END;
|
|
123
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- Session-scoped ephemeral bearer tokens (prefix: aseph_) minted per ACP
|
|
2
|
+
-- provider session. The ACP adapter hands this token to the target process
|
|
3
|
+
-- in the swarm MCP server's Authorization header instead of the full operator
|
|
4
|
+
-- key. The token is revoked when the session ends (finish / abort) and also
|
|
5
|
+
-- carries an expiresAt ceiling so a leaked bearer cannot be used indefinitely.
|
|
6
|
+
--
|
|
7
|
+
-- Schema mirrors user_tokens but is separate so the two lifecycles cannot
|
|
8
|
+
-- interfere: user tokens are long-lived and manually revoked; session tokens
|
|
9
|
+
-- are programmatically minted and revoked, and always carry expiresAt.
|
|
10
|
+
|
|
11
|
+
CREATE TABLE IF NOT EXISTS session_tokens (
|
|
12
|
+
id TEXT PRIMARY KEY,
|
|
13
|
+
tokenHash TEXT NOT NULL UNIQUE,
|
|
14
|
+
tokenPreview TEXT NOT NULL,
|
|
15
|
+
agentId TEXT NOT NULL,
|
|
16
|
+
taskId TEXT NOT NULL,
|
|
17
|
+
expiresAt TEXT NOT NULL,
|
|
18
|
+
revokedAt TEXT,
|
|
19
|
+
createdAt TEXT NOT NULL DEFAULT (datetime('now')),
|
|
20
|
+
lastUsedAt TEXT
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_session_tokens_agentId
|
|
24
|
+
ON session_tokens(agentId);
|
|
@@ -138,6 +138,7 @@ export interface SwarmSdk {
|
|
|
138
138
|
task_list(args?: Record<string, unknown>): Promise<unknown>;
|
|
139
139
|
task_get(args: { taskId: string }): Promise<unknown>;
|
|
140
140
|
task_storeProgress(args: Record<string, unknown>): Promise<unknown>;
|
|
141
|
+
task_defer(args: { taskId: string; delayMs?: number; runAt?: string; summary: string; note: string; checks?: string[] }): Promise<unknown>;
|
|
141
142
|
task_poll(args?: Record<string, unknown>): Promise<unknown>;
|
|
142
143
|
// --- kv ---
|
|
143
144
|
kv_get<T = unknown>(args: { key: string; namespace?: string }): Promise<KvSdkResponse<KvEntry<T>>>;
|
package/src/be/seed-pricing.ts
CHANGED
|
@@ -261,6 +261,18 @@ export function buildModelsDevSeedRows(cache: ModelsDevCache): PricingSeedRow[]
|
|
|
261
261
|
return rows;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
/** Build the exact provider rows inserted by the boot-time pricing seeder. */
|
|
265
|
+
export function buildPricingSeedRows(cache: ModelsDevCache | null): PricingSeedRow[] {
|
|
266
|
+
const modelsdevRows = cache ? buildModelsDevSeedRows(cache) : [];
|
|
267
|
+
const manualRows = MANUAL_PRICING_OVERRIDES.map((override) => ({
|
|
268
|
+
provider: override.provider,
|
|
269
|
+
model: override.model,
|
|
270
|
+
tokenClass: override.tokenClass,
|
|
271
|
+
pricePerMillionUsd: override.pricePerMillionUsd,
|
|
272
|
+
}));
|
|
273
|
+
return [...modelsdevRows, ...manualRows];
|
|
274
|
+
}
|
|
275
|
+
|
|
264
276
|
/**
|
|
265
277
|
* Phase 2 entrypoint. Idempotent — safe to call on every boot. Logs a one-line
|
|
266
278
|
* summary so operators can tell whether the boot picked up new rates.
|
|
@@ -271,14 +283,7 @@ export function seedPricingFromModelsDev(opts?: { quiet?: boolean }): {
|
|
|
271
283
|
} {
|
|
272
284
|
const db = getDb();
|
|
273
285
|
const cache = loadModelsDevCache();
|
|
274
|
-
const
|
|
275
|
-
const manualRows = MANUAL_PRICING_OVERRIDES.map((o) => ({
|
|
276
|
-
provider: o.provider,
|
|
277
|
-
model: o.model,
|
|
278
|
-
tokenClass: o.tokenClass,
|
|
279
|
-
pricePerMillionUsd: o.pricePerMillionUsd,
|
|
280
|
-
}));
|
|
281
|
-
const allRows = [...modelsdevRows, ...manualRows];
|
|
286
|
+
const allRows = buildPricingSeedRows(cache);
|
|
282
287
|
|
|
283
288
|
const insert = db.prepare<null, [string, string, string, number]>(
|
|
284
289
|
`INSERT OR IGNORE INTO pricing
|
|
@@ -38,7 +38,7 @@ const CONTRADICTORY_RE =
|
|
|
38
38
|
/\b(do not|don't|never)\b[\s\S]{0,240}\b(always|must|required)\b|\b(always|must|required)\b[\s\S]{0,240}\b(do not|don't|never)\b/i;
|
|
39
39
|
|
|
40
40
|
const CODE_REGISTRY_EVENTS =
|
|
41
|
-
"agentmail.email.followup agentmail.email.mapped_lead agentmail.email.mapped_worker agentmail.email.no_agent agentmail.email.unmapped common.command_suggestions.github_comment_issue common.command_suggestions.github_comment_pr common.command_suggestions.github_issue common.command_suggestions.github_pr common.command_suggestions.gitlab_issue common.command_suggestions.gitlab_mr common.delegation_instruction common.delegation_instruction.gitlab github.check_run.failed github.check_suite.failed github.comment.mentioned github.issue.assigned github.issue.labeled github.issue.mentioned github.pull_request.assigned github.pull_request.closed github.pull_request.labeled github.pull_request.mentioned github.pull_request.review_requested github.pull_request.review_submitted github.pull_request.synchronize github.workflow_run.failed gitlab.comment.mentioned gitlab.issue.assigned gitlab.merge_request.opened gitlab.pipeline.failed heartbeat.boot-triage heartbeat.checklist jira.issue.assigned jira.issue.commented jira.issue.followup kapso.message.received linear.issue.assigned linear.issue.followup linear.issue.reassigned slack.assistant.greeting slack.assistant.offline slack.assistant.suggested_prompts slack.message.thread_context system.agent.communication system.agent.lead system.agent.memory system.agent.memory.remote system.agent.outputs system.agent.outputs.no_agent_fs system.agent.repository system.agent.role system.agent.secrets system.agent.slack system.agent.tools_skills system.agent.worker system.agent.worker.remote system.agent.workspace system.agent.workspace.remote system.session.lead system.session.lead.managed system.session.worker system.session.worker.managed system.session.worker.remote task.budget.refused task.requester.profile task.worker.completed task.worker.failed".split(
|
|
41
|
+
"agentmail.email.followup agentmail.email.mapped_lead agentmail.email.mapped_worker agentmail.email.no_agent agentmail.email.unmapped common.command_suggestions.github_comment_issue common.command_suggestions.github_comment_pr common.command_suggestions.github_issue common.command_suggestions.github_pr common.command_suggestions.gitlab_issue common.command_suggestions.gitlab_mr common.delegation_instruction common.delegation_instruction.gitlab github.check_run.failed github.check_suite.failed github.comment.mentioned github.issue.assigned github.issue.labeled github.issue.mentioned github.pull_request.assigned github.pull_request.closed github.pull_request.labeled github.pull_request.mentioned github.pull_request.review_requested github.pull_request.review_submitted github.pull_request.synchronize github.workflow_run.failed gitlab.comment.mentioned gitlab.issue.assigned gitlab.merge_request.opened gitlab.pipeline.failed heartbeat.boot-triage heartbeat.checklist jira.issue.assigned jira.issue.commented jira.issue.followup kapso.message.received linear.issue.assigned linear.issue.followup linear.issue.reassigned slack.assistant.greeting slack.assistant.offline slack.assistant.suggested_prompts slack.message.attachment_failed slack.message.thread_context system.agent.communication system.agent.lead system.agent.memory system.agent.memory.remote system.agent.outputs system.agent.outputs.no_agent_fs system.agent.repository system.agent.role system.agent.secrets system.agent.slack system.agent.tools_skills system.agent.worker system.agent.worker.remote system.agent.workspace system.agent.workspace.remote system.session.lead system.session.lead.managed system.session.worker system.session.worker.managed system.session.worker.remote task.budget.refused task.requester.profile task.worker.completed task.worker.failed".split(
|
|
42
42
|
" ",
|
|
43
43
|
);
|
|
44
44
|
|
|
@@ -38,7 +38,7 @@ const CONTRADICTORY_RE =
|
|
|
38
38
|
/\b(do not|don't|never)\b[\s\S]{0,240}\b(always|must|required)\b|\b(always|must|required)\b[\s\S]{0,240}\b(do not|don't|never)\b/i;
|
|
39
39
|
|
|
40
40
|
const CODE_REGISTRY_EVENTS =
|
|
41
|
-
"agentmail.email.followup agentmail.email.mapped_lead agentmail.email.mapped_worker agentmail.email.no_agent agentmail.email.unmapped common.command_suggestions.github_comment_issue common.command_suggestions.github_comment_pr common.command_suggestions.github_issue common.command_suggestions.github_pr common.command_suggestions.gitlab_issue common.command_suggestions.gitlab_mr common.delegation_instruction common.delegation_instruction.gitlab github.check_run.failed github.check_suite.failed github.comment.mentioned github.issue.assigned github.issue.labeled github.issue.mentioned github.pull_request.assigned github.pull_request.closed github.pull_request.labeled github.pull_request.mentioned github.pull_request.review_requested github.pull_request.review_submitted github.pull_request.synchronize github.workflow_run.failed gitlab.comment.mentioned gitlab.issue.assigned gitlab.merge_request.opened gitlab.pipeline.failed heartbeat.boot-triage heartbeat.checklist jira.issue.assigned jira.issue.commented jira.issue.followup kapso.message.received linear.issue.assigned linear.issue.followup linear.issue.reassigned slack.assistant.greeting slack.assistant.offline slack.assistant.suggested_prompts slack.message.thread_context system.agent.communication system.agent.lead system.agent.memory system.agent.memory.remote system.agent.outputs system.agent.outputs.no_agent_fs system.agent.repository system.agent.role system.agent.secrets system.agent.slack system.agent.tools_skills system.agent.worker system.agent.worker.remote system.agent.workspace system.agent.workspace.remote system.session.lead system.session.lead.managed system.session.worker system.session.worker.managed system.session.worker.remote task.budget.refused task.requester.profile task.worker.completed task.worker.failed".split(
|
|
41
|
+
"agentmail.email.followup agentmail.email.mapped_lead agentmail.email.mapped_worker agentmail.email.no_agent agentmail.email.unmapped common.command_suggestions.github_comment_issue common.command_suggestions.github_comment_pr common.command_suggestions.github_issue common.command_suggestions.github_pr common.command_suggestions.gitlab_issue common.command_suggestions.gitlab_mr common.delegation_instruction common.delegation_instruction.gitlab github.check_run.failed github.check_suite.failed github.comment.mentioned github.issue.assigned github.issue.labeled github.issue.mentioned github.pull_request.assigned github.pull_request.closed github.pull_request.labeled github.pull_request.mentioned github.pull_request.review_requested github.pull_request.review_submitted github.pull_request.synchronize github.workflow_run.failed gitlab.comment.mentioned gitlab.issue.assigned gitlab.merge_request.opened gitlab.pipeline.failed heartbeat.boot-triage heartbeat.checklist jira.issue.assigned jira.issue.commented jira.issue.followup kapso.message.received linear.issue.assigned linear.issue.followup linear.issue.reassigned slack.assistant.greeting slack.assistant.offline slack.assistant.suggested_prompts slack.message.attachment_failed slack.message.thread_context system.agent.communication system.agent.lead system.agent.memory system.agent.memory.remote system.agent.outputs system.agent.outputs.no_agent_fs system.agent.repository system.agent.role system.agent.secrets system.agent.slack system.agent.tools_skills system.agent.worker system.agent.worker.remote system.agent.workspace system.agent.workspace.remote system.session.lead system.session.lead.managed system.session.worker system.session.worker.managed system.session.worker.remote task.budget.refused task.requester.profile task.worker.completed task.worker.failed".split(
|
|
42
42
|
" ",
|
|
43
43
|
);
|
|
44
44
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { ScriptContext } from "swarm-sdk";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { renderChart } from "./star-history-renderer";
|
|
4
|
+
|
|
5
|
+
export const argsSchema = z.object({
|
|
6
|
+
dryRun: z.boolean().default(false),
|
|
7
|
+
authenticated: z.boolean().default(true),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const repository = "desplega-ai/agent-swarm";
|
|
11
|
+
const namespace = "star-history:desplega-ai/agent-swarm";
|
|
12
|
+
const cacheSchema = z.object({
|
|
13
|
+
fetchedAt: z.string(),
|
|
14
|
+
pages: z.array(z.object({ etag: z.string().nullable(), timestamps: z.array(z.number().finite()) })),
|
|
15
|
+
});
|
|
16
|
+
type Cache = z.infer<typeof cacheSchema>;
|
|
17
|
+
|
|
18
|
+
/** Refresh the light and dark star-history images, retaining the last-known series on GitHub failure. */
|
|
19
|
+
export default async function main(args: z.input<typeof argsSchema>, ctx: ScriptContext) {
|
|
20
|
+
const options = argsSchema.parse(args ?? {});
|
|
21
|
+
const entry = await ctx.swarm.kv_getOrNull({ namespace, key: "series" });
|
|
22
|
+
const parsed = cacheSchema.safeParse(entry?.value);
|
|
23
|
+
const cached = parsed.success ? parsed.data : undefined;
|
|
24
|
+
let series: Cache;
|
|
25
|
+
let stale = false;
|
|
26
|
+
let fetchError: string | undefined;
|
|
27
|
+
let requests = 0;
|
|
28
|
+
let notModified = 0;
|
|
29
|
+
try {
|
|
30
|
+
const pages: Cache["pages"] = [];
|
|
31
|
+
const deadline = Date.now() + 12000;
|
|
32
|
+
// Bound the job so a pagination error cannot consume the entire API budget.
|
|
33
|
+
for (let page = 1; page <= 50; page++) {
|
|
34
|
+
if (Date.now() > deadline) throw new Error("GitHub refresh budget exhausted");
|
|
35
|
+
const previous = cached?.pages[page - 1];
|
|
36
|
+
const headers: Record<string, string> = {
|
|
37
|
+
Accept: "application/vnd.github.star+json",
|
|
38
|
+
"User-Agent": "agent-swarm-star-history-generator",
|
|
39
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
40
|
+
};
|
|
41
|
+
if (options.authenticated) headers.Authorization = "Bearer [REDACTED:GITHUB_TOKEN]";
|
|
42
|
+
if (previous?.etag) headers["If-None-Match"] = previous.etag;
|
|
43
|
+
requests++;
|
|
44
|
+
const response = await ctx.stdlib.fetch(
|
|
45
|
+
`https://api.github.com/repos/${repository}/stargazers?per_page=100&page=${page}`,
|
|
46
|
+
{ headers, signal: AbortSignal.timeout(1500) },
|
|
47
|
+
);
|
|
48
|
+
let current: Cache["pages"][number];
|
|
49
|
+
if (response.status === 304 && previous) {
|
|
50
|
+
current = previous;
|
|
51
|
+
notModified++;
|
|
52
|
+
} else {
|
|
53
|
+
if (!response.ok) throw new Error(`GitHub stargazers HTTP ${response.status}`);
|
|
54
|
+
const rows = z.array(z.object({ starred_at: z.string() })).parse(await response.json());
|
|
55
|
+
const timestamps = rows.map((row) => Date.parse(row.starred_at));
|
|
56
|
+
if (timestamps.some((timestamp) => !Number.isFinite(timestamp))) {
|
|
57
|
+
throw new Error("GitHub returned invalid star timestamps");
|
|
58
|
+
}
|
|
59
|
+
current = { etag: response.headers.get("etag"), timestamps };
|
|
60
|
+
}
|
|
61
|
+
pages.push(current);
|
|
62
|
+
if (current.timestamps.length < 100) break;
|
|
63
|
+
if (page === 50) throw new Error("Stargazer pagination exceeded 50 pages");
|
|
64
|
+
}
|
|
65
|
+
if (!pages.some((page) => page.timestamps.length)) throw new Error("No stargazers returned");
|
|
66
|
+
series = { fetchedAt: new Date().toISOString(), pages };
|
|
67
|
+
await ctx.swarm.kv_set({ namespace, key: "series", value: series });
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (!cached?.pages.some((page) => page.timestamps.length)) {
|
|
70
|
+
throw new Error("GitHub fetch failed and no cached series exists; no pages published");
|
|
71
|
+
}
|
|
72
|
+
series = cached;
|
|
73
|
+
stale = true;
|
|
74
|
+
// Avoid transporting fetch exception text, which may include request details.
|
|
75
|
+
fetchError = error instanceof Error && error.message.startsWith("GitHub stargazers HTTP")
|
|
76
|
+
? error.message : "GitHub refresh failed; using last-known series";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const timestamps = series.pages.flatMap((page) => page.timestamps).sort((a, b) => a - b);
|
|
80
|
+
const pages = [];
|
|
81
|
+
for (const theme of ["light", "dark"] as const) {
|
|
82
|
+
const body = renderChart(repository, timestamps, theme);
|
|
83
|
+
const slug = `star-history-${theme}`;
|
|
84
|
+
if (options.dryRun) {
|
|
85
|
+
pages.push({ slug, bytes: new TextEncoder().encode(body).length });
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const response = await ctx.swarm.page_create({
|
|
89
|
+
slug, title: `Star history (${theme})`, body,
|
|
90
|
+
description: `GitHub stars for ${repository}; fetched ${series.fetchedAt}`,
|
|
91
|
+
contentType: "image/svg+xml", authMode: "public",
|
|
92
|
+
}) as { data?: { id?: string; api_url?: string }; id?: string; api_url?: string };
|
|
93
|
+
const page = response.data ?? response;
|
|
94
|
+
if (!page.id || !page.api_url) throw new Error(`Failed to publish ${slug}`);
|
|
95
|
+
pages.push({ slug, id: page.id, apiUrl: page.api_url });
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
repository, stars: timestamps.length, fetchedAt: series.fetchedAt, stale, fetchError,
|
|
99
|
+
authenticated: options.authenticated, requests, notModified, dryRun: options.dryRun, pages,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const themes = {
|
|
2
|
+
light: {
|
|
3
|
+
background: "#ffffff",
|
|
4
|
+
border: "#e5e7eb",
|
|
5
|
+
grid: "#e5e7eb",
|
|
6
|
+
text: "#111827",
|
|
7
|
+
muted: "#6b7280",
|
|
8
|
+
accent: "#f59e0b",
|
|
9
|
+
},
|
|
10
|
+
dark: {
|
|
11
|
+
background: "#0d1117",
|
|
12
|
+
border: "#30363d",
|
|
13
|
+
grid: "#21262d",
|
|
14
|
+
text: "#f0f6fc",
|
|
15
|
+
muted: "#8b949e",
|
|
16
|
+
accent: "#f59e0b",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function escapeXml(value: string) {
|
|
21
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function niceStep(maximum: number, targetTickCount = 6) {
|
|
25
|
+
const roughStep = maximum / targetTickCount;
|
|
26
|
+
const power = 10 ** Math.floor(Math.log10(roughStep));
|
|
27
|
+
const normalized = roughStep / power;
|
|
28
|
+
const multiplier = normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10;
|
|
29
|
+
return multiplier * power;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function renderChart(repository: string, timestamps: number[], themeName: keyof typeof themes) {
|
|
33
|
+
const theme = themes[themeName];
|
|
34
|
+
const width = 960;
|
|
35
|
+
const height = 520;
|
|
36
|
+
const margin = { top: 96, right: 34, bottom: 62, left: 76 };
|
|
37
|
+
const plotWidth = width - margin.left - margin.right;
|
|
38
|
+
const plotHeight = height - margin.top - margin.bottom;
|
|
39
|
+
const firstStar = timestamps[0]!;
|
|
40
|
+
const lastStar = timestamps.at(-1)!;
|
|
41
|
+
const timeRange = Math.max(lastStar - firstStar, 1);
|
|
42
|
+
const yStep = niceStep(timestamps.length);
|
|
43
|
+
const yMaximum = Math.ceil(timestamps.length / yStep) * yStep;
|
|
44
|
+
const plotBottom = margin.top + plotHeight;
|
|
45
|
+
|
|
46
|
+
const x = (timestamp: number) => margin.left + ((timestamp - firstStar) / timeRange) * plotWidth;
|
|
47
|
+
const y = (stars: number) => margin.top + plotHeight - (stars / yMaximum) * plotHeight;
|
|
48
|
+
|
|
49
|
+
const points = timestamps.map((timestamp, index) => ({
|
|
50
|
+
x: x(timestamp),
|
|
51
|
+
y: y(index + 1),
|
|
52
|
+
}));
|
|
53
|
+
const linePath = points
|
|
54
|
+
.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x.toFixed(1)} ${point.y.toFixed(1)}`)
|
|
55
|
+
.join(" ");
|
|
56
|
+
const areaPath = `M ${points[0]!.x.toFixed(1)} ${plotBottom.toFixed(1)} ${linePath.replace(/^M/, "L")} L ${points.at(-1)!.x.toFixed(1)} ${plotBottom.toFixed(1)} Z`;
|
|
57
|
+
|
|
58
|
+
const yTicks = [];
|
|
59
|
+
for (let stars = 0; stars <= yMaximum; stars += yStep) {
|
|
60
|
+
const tickY = y(stars);
|
|
61
|
+
yTicks.push(`
|
|
62
|
+
<line x1="${margin.left}" y1="${tickY.toFixed(1)}" x2="${width - margin.right}" y2="${tickY.toFixed(1)}" stroke="${theme.grid}" />
|
|
63
|
+
<text x="${margin.left - 14}" y="${(tickY + 5).toFixed(1)}" text-anchor="end" fill="${theme.muted}" font-size="13">${stars}</text>`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const dateFormatter = new Intl.DateTimeFormat("en-US", {
|
|
67
|
+
month: "short",
|
|
68
|
+
year: "numeric",
|
|
69
|
+
timeZone: "UTC",
|
|
70
|
+
});
|
|
71
|
+
const updatedFormatter = new Intl.DateTimeFormat("en-US", {
|
|
72
|
+
day: "numeric",
|
|
73
|
+
month: "short",
|
|
74
|
+
year: "numeric",
|
|
75
|
+
timeZone: "UTC",
|
|
76
|
+
});
|
|
77
|
+
const xTicks = Array.from({ length: 7 }, (_, index) => {
|
|
78
|
+
const fraction = index / 6;
|
|
79
|
+
const timestamp = firstStar + timeRange * fraction;
|
|
80
|
+
const tickX = margin.left + plotWidth * fraction;
|
|
81
|
+
return `
|
|
82
|
+
<line x1="${tickX.toFixed(1)}" y1="${margin.top}" x2="${tickX.toFixed(1)}" y2="${plotBottom}" stroke="${theme.grid}" />
|
|
83
|
+
<text x="${tickX.toFixed(1)}" y="${plotBottom + 30}" text-anchor="middle" fill="${theme.muted}" font-size="13">${dateFormatter.format(timestamp)}</text>`;
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const escapedRepository = escapeXml(repository);
|
|
87
|
+
const lastPoint = points.at(-1)!;
|
|
88
|
+
|
|
89
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="960" height="520" viewBox="0 0 960 520" role="img" aria-labelledby="title description">
|
|
90
|
+
<title id="title">Star history for ${escapedRepository}</title>
|
|
91
|
+
<desc id="description">${timestamps.length} cumulative GitHub stars from ${updatedFormatter.format(firstStar)} through ${updatedFormatter.format(lastStar)}.</desc>
|
|
92
|
+
<defs>
|
|
93
|
+
<linearGradient id="star-area" x1="0" y1="0" x2="0" y2="1">
|
|
94
|
+
<stop offset="0%" stop-color="${theme.accent}" stop-opacity="0.24" />
|
|
95
|
+
<stop offset="100%" stop-color="${theme.accent}" stop-opacity="0.02" />
|
|
96
|
+
</linearGradient>
|
|
97
|
+
<filter id="point-shadow" x="-100%" y="-100%" width="300%" height="300%">
|
|
98
|
+
<feDropShadow dx="0" dy="1" stdDeviation="2" flood-color="${theme.accent}" flood-opacity="0.35" />
|
|
99
|
+
</filter>
|
|
100
|
+
</defs>
|
|
101
|
+
<rect x="0.5" y="0.5" width="959" height="519" rx="12" fill="${theme.background}" stroke="${theme.border}" />
|
|
102
|
+
<g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif">
|
|
103
|
+
<text x="${margin.left}" y="43" fill="${theme.text}" font-size="21" font-weight="600">${escapedRepository}</text>
|
|
104
|
+
<text x="${margin.left}" y="69" fill="${theme.muted}" font-size="13">Cumulative GitHub stars · updated ${updatedFormatter.format(lastStar)}</text>
|
|
105
|
+
<g transform="translate(${width - margin.right - 118}, 34)">
|
|
106
|
+
<text x="0" y="17" fill="${theme.accent}" font-size="19">★</text>
|
|
107
|
+
<text x="27" y="17" fill="${theme.text}" font-size="16" font-weight="600">${timestamps.length} stars</text>
|
|
108
|
+
</g>
|
|
109
|
+
${yTicks.join("").trim()}
|
|
110
|
+
${xTicks.join("").trim()}
|
|
111
|
+
<path d="${areaPath}" fill="url(#star-area)" />
|
|
112
|
+
<path d="${linePath}" fill="none" stroke="${theme.accent}" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />
|
|
113
|
+
<circle cx="${lastPoint.x.toFixed(1)}" cy="${lastPoint.y.toFixed(1)}" r="5" fill="${theme.background}" stroke="${theme.accent}" stroke-width="3" filter="url(#point-shadow)" />
|
|
114
|
+
<text x="20" y="${margin.top + plotHeight / 2}" transform="rotate(-90 20 ${margin.top + plotHeight / 2})" text-anchor="middle" fill="${theme.muted}" font-size="13">GitHub stars</text>
|
|
115
|
+
</g>
|
|
116
|
+
</svg>
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
|
|
@@ -44,6 +44,9 @@ import reportProgressSrc from "./catalog/report-progress.ts" with { type: "text"
|
|
|
44
44
|
import scheduleHealthSrc from "./catalog/schedule-health.ts" with { type: "text" };
|
|
45
45
|
import slackThreadFlattenSrc from "./catalog/slack-thread-flatten.ts" with { type: "text" };
|
|
46
46
|
import smartRecallSrc from "./catalog/smart-recall.ts" with { type: "text" };
|
|
47
|
+
import starHistoryRefreshSrc from "./catalog/star-history-refresh.ts" with { type: "text" };
|
|
48
|
+
// @ts-expect-error Bun text imports synthesize a default string for this helper.
|
|
49
|
+
import starHistoryRendererSrc from "./catalog/star-history-renderer.ts" with { type: "text" };
|
|
47
50
|
import swarmOverviewSrc from "./catalog/swarm-overview.ts" with { type: "text" };
|
|
48
51
|
import taskContextGatheringSrc from "./catalog/task-context-gathering.ts" with { type: "text" };
|
|
49
52
|
import taskFailureAuditSrc from "./catalog/task-failure-audit.ts" with { type: "text" };
|
|
@@ -71,6 +74,20 @@ function bundleCatalogReport(source: string): string {
|
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
export const SEED_SCRIPTS: SeedScript[] = [
|
|
77
|
+
{
|
|
78
|
+
name: "star-history-refresh",
|
|
79
|
+
description:
|
|
80
|
+
"Refresh stable public light/dark SVG star-history pages from GitHub with ETags and a last-known KV series.",
|
|
81
|
+
intent:
|
|
82
|
+
"Run hourly under the same page-owning agent identity; dryRun validates rendering before SVG page support deploys.",
|
|
83
|
+
source:
|
|
84
|
+
asText(starHistoryRendererSrc) +
|
|
85
|
+
"\n" +
|
|
86
|
+
asText(starHistoryRefreshSrc).replace(
|
|
87
|
+
'import { renderChart } from "./star-history-renderer";',
|
|
88
|
+
"",
|
|
89
|
+
),
|
|
90
|
+
},
|
|
74
91
|
{
|
|
75
92
|
name: "gh-pr-snapshot",
|
|
76
93
|
description:
|
|
@@ -154,6 +154,12 @@ import researchingConfig from "../../../templates/skills/researching/config.json
|
|
|
154
154
|
import researchingContent from "../../../templates/skills/researching/content.md" with {
|
|
155
155
|
type: "text",
|
|
156
156
|
};
|
|
157
|
+
import reviewOfferedTaskConfig from "../../../templates/skills/review-offered-task/config.json" with {
|
|
158
|
+
type: "text",
|
|
159
|
+
};
|
|
160
|
+
import reviewOfferedTaskContent from "../../../templates/skills/review-offered-task/content.md" with {
|
|
161
|
+
type: "text",
|
|
162
|
+
};
|
|
157
163
|
import reviewingConfig from "../../../templates/skills/reviewing/config.json" with { type: "text" };
|
|
158
164
|
import reviewingContent from "../../../templates/skills/reviewing/content.md" with { type: "text" };
|
|
159
165
|
import scheduledTaskResilienceConfig from "../../../templates/skills/scheduled-task-resilience/config.json" with {
|
|
@@ -230,6 +236,12 @@ import vPlanningContent from "../../../templates/skills/v-planning/content.md" w
|
|
|
230
236
|
};
|
|
231
237
|
import verifyingConfig from "../../../templates/skills/verifying/config.json" with { type: "text" };
|
|
232
238
|
import verifyingContent from "../../../templates/skills/verifying/content.md" with { type: "text" };
|
|
239
|
+
import workOnTaskConfig from "../../../templates/skills/work-on-task/config.json" with {
|
|
240
|
+
type: "text",
|
|
241
|
+
};
|
|
242
|
+
import workOnTaskContent from "../../../templates/skills/work-on-task/content.md" with {
|
|
243
|
+
type: "text",
|
|
244
|
+
};
|
|
233
245
|
import workflowIterateConfig from "../../../templates/skills/workflow-iterate/config.json" with {
|
|
234
246
|
type: "text",
|
|
235
247
|
};
|
|
@@ -328,6 +340,7 @@ const BUILT_IN_SKILL_SOURCES = [
|
|
|
328
340
|
{ config: qaConfig, body: qaContent },
|
|
329
341
|
{ config: questioningConfig, body: questioningContent },
|
|
330
342
|
{ config: researchingConfig, body: researchingContent },
|
|
343
|
+
{ config: reviewOfferedTaskConfig, body: reviewOfferedTaskContent },
|
|
331
344
|
{ config: reviewingConfig, body: reviewingContent },
|
|
332
345
|
{ config: scheduledTaskResilienceConfig, body: scheduledTaskResilienceContent },
|
|
333
346
|
{ config: schedulingConfig, body: schedulingContent },
|
|
@@ -342,6 +355,7 @@ const BUILT_IN_SKILL_SOURCES = [
|
|
|
342
355
|
{ config: vImplementingConfig, body: vImplementingContent },
|
|
343
356
|
{ config: vPlanningConfig, body: vPlanningContent },
|
|
344
357
|
{ config: verifyingConfig, body: verifyingContent },
|
|
358
|
+
{ config: workOnTaskConfig, body: workOnTaskContent },
|
|
345
359
|
{ config: workflowIterateConfig, body: workflowIterateContent },
|
|
346
360
|
{ config: workflowStructuredOutputConfig, body: workflowStructuredOutputContent },
|
|
347
361
|
{ config: wtsExpertConfig, body: wtsExpertContent },
|
|
@@ -11,10 +11,13 @@ import { ProviderNameSchema } from "../types";
|
|
|
11
11
|
* - `SECRETS_ENCRYPTION_KEY` is required to decrypt secrets stored in
|
|
12
12
|
* swarm_config, so it cannot itself be stored encrypted there.
|
|
13
13
|
*
|
|
14
|
+
* `CORS_ALLOW_ANY_ORIGIN` is deployment-only: runtime config must not
|
|
15
|
+
* re-enable unrestricted credentialed CORS.
|
|
16
|
+
*
|
|
14
17
|
* Matching is case-insensitive so `api_key`, `Api_Key`, etc. are all
|
|
15
18
|
* rejected at every write path (DB helpers, HTTP routes, MCP tools).
|
|
16
19
|
*/
|
|
17
|
-
const RESERVED_KEYS = new Set(["API_KEY", "SECRETS_ENCRYPTION_KEY"]);
|
|
20
|
+
const RESERVED_KEYS = new Set(["API_KEY", "SECRETS_ENCRYPTION_KEY", "CORS_ALLOW_ANY_ORIGIN"]);
|
|
18
21
|
|
|
19
22
|
export function isReservedConfigKey(key: string): boolean {
|
|
20
23
|
return RESERVED_KEYS.has(key.toUpperCase());
|
|
@@ -223,7 +226,7 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
|
|
|
223
226
|
},
|
|
224
227
|
// AWS credential mode for the Bedrock path on the pi harness.
|
|
225
228
|
// sdk — AWS SDK default credential chain (env, ~/.aws/*, SSO, IMDS, …)
|
|
226
|
-
// bearer — explicit
|
|
229
|
+
// bearer — explicit Bedrock API key via AWS_BEARER_TOKEN_BEDROCK (required in this mode)
|
|
227
230
|
// When absent the worker infers the mode from MODEL_OVERRIDE (sdk semantics).
|
|
228
231
|
BEDROCK_AUTH_MODE: (value) => {
|
|
229
232
|
if (value === "sdk" || value === "bearer") return null;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { FileObject, FileScope, FileStorageProvider } from "../fs/provider";
|
|
2
|
+
import type { TaskAttachment } from "../types";
|
|
3
|
+
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
4
|
+
import { insertTaskAttachment } from "./db";
|
|
5
|
+
|
|
6
|
+
/** Per-file cap for every path that stores a blob as a task attachment. */
|
|
7
|
+
export const MAX_TASK_ATTACHMENT_BYTES = 50 * 1024 * 1024;
|
|
8
|
+
|
|
9
|
+
export type RecordTaskAttachmentUploadInput = {
|
|
10
|
+
provider: FileStorageProvider;
|
|
11
|
+
scope: FileScope;
|
|
12
|
+
/** What `provider.upload(scope, body, …)` returned. */
|
|
13
|
+
uploaded: FileObject;
|
|
14
|
+
/** Size and sha256 of the body that was uploaded. */
|
|
15
|
+
sizeBytes: number;
|
|
16
|
+
sha256: string;
|
|
17
|
+
contentType: string;
|
|
18
|
+
agentId: string | null;
|
|
19
|
+
intent?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
isPrimary?: boolean;
|
|
22
|
+
createdBy?: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Record a blob the active provider just stored as a `task_attachments` row.
|
|
27
|
+
* If the row can't be written the blob is deleted, so a failed insert never
|
|
28
|
+
* leaves an orphan in storage, and the insert error is rethrown.
|
|
29
|
+
*/
|
|
30
|
+
export async function recordTaskAttachmentUpload(
|
|
31
|
+
input: RecordTaskAttachmentUploadInput,
|
|
32
|
+
): Promise<TaskAttachment> {
|
|
33
|
+
const { provider, scope, uploaded, contentType } = input;
|
|
34
|
+
try {
|
|
35
|
+
return await insertTaskAttachment({
|
|
36
|
+
taskId: scope.taskId,
|
|
37
|
+
agentId: input.agentId,
|
|
38
|
+
name: scope.name,
|
|
39
|
+
kind: provider.id === "agent-fs" ? "agent-fs" : "shared-fs",
|
|
40
|
+
path: uploaded.key,
|
|
41
|
+
providerId: provider.id,
|
|
42
|
+
providerKey: uploaded.key,
|
|
43
|
+
capabilities: {
|
|
44
|
+
...provider.capabilities,
|
|
45
|
+
version: uploaded.version,
|
|
46
|
+
etag: uploaded.etag,
|
|
47
|
+
},
|
|
48
|
+
mimeType: uploaded.contentType ?? contentType,
|
|
49
|
+
sizeBytes: uploaded.sizeBytes ?? input.sizeBytes,
|
|
50
|
+
sha256: uploaded.sha256 ?? input.sha256,
|
|
51
|
+
intent: input.intent,
|
|
52
|
+
description: input.description,
|
|
53
|
+
isPrimary: input.isPrimary ?? false,
|
|
54
|
+
createdBy: input.createdBy,
|
|
55
|
+
});
|
|
56
|
+
} catch (error) {
|
|
57
|
+
try {
|
|
58
|
+
await provider.delete(scope);
|
|
59
|
+
} catch (cleanupError) {
|
|
60
|
+
console.warn(
|
|
61
|
+
scrubSecrets(
|
|
62
|
+
`[fs] upload metadata insert failed and blob cleanup failed: ${
|
|
63
|
+
cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
64
|
+
}`,
|
|
65
|
+
),
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|