@coreplane/switchboard 1.239.0 → 1.241.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/dist/assets/config/config.example.yaml +32 -7
- package/dist/assets/deploy/cloudflare/worker.ts +77 -18
- package/dist/assets/deploy/cloudflare-memory/worker.ts +115 -1
- package/dist/assets/deploy/cloudflare-memory/wrangler.template.jsonc +7 -1
- package/dist/assets/deploy/cloudflare-resident/worker.ts +224 -70
- package/dist/assets/deploy/secrets.manifest.json +7 -1
- package/dist/assets/package-lock.json +207 -3
- package/dist/assets/package.json +2 -1
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/agents/registry.ts +27 -8
- package/dist/assets/src/core/authz/actor.ts +38 -2
- package/dist/assets/src/core/authz/grants.ts +20 -9
- package/dist/assets/src/core/authz/policy.ts +6 -0
- package/dist/assets/src/core/coordinator/contract.ts +49 -1
- package/dist/assets/src/core/coordinator/driver.ts +30 -1
- package/dist/assets/src/core/coordinator/instancesRoute.ts +72 -0
- package/dist/assets/src/core/costs.ts +1119 -0
- package/dist/assets/src/core/costsSnapshotStore.ts +209 -0
- package/dist/assets/src/core/delivery.ts +4 -11
- package/dist/assets/src/core/deliverySnapshotStore.ts +12 -28
- package/dist/assets/src/core/ingressTokens.ts +27 -13
- package/dist/assets/src/core/runLedger/types.ts +3 -0
- package/dist/assets/src/core/runRecord.ts +10 -3
- package/dist/assets/src/core/schedules.ts +2 -1
- package/dist/assets/src/core/ship/coordinator.ts +92 -7
- package/dist/assets/src/core/snapshotAge.ts +30 -0
- package/dist/assets/src/core/stateWorkerRef.ts +41 -0
- package/dist/assets/src/core/trace/attrs.ts +1 -1
- package/dist/assets/src/execution/bindingPurge.ts +2 -2
- package/dist/assets/src/execution/residentAutoRebuild.ts +73 -0
- package/dist/assets/src/execution/residentRefresh.ts +25 -3
- package/dist/assets/src/execution/restoreWaiters.ts +61 -0
- package/dist/assets/src/mcp/registry.ts +7 -0
- package/dist/assets/web/dist/.vite/manifest.json +509 -427
- package/dist/assets/web/dist/assets/AppShell-DEy5jRuS.js +1 -0
- package/dist/assets/web/dist/assets/CostsPage-BuHD-Bv7.js +2 -0
- package/dist/assets/web/dist/assets/DeliveryPage-BGpPr5xr.js +1 -0
- package/dist/assets/web/dist/assets/HomePage-dKBvWh-E.js +2 -0
- package/dist/assets/web/dist/assets/NotFoundPage-DtmQM2gD.js +1 -0
- package/dist/assets/web/dist/assets/PendingTurnRow-CrEAWx5b.js +1 -0
- package/dist/assets/web/dist/assets/{ResidentDetailPage-CrfCd8fx.js → ResidentDetailPage-C-48fxat.js} +1 -1
- package/dist/assets/web/dist/assets/ResidentsIndexPage-CBBIjPOa.js +1 -0
- package/dist/assets/web/dist/assets/RunFoldRow-B6vxjcBI.js +1 -0
- package/dist/assets/web/dist/assets/RunRoutePage-CQjd3Cz-.js +6 -0
- package/dist/assets/web/dist/assets/RunsIndexPage-Cy9G6D0p.js +1 -0
- package/dist/assets/web/dist/assets/{RunsTabs-XpCqeWu4.js → RunsTabs-CtNGNnhN.js} +1 -1
- package/dist/assets/web/dist/assets/ScheduledPage-Ci1Ygqnc.js +1 -0
- package/dist/assets/web/dist/assets/SettingsPage-DxmJvAmT.js +1 -0
- package/dist/assets/web/dist/assets/SlackMark-VDNs7Vjh.js +1 -0
- package/dist/assets/web/dist/assets/{StatusDot-DkXALvKf.js → StatusDot-DPWE1JmO.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-DtLIyi5P.js → Tooltip-DKhSRH9t.js} +1 -1
- package/dist/assets/web/dist/assets/UnitRoutePage-DEN5bSQf.js +1 -0
- package/dist/assets/web/dist/assets/{angular-html-DYtV9uIN.js → angular-html-DgSK1qvr.js} +1 -1
- package/dist/assets/web/dist/assets/{angular-ts-DF2P25Zp.js → angular-ts-D3gNdiSG.js} +1 -1
- package/dist/assets/web/dist/assets/{apl-Ff96wxko.js → apl-CkHCYM8I.js} +1 -1
- package/dist/assets/web/dist/assets/{astro-LbBnZna-.js → astro-DLm45axt.js} +1 -1
- package/dist/assets/web/dist/assets/{blade-DltuxeBW.js → blade-BKa-VE-c.js} +1 -1
- package/dist/assets/web/dist/assets/{c-DBg7yuPx.js → c-C8NCNWai.js} +1 -1
- package/dist/assets/web/dist/assets/{chapel-C83hUAds.js → chapel-DqDQ7IKH.js} +1 -1
- package/dist/assets/web/dist/assets/{cobol-DB0yV_2D.js → cobol-j4vCD6AJ.js} +1 -1
- package/dist/assets/web/dist/assets/{coffee-Bpih6Kzl.js → coffee-C6oDVH-0.js} +1 -1
- package/dist/assets/web/dist/assets/{cpp-CU00ZeRn.js → cpp-Bd3A1Rtc.js} +1 -1
- package/dist/assets/web/dist/assets/{crystal-f8ImJkux.js → crystal-CUOgOw0d.js} +1 -1
- package/dist/assets/web/dist/assets/{css-4VrC4ISo.js → css-RYljyv7G.js} +1 -1
- package/dist/assets/web/dist/assets/delivery-CTdOqpVK.js +1 -0
- package/dist/assets/web/dist/assets/{dist-DtA7JiH5.js → dist-BnJXKHCY.js} +2 -2
- package/dist/assets/web/dist/assets/durationTone-DXG-3R7_.js +1 -0
- package/dist/assets/web/dist/assets/{edge-BwFDzfS_.js → edge-BJhNdQDc.js} +1 -1
- package/dist/assets/web/dist/assets/{elixir-wwIYIpJm.js → elixir-g1AWOAfT.js} +1 -1
- package/dist/assets/web/dist/assets/{elm-DyDuM3v3.js → elm-CER5e4Dz.js} +1 -1
- package/dist/assets/web/dist/assets/{erb-DFJBEVrh.js → erb-D5aOmMQf.js} +1 -1
- package/dist/assets/web/dist/assets/eventSource-tRprhqm7.js +1 -0
- package/dist/assets/web/dist/assets/favicon-D1hkyC5j.js +1 -0
- package/dist/assets/web/dist/assets/{git-rebase-CuDv-44X.js → git-rebase-D6rfV8jp.js} +1 -1
- package/dist/assets/web/dist/assets/{glimmer-js-ZFnrm4J3.js → glimmer-js-BvDH3-mC.js} +1 -1
- package/dist/assets/web/dist/assets/{glimmer-ts-XY4Yqshp.js → glimmer-ts-DChtNs9V.js} +1 -1
- package/dist/assets/web/dist/assets/{glsl-xnR8efx0.js → glsl-BHlsWrxf.js} +1 -1
- package/dist/assets/web/dist/assets/{graphql-D-gO5tnP.js → graphql-BsaBHb53.js} +1 -1
- package/dist/assets/web/dist/assets/{hack-CSxbW4ax.js → hack-0lbDosCd.js} +1 -1
- package/dist/assets/web/dist/assets/{haml-D4ar42QT.js → haml-BKtco2vr.js} +1 -1
- package/dist/assets/web/dist/assets/{handlebars-CMLbDE7o.js → handlebars-BE_cj04z.js} +1 -1
- package/dist/assets/web/dist/assets/{html-CVekU4Fs.js → html-BNcr8EVd.js} +1 -1
- package/dist/assets/web/dist/assets/{html-derivative-St3HHw_N.js → html-derivative-BsJt2Kei.js} +1 -1
- package/dist/assets/web/dist/assets/{http-Mon0DWHS.js → http-BR5P8ER_.js} +1 -1
- package/dist/assets/web/dist/assets/{hurl-Cbl5IvBs.js → hurl-CtHalpWS.js} +1 -1
- package/dist/assets/web/dist/assets/{localIso-CNA-bhS-.js → indexFormat-B-pd4r7Y.js} +1 -1
- package/dist/assets/web/dist/assets/{indexRow-FLJu5mR9.js → indexRow-BD1VT8o8.js} +1 -1
- package/dist/assets/web/dist/assets/{java-Bprck1l-.js → java-BXVdhN11.js} +1 -1
- package/dist/assets/web/dist/assets/{javascript-C73G1-UR.js → javascript-CyoShgNQ.js} +1 -1
- package/dist/assets/web/dist/assets/{jinja-C4DuRxYJ.js → jinja-BQYZzHex.js} +1 -1
- package/dist/assets/web/dist/assets/{jison-B2U03GEC.js → jison-DqrUa1Eq.js} +1 -1
- package/dist/assets/web/dist/assets/{json-CvTZUDzx.js → json-CQiTF9Jj.js} +1 -1
- package/dist/assets/web/dist/assets/{jsx-DMWKCzwo.js → jsx-Y16MkCYQ.js} +1 -1
- package/dist/assets/web/dist/assets/{julia-Czn7bV_3.js → julia-zn16YONe.js} +1 -1
- package/dist/assets/web/dist/assets/{just-BBxpNfvC.js → just-DcVeN_MN.js} +1 -1
- package/dist/assets/web/dist/assets/{latex-Bw9yg5mr.js → latex-BNNoF-WP.js} +1 -1
- package/dist/assets/web/dist/assets/{liquid-BRCjaydE.js → liquid-DAi6qHzn.js} +1 -1
- package/dist/assets/web/dist/assets/localIso-L06jV29p.js +1 -0
- package/dist/assets/web/dist/assets/{lua-DUu2KIC0.js → lua-BswS0axw.js} +1 -1
- package/dist/assets/web/dist/assets/main-B3is4sk6.js +28 -0
- package/dist/assets/web/dist/assets/main-DP_zSemY.css +1 -0
- package/dist/assets/web/dist/assets/{marko-CZJZIlSQ.js → marko-C-4hkmQZ.js} +1 -1
- package/dist/assets/web/dist/assets/{mdc-BmClq6fd.js → mdc-0ZaHUkS7.js} +1 -1
- package/dist/assets/web/dist/assets/{nginx-Bmt3xSEm.js → nginx-DBDg5tOR.js} +1 -1
- package/dist/assets/web/dist/assets/{nim-Da-i0utK.js → nim-BVMz49Yw.js} +1 -1
- package/dist/assets/web/dist/assets/{org-BvAre2qP.js → org-1hO_K6ya.js} +1 -1
- package/dist/assets/web/dist/assets/{perl-v9WwFFtB.js → perl-CVRQLvVk.js} +1 -1
- package/dist/assets/web/dist/assets/{php-DTU4Zyze.js → php-K9nCrB9n.js} +1 -1
- package/dist/assets/web/dist/assets/{pug-DhTwEqTO.js → pug-CTxOcmO3.js} +1 -1
- package/dist/assets/web/dist/assets/{qml-BUD9AC_c.js → qml-CmCkfG5q.js} +1 -1
- package/dist/assets/web/dist/assets/{r-CAnu56n7.js → r-pP47Xn1X.js} +1 -1
- package/dist/assets/web/dist/assets/{razor-Dn0P4gAq.js → razor-BpW6r3tC.js} +1 -1
- package/dist/assets/web/dist/assets/{regexp-CZyBRaVW.js → regexp-CINgdY4N.js} +1 -1
- package/dist/assets/web/dist/assets/{rst-Ckyd5UsY.js → rst-BZIUEq2Q.js} +1 -1
- package/dist/assets/web/dist/assets/{ruby-BBQ62fsx.js → ruby-nzAOxz6r.js} +1 -1
- package/dist/assets/web/dist/assets/{sas-CW35hMxG.js → sas-QIS1bFth.js} +1 -1
- package/dist/assets/web/dist/assets/{scss-CpV8pF4J.js → scss-BuhBBVNt.js} +1 -1
- package/dist/assets/web/dist/assets/settingsApi-priOPiwu.js +1 -0
- package/dist/assets/web/dist/assets/{shellscript-CRJvsmE1.js → shellscript-CQc1vXbk.js} +1 -1
- package/dist/assets/web/dist/assets/{shellsession-CyriUZxf.js → shellsession-CoubCAUv.js} +1 -1
- package/dist/assets/web/dist/assets/{soy-D5QzYUeg.js → soy-CPRzlder.js} +1 -1
- package/dist/assets/web/dist/assets/{sql-CUBf_Mse.js → sql-W9krb8-9.js} +1 -1
- package/dist/assets/web/dist/assets/sseReplay-yji8a1wM.js +9 -0
- package/dist/assets/web/dist/assets/{stata-B-4n4ITz.js → stata-CuISJEC0.js} +1 -1
- package/dist/assets/web/dist/assets/{surrealql-RuWZBLtr.js → surrealql-CSet7584.js} +1 -1
- package/dist/assets/web/dist/assets/{svelte-CO5YzCsK.js → svelte-ChXTSYwK.js} +1 -1
- package/dist/assets/web/dist/assets/{templ-DbkWVaBF.js → templ-Bm55v62k.js} +1 -1
- package/dist/assets/web/dist/assets/{tex-IuxoEcId.js → tex-CICMX8Gj.js} +1 -1
- package/dist/assets/web/dist/assets/{ts-tags-g6dGQPjd.js → ts-tags-CA1UzWyB.js} +1 -1
- package/dist/assets/web/dist/assets/{tsx-WnXwiyH2.js → tsx-Dy04HNbv.js} +1 -1
- package/dist/assets/web/dist/assets/{twig-Lx1G7PnY.js → twig-BBHsVnVD.js} +1 -1
- package/dist/assets/web/dist/assets/{typescript-BQd7biLF.js → typescript-Dvc-wVBT.js} +1 -1
- package/dist/assets/web/dist/assets/{typst-D2lXPHK7.js → typst-Dvlqx3_q.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-html-DZPaRte4.js → vue-html-D4YxT3An.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-vine-DbmZCmu-.js → vue-vine-0YE7uQlH.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-4wVQD9y9.js → vue-zWi1MNU2.js} +1 -1
- package/dist/assets/web/dist/assets/{xml-DV16szyo.js → xml-gm-iksZB.js} +1 -1
- package/dist/assets/web/dist/assets/{xsl-eo5-1sk0.js → xsl-D_W5BcrY.js} +1 -1
- package/dist/assets/web/dist/assets/{yaml-BXdX8HZf.js → yaml-CHmZ21wZ.js} +1 -1
- package/dist/cli.js +6014 -2362
- package/package.json +1 -1
- package/dist/assets/web/dist/assets/AppShell-MYHNxJks.js +0 -1
- package/dist/assets/web/dist/assets/CostsPage-DKk9OjB0.js +0 -2
- package/dist/assets/web/dist/assets/DeliveryPage-Kz6js49i.js +0 -1
- package/dist/assets/web/dist/assets/NotFoundPage-BXLrQQzy.js +0 -1
- package/dist/assets/web/dist/assets/ResidentsIndexPage-BdW0k2h3.js +0 -1
- package/dist/assets/web/dist/assets/RunFoldRow-CbTd9SiS.js +0 -9
- package/dist/assets/web/dist/assets/RunRoutePage-br0H-8Pz.js +0 -6
- package/dist/assets/web/dist/assets/RunsIndexPage-Bnzb15zH.js +0 -1
- package/dist/assets/web/dist/assets/ScheduledPage-NLhjzHAz.js +0 -1
- package/dist/assets/web/dist/assets/SettingsPage-D-i0uVw-.js +0 -1
- package/dist/assets/web/dist/assets/UnitRoutePage-DGXukEAH.js +0 -1
- package/dist/assets/web/dist/assets/durationTone-CYMux25J.js +0 -1
- package/dist/assets/web/dist/assets/favicon-CSt-qDvc.js +0 -1
- package/dist/assets/web/dist/assets/main-CFHF2RvQ.css +0 -1
- package/dist/assets/web/dist/assets/main-Dht0in4v.js +0 -28
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.241.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "switchboard",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.241.0",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"workspaces": [
|
|
12
12
|
"web",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
36
36
|
"@eslint/js": "^10.0.1",
|
|
37
|
+
"@opencode/cli": "^2.0.3",
|
|
37
38
|
"@opencode/protocol": "2.0.3",
|
|
38
39
|
"@opencode/schema": "2.0.3",
|
|
39
40
|
"@types/node": "^24.0.0",
|
|
@@ -6242,6 +6243,209 @@
|
|
|
6242
6243
|
"dev": true,
|
|
6243
6244
|
"license": "MIT"
|
|
6244
6245
|
},
|
|
6246
|
+
"node_modules/@opencode/cli": {
|
|
6247
|
+
"version": "2.0.3",
|
|
6248
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli/-/cli-2.0.3.tgz",
|
|
6249
|
+
"integrity": "sha512-FC4+2a5kwdKS2o/pIcGCscpSQB7PuhBObwGMfqnx/2XtoaZBMtSq/99nuEdeDNAFvy1qyK6mp2hwvoiMWsiI4w==",
|
|
6250
|
+
"cpu": [
|
|
6251
|
+
"arm64",
|
|
6252
|
+
"x64"
|
|
6253
|
+
],
|
|
6254
|
+
"dev": true,
|
|
6255
|
+
"hasInstallScript": true,
|
|
6256
|
+
"license": "MIT",
|
|
6257
|
+
"os": [
|
|
6258
|
+
"darwin",
|
|
6259
|
+
"linux",
|
|
6260
|
+
"win32"
|
|
6261
|
+
],
|
|
6262
|
+
"bin": {
|
|
6263
|
+
"opencode": "bin/opencode.exe",
|
|
6264
|
+
"opencode2": "bin/opencode.exe"
|
|
6265
|
+
},
|
|
6266
|
+
"optionalDependencies": {
|
|
6267
|
+
"@opencode/cli-darwin-arm64": "2.0.3",
|
|
6268
|
+
"@opencode/cli-darwin-x64": "2.0.3",
|
|
6269
|
+
"@opencode/cli-darwin-x64-baseline": "2.0.3",
|
|
6270
|
+
"@opencode/cli-linux-arm64": "2.0.3",
|
|
6271
|
+
"@opencode/cli-linux-arm64-musl": "2.0.3",
|
|
6272
|
+
"@opencode/cli-linux-x64": "2.0.3",
|
|
6273
|
+
"@opencode/cli-linux-x64-baseline": "2.0.3",
|
|
6274
|
+
"@opencode/cli-linux-x64-baseline-musl": "2.0.3",
|
|
6275
|
+
"@opencode/cli-linux-x64-musl": "2.0.3",
|
|
6276
|
+
"@opencode/cli-windows-arm64": "2.0.3",
|
|
6277
|
+
"@opencode/cli-windows-x64": "2.0.3",
|
|
6278
|
+
"@opencode/cli-windows-x64-baseline": "2.0.3"
|
|
6279
|
+
}
|
|
6280
|
+
},
|
|
6281
|
+
"node_modules/@opencode/cli-darwin-arm64": {
|
|
6282
|
+
"version": "2.0.3",
|
|
6283
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-darwin-arm64/-/cli-darwin-arm64-2.0.3.tgz",
|
|
6284
|
+
"integrity": "sha512-2JzNaHmMHUCk2uLXo2kCKCs81KOzErt7V7ypFFp5hUCIXRPjt9D7C5CKsz2GKWfpHRivUKILKrfUS9MpYzfq6A==",
|
|
6285
|
+
"cpu": [
|
|
6286
|
+
"arm64"
|
|
6287
|
+
],
|
|
6288
|
+
"dev": true,
|
|
6289
|
+
"license": "MIT",
|
|
6290
|
+
"optional": true,
|
|
6291
|
+
"os": [
|
|
6292
|
+
"darwin"
|
|
6293
|
+
]
|
|
6294
|
+
},
|
|
6295
|
+
"node_modules/@opencode/cli-darwin-x64": {
|
|
6296
|
+
"version": "2.0.3",
|
|
6297
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-darwin-x64/-/cli-darwin-x64-2.0.3.tgz",
|
|
6298
|
+
"integrity": "sha512-dMAH/N5KD10Wlct2BbCa8tEV6SiPgBg1kF9Ud7N7ZUctMEeGoz3fqZTrcGrQz7yoAkyyHhGgq+gmxqobwrAhhg==",
|
|
6299
|
+
"cpu": [
|
|
6300
|
+
"x64"
|
|
6301
|
+
],
|
|
6302
|
+
"dev": true,
|
|
6303
|
+
"license": "MIT",
|
|
6304
|
+
"optional": true,
|
|
6305
|
+
"os": [
|
|
6306
|
+
"darwin"
|
|
6307
|
+
]
|
|
6308
|
+
},
|
|
6309
|
+
"node_modules/@opencode/cli-darwin-x64-baseline": {
|
|
6310
|
+
"version": "2.0.3",
|
|
6311
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-darwin-x64-baseline/-/cli-darwin-x64-baseline-2.0.3.tgz",
|
|
6312
|
+
"integrity": "sha512-sm9ZjG2KOk/v4ht6WHAo+pAeOfxnnImwT5rFWNIn15fVlXncbWH2QmKWDC3Nf/h7vpgeghZ1UBbBmo8fP3lBCA==",
|
|
6313
|
+
"cpu": [
|
|
6314
|
+
"x64"
|
|
6315
|
+
],
|
|
6316
|
+
"dev": true,
|
|
6317
|
+
"license": "MIT",
|
|
6318
|
+
"optional": true,
|
|
6319
|
+
"os": [
|
|
6320
|
+
"darwin"
|
|
6321
|
+
]
|
|
6322
|
+
},
|
|
6323
|
+
"node_modules/@opencode/cli-linux-arm64": {
|
|
6324
|
+
"version": "2.0.3",
|
|
6325
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-linux-arm64/-/cli-linux-arm64-2.0.3.tgz",
|
|
6326
|
+
"integrity": "sha512-q3QhCIW5CxkmJjzKI6GXJ89M0OF9lOsi1e3e4YTvQL6Htv0S7eHyZ+3Wg0UYQaoYqegAf3vBoYiPR3Z9ieIVrQ==",
|
|
6327
|
+
"cpu": [
|
|
6328
|
+
"arm64"
|
|
6329
|
+
],
|
|
6330
|
+
"dev": true,
|
|
6331
|
+
"license": "MIT",
|
|
6332
|
+
"optional": true,
|
|
6333
|
+
"os": [
|
|
6334
|
+
"linux"
|
|
6335
|
+
]
|
|
6336
|
+
},
|
|
6337
|
+
"node_modules/@opencode/cli-linux-arm64-musl": {
|
|
6338
|
+
"version": "2.0.3",
|
|
6339
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.3.tgz",
|
|
6340
|
+
"integrity": "sha512-cif0oXReK/lVZ9kFplNc3XTNM3uuAKLIgcfcEIVMbjTivLzdHe0O5Dp8y7rakJOdXqQ5yM1k6oP8kP2rfpitxg==",
|
|
6341
|
+
"cpu": [
|
|
6342
|
+
"arm64"
|
|
6343
|
+
],
|
|
6344
|
+
"dev": true,
|
|
6345
|
+
"license": "MIT",
|
|
6346
|
+
"optional": true,
|
|
6347
|
+
"os": [
|
|
6348
|
+
"linux"
|
|
6349
|
+
]
|
|
6350
|
+
},
|
|
6351
|
+
"node_modules/@opencode/cli-linux-x64": {
|
|
6352
|
+
"version": "2.0.3",
|
|
6353
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-linux-x64/-/cli-linux-x64-2.0.3.tgz",
|
|
6354
|
+
"integrity": "sha512-H8m5m4g1Z/zkx1O8+pos7euLYpY/zgc5NTdUbZZ7Dh8xQ35qoHCnJjt9H8Y1hnpm4ClNKDVHmEISw/qPiskX5A==",
|
|
6355
|
+
"cpu": [
|
|
6356
|
+
"x64"
|
|
6357
|
+
],
|
|
6358
|
+
"dev": true,
|
|
6359
|
+
"license": "MIT",
|
|
6360
|
+
"optional": true,
|
|
6361
|
+
"os": [
|
|
6362
|
+
"linux"
|
|
6363
|
+
]
|
|
6364
|
+
},
|
|
6365
|
+
"node_modules/@opencode/cli-linux-x64-baseline": {
|
|
6366
|
+
"version": "2.0.3",
|
|
6367
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-linux-x64-baseline/-/cli-linux-x64-baseline-2.0.3.tgz",
|
|
6368
|
+
"integrity": "sha512-14CFor+PFx7tPAFOB3uEcg2EOQZNB1gK4uit4p8gfN30FK7kwNHBjs/m79QGICPMjwZrCOVdZ3ZiI+AgbjanjA==",
|
|
6369
|
+
"cpu": [
|
|
6370
|
+
"x64"
|
|
6371
|
+
],
|
|
6372
|
+
"dev": true,
|
|
6373
|
+
"license": "MIT",
|
|
6374
|
+
"optional": true,
|
|
6375
|
+
"os": [
|
|
6376
|
+
"linux"
|
|
6377
|
+
]
|
|
6378
|
+
},
|
|
6379
|
+
"node_modules/@opencode/cli-linux-x64-baseline-musl": {
|
|
6380
|
+
"version": "2.0.3",
|
|
6381
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-linux-x64-baseline-musl/-/cli-linux-x64-baseline-musl-2.0.3.tgz",
|
|
6382
|
+
"integrity": "sha512-AYMNzjwPU63FjqjKLEm61s2tBL7+yipt/lzn+2eMpPHYGggV2urJH9TEME2+mReENeYFfOSItPR7gWLX1p2g5A==",
|
|
6383
|
+
"cpu": [
|
|
6384
|
+
"x64"
|
|
6385
|
+
],
|
|
6386
|
+
"dev": true,
|
|
6387
|
+
"license": "MIT",
|
|
6388
|
+
"optional": true,
|
|
6389
|
+
"os": [
|
|
6390
|
+
"linux"
|
|
6391
|
+
]
|
|
6392
|
+
},
|
|
6393
|
+
"node_modules/@opencode/cli-linux-x64-musl": {
|
|
6394
|
+
"version": "2.0.3",
|
|
6395
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.3.tgz",
|
|
6396
|
+
"integrity": "sha512-YDZCk0MddTJ8lDwlEmE5bVWF5R13nDpLEQPcCA5IY2njB/y2g6UaAiIVbJE1rVmFd7/Z7JmyB2X3z60uk3C/dA==",
|
|
6397
|
+
"cpu": [
|
|
6398
|
+
"x64"
|
|
6399
|
+
],
|
|
6400
|
+
"dev": true,
|
|
6401
|
+
"license": "MIT",
|
|
6402
|
+
"optional": true,
|
|
6403
|
+
"os": [
|
|
6404
|
+
"linux"
|
|
6405
|
+
]
|
|
6406
|
+
},
|
|
6407
|
+
"node_modules/@opencode/cli-windows-arm64": {
|
|
6408
|
+
"version": "2.0.3",
|
|
6409
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-windows-arm64/-/cli-windows-arm64-2.0.3.tgz",
|
|
6410
|
+
"integrity": "sha512-WQuojS+6O6YNlRsal9kbePiEEv4hZHVL7l7ILRnlyZSLx7M2ynTOUahtGzC42AbdH9sdIa4OGQDmDwcbfCqHuA==",
|
|
6411
|
+
"cpu": [
|
|
6412
|
+
"arm64"
|
|
6413
|
+
],
|
|
6414
|
+
"dev": true,
|
|
6415
|
+
"license": "MIT",
|
|
6416
|
+
"optional": true,
|
|
6417
|
+
"os": [
|
|
6418
|
+
"win32"
|
|
6419
|
+
]
|
|
6420
|
+
},
|
|
6421
|
+
"node_modules/@opencode/cli-windows-x64": {
|
|
6422
|
+
"version": "2.0.3",
|
|
6423
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-windows-x64/-/cli-windows-x64-2.0.3.tgz",
|
|
6424
|
+
"integrity": "sha512-4pCiryt3LZG4dCkhvDOiTttzBECE36HUKe5uwCSAu9Ny7Sh2H1iVw1XFKo3QYqh6XdkWa9Uyza0lqLB6SSAGTw==",
|
|
6425
|
+
"cpu": [
|
|
6426
|
+
"x64"
|
|
6427
|
+
],
|
|
6428
|
+
"dev": true,
|
|
6429
|
+
"license": "MIT",
|
|
6430
|
+
"optional": true,
|
|
6431
|
+
"os": [
|
|
6432
|
+
"win32"
|
|
6433
|
+
]
|
|
6434
|
+
},
|
|
6435
|
+
"node_modules/@opencode/cli-windows-x64-baseline": {
|
|
6436
|
+
"version": "2.0.3",
|
|
6437
|
+
"resolved": "https://registry.npmjs.org/@opencode/cli-windows-x64-baseline/-/cli-windows-x64-baseline-2.0.3.tgz",
|
|
6438
|
+
"integrity": "sha512-9R6QdvoEd6bxv+Izi2kwg+85Mc3lCoTRgAsTZpNadVaRgAcU8vzEjjgrzFM6gLr8j+65EgG7vtP1gCVhfyQRwg==",
|
|
6439
|
+
"cpu": [
|
|
6440
|
+
"x64"
|
|
6441
|
+
],
|
|
6442
|
+
"dev": true,
|
|
6443
|
+
"license": "MIT",
|
|
6444
|
+
"optional": true,
|
|
6445
|
+
"os": [
|
|
6446
|
+
"win32"
|
|
6447
|
+
]
|
|
6448
|
+
},
|
|
6245
6449
|
"node_modules/@opencode/protocol": {
|
|
6246
6450
|
"version": "2.0.3",
|
|
6247
6451
|
"resolved": "https://registry.npmjs.org/@opencode/protocol/-/protocol-2.0.3.tgz",
|
|
@@ -20241,7 +20445,7 @@
|
|
|
20241
20445
|
},
|
|
20242
20446
|
"packages/switchboard": {
|
|
20243
20447
|
"name": "@coreplane/switchboard",
|
|
20244
|
-
"version": "1.
|
|
20448
|
+
"version": "1.241.0",
|
|
20245
20449
|
"license": "Apache-2.0",
|
|
20246
20450
|
"dependencies": {
|
|
20247
20451
|
"@earendil-works/pi-ai": "0.85.1",
|
package/dist/assets/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.241.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
"devDependencies": {
|
|
92
92
|
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
93
93
|
"@eslint/js": "^10.0.1",
|
|
94
|
+
"@opencode/cli": "^2.0.3",
|
|
94
95
|
"@opencode/protocol": "2.0.3",
|
|
95
96
|
"@opencode/schema": "2.0.3",
|
|
96
97
|
"@types/node": "^24.0.0",
|
package/dist/assets/source.json
CHANGED
|
@@ -133,6 +133,23 @@ export interface AgentDef {
|
|
|
133
133
|
// and rendered against the head sha at render time, so a repush is a
|
|
134
134
|
// re-render by Switchboard — the agent only resubmits when the CONTENT (line
|
|
135
135
|
// numbers included) changed.
|
|
136
|
+
/** The status-card rule every tool-running preset carries (docs/reference/specs/run-visibility.md
|
|
137
|
+
* item 2). One sentence in one place: the card shows the command running right
|
|
138
|
+
* now beside the checklist, so the checklist's markers must be facts — ✱ from
|
|
139
|
+
* the item's first command, ✓ only once its result has been read — or the two
|
|
140
|
+
* contradict each other on the card. `examples` are the preset's own outcome
|
|
141
|
+
* phrasings; the rule itself never varies by preset. */
|
|
142
|
+
export function statusCardRule(examples = '"Implement the fix", "Run the test suite"'): string {
|
|
143
|
+
return (
|
|
144
|
+
"Maintain the user-facing status card with the update_status tool. Post your plan as a checklist (○ pending) as soon as you have it, " +
|
|
145
|
+
"then keep it truthful at every moment: the markers are facts, not intentions. Mark an item ✱ when you issue the first command that does it, " +
|
|
146
|
+
"and ✓ only after you have read the result that proves it happened — never in the same turn as the command, never because you intend to run it next, " +
|
|
147
|
+
"never for a reporting or posting step you have not done. The order is: mark the item ✱, run its commands, read the result, then mark it ✓ and the next item ✱. " +
|
|
148
|
+
"The card shows the command running right now beside your checklist, so a ✓ item whose command is still running reads as a lie. " +
|
|
149
|
+
`Items are short outcomes (${examples}), never commands. This is the only progress the user sees while you work.`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
136
153
|
const PR_DESCRIPTION_TEMPLATE = `PR description — submit it with the submit_pr_description tool for EVERY PR (this is the default, not something to wait to be asked for). Switchboard renders the GitHub body from the object you submit, so never author PR-body markdown yourself. Before submitting, judge your title with the ${PR_TITLE_GUARD} gate — \`npm run check:pr-title -- "<title>"\` — and submit only a title it accepts; the same gate refuses the PR in CI. Content contract per field (each renders as its own section): prose is unwrapped — no hard line breaks inside a paragraph. Always hyperlink the triggering issue/request. Never fabricate validation — state exactly what you ran and the real result. Keep each field concise, not padded.
|
|
137
154
|
EVERY PR includes one that already exists when you push — opened by a person, by dependabot, or by an earlier run. After EVERY push to such a PR: read its current title and body (\`github_issue_get\` with the PR number works for pull requests; \`gh pr view\` where gh exists), judge them against the change as it now stands at the pushed head, and submit the object that describes the PR as it is NOW — carry forward what the existing body says that is still true (a dependency bump's release notes belong in whatWhy), add what you changed, and anchor the Tour at the new head. Switchboard replaces the PR's title and body with your rendering. A description that describes an earlier state of its branch is a bug; "it is someone else's PR" is never a reason to leave it.
|
|
138
155
|
- **title**: the PR title — one line naming the change, specific enough to pick out of a PR list.
|
|
@@ -237,7 +254,7 @@ ${SHOW_FILES}
|
|
|
237
254
|
|
|
238
255
|
${NOTEPAD}
|
|
239
256
|
|
|
240
|
-
|
|
257
|
+
${statusCardRule('"Clone repo and read the diff", "Run the test suite"')}
|
|
241
258
|
|
|
242
259
|
If the request doesn't name a repository and you can't infer it, ask for it instead of guessing.
|
|
243
260
|
Report outcomes faithfully: if tests fail or a step was skipped, say so plainly.
|
|
@@ -280,7 +297,7 @@ ${SHOW_FILES}
|
|
|
280
297
|
|
|
281
298
|
${NOTEPAD}
|
|
282
299
|
|
|
283
|
-
|
|
300
|
+
${statusCardRule()}
|
|
284
301
|
|
|
285
302
|
Report outcomes faithfully: if tests fail or a step was skipped, say so plainly.
|
|
286
303
|
${FENCED_CONTENT_RULE}
|
|
@@ -319,7 +336,7 @@ ${SHOW_FILES}
|
|
|
319
336
|
|
|
320
337
|
${NOTEPAD}
|
|
321
338
|
|
|
322
|
-
|
|
339
|
+
${statusCardRule()}
|
|
323
340
|
|
|
324
341
|
Report outcomes faithfully: if tests fail or a step was skipped, say so plainly.
|
|
325
342
|
${FENCED_CONTENT_RULE}
|
|
@@ -384,7 +401,7 @@ ${REVIEW_VERDICT_INSTRUCTION}
|
|
|
384
401
|
|
|
385
402
|
${NOTEPAD}
|
|
386
403
|
|
|
387
|
-
|
|
404
|
+
${statusCardRule('"Gather the diff and the files", "Analyze the change", "Post the verdict"')}
|
|
388
405
|
|
|
389
406
|
${FENCED_CONTENT_RULE}
|
|
390
407
|
Your final message is posted to Slack. Lead with a one-line verdict, then the findings.`;
|
|
@@ -417,7 +434,7 @@ ${REVIEW_VERDICT_INSTRUCTION}
|
|
|
417
434
|
|
|
418
435
|
${NOTEPAD}
|
|
419
436
|
|
|
420
|
-
|
|
437
|
+
${statusCardRule('"Gather the diff and the files", "Analyze the change", "Post the verdict"')}
|
|
421
438
|
|
|
422
439
|
${FENCED_CONTENT_RULE}
|
|
423
440
|
Your final message is posted to Slack. Lead with a one-line verdict, then the findings.`;
|
|
@@ -451,7 +468,7 @@ ${REVIEW_VERDICT_INSTRUCTION}
|
|
|
451
468
|
|
|
452
469
|
${NOTEPAD}
|
|
453
470
|
|
|
454
|
-
|
|
471
|
+
${statusCardRule('"Gather the diff and the files", "Analyze the change", "Post the verdict"')}
|
|
455
472
|
|
|
456
473
|
${FENCED_CONTENT_RULE}
|
|
457
474
|
Your final message is posted to Slack. Lead with a one-line verdict, then the findings.`;
|
|
@@ -469,7 +486,7 @@ How to work:
|
|
|
469
486
|
2. Prefer primary sources; corroborate a surprising claim with a second source.
|
|
470
487
|
3. Answer concisely and cite the URLs (or repo paths) you used. If sources conflict or you couldn't verify something, say so plainly. If web search is unconfigured, use web_fetch / the GitHub tools on what you have and say search was unavailable.
|
|
471
488
|
|
|
472
|
-
|
|
489
|
+
${statusCardRule('"Search the sources", "Write the answer"')}
|
|
473
490
|
|
|
474
491
|
${FENCED_CONTENT_RULE}
|
|
475
492
|
Use Slack-friendly formatting (no markdown headers; *bold*, bullets, code blocks). Your final message is posted to Slack — lead with the answer, then supporting detail and sources.`;
|
|
@@ -485,6 +502,8 @@ Answer directly and concisely. Use Slack-friendly formatting (no markdown header
|
|
|
485
502
|
|
|
486
503
|
Your tools work without a workspace: the GitHub tools — \`github_repos\` (the org repositories you can reach), \`github_tree\` / \`github_file\` / \`github_search_code\` (browse, read, search their code and docs, private repos included), \`github_issue_list\` / \`github_issue_get\` (read issues), \`github_issue_create\` / \`github_issue_update\` / \`github_issue_comment\` / \`github_issue_delete\` (act on issues) — and \`web_fetch\` (read a public URL). Use them: when the user names a repo loosely ("the switchboard app"), resolve it with github_repos (or the thread) rather than asking; when asked about one of our repos, read it before answering. Report exactly what a tool did (issue number + URL) — never claim an action you did not perform, and never fabricate file contents, URLs, or command output.
|
|
487
504
|
|
|
505
|
+
${statusCardRule('"Read the issue and its thread", "Post the comment"')} A one-step answer needs no checklist; post one when the request has steps the person would wait on.
|
|
506
|
+
|
|
488
507
|
You cannot run commands, clone repositories, edit code, or review pull requests, and you cannot search the web. Other Switchboard agents can: for code changes or PRs tell the user to re-send with \`agent:coding\`; for a PR review, \`agent:review\`; for a web-research question, \`agent:research\` (e.g. "\`agent:coding fix the failing login test in acme/api\`", "\`agent:research compare X and Y\`"). Delete an issue only when the user explicitly asked to delete it (closing is an update).`;
|
|
489
508
|
|
|
490
509
|
// The explore agent (docs/reference/specs/agent-explore.md): a long, read-only
|
|
@@ -512,7 +531,7 @@ READ-ONLY: NEVER open a pull request, and never commit or push — no branch, no
|
|
|
512
531
|
|
|
513
532
|
You cannot attach or post files: your whole answer is text. Never say a file is attached or below — name its path in the workspace and describe it (what it shows, its size) instead; a person who needs the file itself asks \`agent:coding\`, which can attach.
|
|
514
533
|
|
|
515
|
-
|
|
534
|
+
${statusCardRule('"Clone and install", "Time the full suite"')}
|
|
516
535
|
|
|
517
536
|
${NOTEPAD}
|
|
518
537
|
|
|
@@ -76,12 +76,35 @@ export function resolveActor(input: ActorInput, grantsFor: GrantsLookup): Actor
|
|
|
76
76
|
return { kind: kindFor(input.surface), id, grants: grantsFor(id), ...(origin ? { origin } : {}) };
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/** The identity fields a bound credential's message carries (`IncomingMessage`). */
|
|
80
|
+
interface BoundFields {
|
|
81
|
+
/** The credential's actor id when the sender is the person it is bound to. */
|
|
82
|
+
authenticatedAs?: string;
|
|
83
|
+
userName?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The actor id whose grants govern a chat message: the credential that
|
|
87
|
+
* authenticated it when it was bound to a person (`authenticatedAs`), else
|
|
88
|
+
* the sender. Every `canRunAgent` / `canUseRepo` / `canManageRepos` /
|
|
89
|
+
* `canEditChannelConfig` question in the dispatch path asks about THIS id,
|
|
90
|
+
* never `msg.userId`: naming the person on a run must not lend the run the
|
|
91
|
+
* person's grants (authorization.md item 15). A relayed message (`postedBy`)
|
|
92
|
+
* is out of scope here — its gates are item 14's. */
|
|
93
|
+
export function grantsSubject(msg: { userId: string; authenticatedAs?: string }): string {
|
|
94
|
+
return msg.authenticatedAs ?? msg.userId;
|
|
95
|
+
}
|
|
96
|
+
|
|
79
97
|
const CHAT_SURFACES: Readonly<Record<string, ActorSurface>> = {
|
|
80
98
|
slack: "slack",
|
|
81
99
|
http: "http",
|
|
82
100
|
mcp: "mcp",
|
|
83
101
|
cli: "cli",
|
|
84
102
|
schedule: "schedule",
|
|
103
|
+
// The web chat (record 0043): a browser session speaks as text, so its
|
|
104
|
+
// `access:<sub>` is a chat credential too — the browser actor, its baseline
|
|
105
|
+
// and its entry. A service token never reaches the chat (the dashboard gate
|
|
106
|
+
// serves it `/api/*` only), so `access:svc:` is no chat surface.
|
|
107
|
+
access: "access-browser",
|
|
85
108
|
};
|
|
86
109
|
|
|
87
110
|
/** A chat message's `userId` is already namespaced by its adapter (`slack:U…`,
|
|
@@ -89,11 +112,24 @@ const CHAT_SURFACES: Readonly<Record<string, ActorSurface>> = {
|
|
|
89
112
|
* A namespace this module does not know stays a `user` with the id as given —
|
|
90
113
|
* its grants are whatever config names for that id, never a guess. */
|
|
91
114
|
export function resolveChatActor(
|
|
92
|
-
msg: { userId: string; channelId: string; threadKey: string; postedBy?: string },
|
|
115
|
+
msg: { userId: string; channelId: string; threadKey: string; postedBy?: string } & BoundFields,
|
|
93
116
|
grantsFor: GrantsLookup,
|
|
94
117
|
): Actor {
|
|
95
118
|
const person = resolveNamespacedActor(msg.userId, msg, grantsFor);
|
|
96
|
-
if (msg.postedBy === undefined)
|
|
119
|
+
if (msg.postedBy === undefined) {
|
|
120
|
+
if (msg.authenticatedAs === undefined || msg.authenticatedAs === msg.userId) return person;
|
|
121
|
+
// A credential bound to a person (authorization.md item 15): the adapter
|
|
122
|
+
// proved the credential and config bound it to the person, so the actor IS
|
|
123
|
+
// the credential — its kind, its id, its grants, exactly as an unbound
|
|
124
|
+
// token's — and the person is its `self` and `asUser`, the same
|
|
125
|
+
// identity-not-authority link a dashboard session carries (record 0042).
|
|
126
|
+
const credential = resolveNamespacedActor(msg.authenticatedAs, msg, grantsFor);
|
|
127
|
+
return {
|
|
128
|
+
...credential,
|
|
129
|
+
self: [credential.id, msg.userId],
|
|
130
|
+
asUser: { id: msg.userId, ...(msg.userName !== undefined ? { name: msg.userName } : {}) },
|
|
131
|
+
};
|
|
132
|
+
}
|
|
97
133
|
// A request an app posted for a person (slack-channel.md item 13): the
|
|
98
134
|
// message text named the person, and text is forgeable, so the person's
|
|
99
135
|
// grants alone must never govern. The actor is the app, acting on the
|
|
@@ -62,10 +62,20 @@ export const CHAT_OPEN_ACTIONS: readonly string[] = [
|
|
|
62
62
|
"mcp:write",
|
|
63
63
|
];
|
|
64
64
|
|
|
65
|
-
/**
|
|
66
|
-
*
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
/** The two writes a browser session holds beside its reads (record 0043): the
|
|
66
|
+
* same personal writes every Slack user holds (`CHAT_OPEN_ACTIONS`), because
|
|
67
|
+
* the web chat makes a browser session a chat user — `memory remember` and
|
|
68
|
+
* `mcp add` for its own tier. The tier rows still decide the target: a shared
|
|
69
|
+
* tier needs the grant it always needed. */
|
|
70
|
+
export const BROWSER_WRITE_ACTIONS: readonly string[] = ["memory:write", "mcp:write"];
|
|
71
|
+
|
|
72
|
+
/** What an Access browser session holds implicitly: every registered group's
|
|
73
|
+
* read plus the two personal chat writes — never another write, never an exec.
|
|
74
|
+
* No groups known (a process that registered no commands) → nothing at all,
|
|
75
|
+
* fail-closed: the writes ride with the catalogue they belong to. */
|
|
76
|
+
export function browserActions(commandGroups: readonly string[]): Set<string> {
|
|
77
|
+
if (commandGroups.length === 0) return new Set();
|
|
78
|
+
return new Set([...commandGroups.map((g) => `${g}:read`), ...BROWSER_WRITE_ACTIONS]);
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
// ---- the native `grants` block ----------------------------------------------
|
|
@@ -243,8 +253,9 @@ export interface GrantsTable {
|
|
|
243
253
|
surfaces: Map<string, Grants>;
|
|
244
254
|
/** What every `slack:` user holds, listed or not: the open chat commands and `agent:run:<name>` for every unrestricted agent. */
|
|
245
255
|
everyone: Grants;
|
|
246
|
-
/** What every Access browser session (`access:<sub>`, never `access:svc:`) holds:
|
|
247
|
-
|
|
256
|
+
/** What every Access browser session (`access:<sub>`, never `access:svc:`) holds:
|
|
257
|
+
* each registered group's read and the two personal chat writes. */
|
|
258
|
+
browser: Grants;
|
|
248
259
|
restrict: Restriction;
|
|
249
260
|
}
|
|
250
261
|
|
|
@@ -253,9 +264,9 @@ export interface GrantsTable {
|
|
|
253
264
|
* `<group>:read`. Every other namespace (`schedule:`, `access:svc:`, `http:`,
|
|
254
265
|
* `mcp:`) is a credential or a job that holds exactly what names it — an
|
|
255
266
|
* unlisted one is `NO_GRANTS` (fail-closed). */
|
|
256
|
-
export function namespaceBaseline(actorId: string, table: Pick<GrantsTable, "everyone" | "
|
|
267
|
+
export function namespaceBaseline(actorId: string, table: Pick<GrantsTable, "everyone" | "browser">): Grants {
|
|
257
268
|
if (actorId.startsWith("slack:")) return table.everyone;
|
|
258
|
-
if (actorId.startsWith("access:") && !actorId.startsWith("access:svc:")) return table.
|
|
269
|
+
if (actorId.startsWith("access:") && !actorId.startsWith("access:svc:")) return table.browser;
|
|
259
270
|
return NO_GRANTS;
|
|
260
271
|
}
|
|
261
272
|
|
|
@@ -271,7 +282,7 @@ export function grantsTable(source: GrantsSource): GrantsTable {
|
|
|
271
282
|
const openAgents = (source.agentNames ?? []).filter((a) => !restrict.agents.has(a)).map(agentRunAction);
|
|
272
283
|
const baselines = {
|
|
273
284
|
everyone: { ...NO_GRANTS, actions: new Set([...CHAT_OPEN_ACTIONS, ...openAgents]) },
|
|
274
|
-
|
|
285
|
+
browser: { ...NO_GRANTS, actions: browserActions(source.commandGroups ?? []) },
|
|
275
286
|
};
|
|
276
287
|
const grants = new Map<string, Grants>();
|
|
277
288
|
const surfaces = new Map<string, Grants>();
|
|
@@ -81,6 +81,12 @@ export const POLICY: readonly Rule[] = [
|
|
|
81
81
|
// `friction propose` files issues: the repo-management gate, now the `friction:write` grant.
|
|
82
82
|
{ action: "friction:write", resource: "command", when: [grant("friction:write")] },
|
|
83
83
|
|
|
84
|
+
// ── costs ────────────────────────────────────────────────────────────────
|
|
85
|
+
// `costs snapshot` reads both billing providers and replaces what every
|
|
86
|
+
// viewer of the costs page sees: the grant, never a baseline (the admins'
|
|
87
|
+
// `all` and a named `grants` entry hold it).
|
|
88
|
+
{ action: "costs:write", resource: "command", when: [grant("costs:write")] },
|
|
89
|
+
|
|
84
90
|
// ── repos ────────────────────────────────────────────────────────────────
|
|
85
91
|
{ action: "repo:read", resource: "command", when: [grant("repo:read")] },
|
|
86
92
|
{ action: "repo:write", resource: "repo", when: [grant("repo:write")] },
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
// parent record the spawn route reads the requester from, and the names the
|
|
9
9
|
// routes decide on.
|
|
10
10
|
//
|
|
11
|
+
import type { AddressSeverity, AddressSeveritySource } from "../ship/coordinator.js";
|
|
12
|
+
|
|
11
13
|
// A coordinator is a Workflow instance in the shim Worker whose children are
|
|
12
14
|
// ordinary `dispatch()` runs as the requesting user. It holds no credential of
|
|
13
15
|
// its own: every step is a call into the bot with the `coordinator` bearer,
|
|
@@ -78,6 +80,22 @@ export function runFinishedEventType(runId: string): string {
|
|
|
78
80
|
return `${RUN_FINISHED_EVENT_PREFIX}${runId}`;
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
/** The event the bot's GitHub check-run intake sends a merge-waiting parent:
|
|
84
|
+
* the type carries the head sha (hex — inside the platform's alphabet), so a
|
|
85
|
+
* driver waiting at that head matches its own event and any other head's is
|
|
86
|
+
* buffered harmlessly. */
|
|
87
|
+
export const CHECKS_SETTLED_EVENT_PREFIX = "checks-settled-";
|
|
88
|
+
export function checksSettledEventType(headSha: string): string {
|
|
89
|
+
return `${CHECKS_SETTLED_EVENT_PREFIX}${headSha}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** What the checks-settled event carries — the head and a clock; the parent
|
|
93
|
+
* re-asks the merge door before it acts, so nothing more rides here. */
|
|
94
|
+
export interface ChecksSettledPayload {
|
|
95
|
+
headSha: string;
|
|
96
|
+
settledAt: number;
|
|
97
|
+
}
|
|
98
|
+
|
|
81
99
|
/** What the event carries — ids, a status and a clock; the parent confirms
|
|
82
100
|
* through `read-record` before it acts, so nothing more rides here. */
|
|
83
101
|
export interface RunFinishedPayload {
|
|
@@ -126,9 +144,12 @@ export function coordinatorFields(tag: CoordinatorTag | undefined): {
|
|
|
126
144
|
export interface CoordinatorInstance {
|
|
127
145
|
id: string;
|
|
128
146
|
kind: "ship";
|
|
129
|
-
/** The requesting
|
|
147
|
+
/** The requesting person (platform-namespaced); every child is dispatched as them. */
|
|
130
148
|
userId: string;
|
|
131
149
|
userName?: string;
|
|
150
|
+
/** The bound credential behind the person (authorization.md item 15), when
|
|
151
|
+
* there was one: every child is authorized under ITS grants, as the request was. */
|
|
152
|
+
authenticatedAs?: string;
|
|
132
153
|
channelId: string;
|
|
133
154
|
channelName?: string;
|
|
134
155
|
/** The requesting thread: where the card lives and where a generated plan's
|
|
@@ -153,6 +174,11 @@ export interface CoordinatorInstance {
|
|
|
153
174
|
* hand-off, answered by the plan route, checked at the merge door; absent
|
|
154
175
|
* (a record written before the field existed) reads as `person`. */
|
|
155
176
|
merge?: "runner" | "person";
|
|
177
|
+
/** The severity to address: resolved once by the hand-off
|
|
178
|
+
* (directive > user > channel > org) and written here beside `merge`, so
|
|
179
|
+
* the machine reads one value; absent reads as the default (`minor`, org). */
|
|
180
|
+
addressSeverity?: AddressSeverity;
|
|
181
|
+
addressSeveritySource?: AddressSeveritySource;
|
|
156
182
|
/** The pipeline's caps as the profile gate clipped them: the rounds cap and the wall clock per unit. */
|
|
157
183
|
caps?: { maxRounds: number; maxMinutes: number };
|
|
158
184
|
/** The status card in the requesting thread, when the channel has one — what
|
|
@@ -234,6 +260,7 @@ export function isCoordinatorInstance(v: unknown): v is CoordinatorInstance {
|
|
|
234
260
|
if (r.kind !== "ship") return false;
|
|
235
261
|
if (!isText(r.userId) || !isText(r.channelId) || !isText(r.threadKey)) return false;
|
|
236
262
|
if (!isOptionalText(r.userName) || !isOptionalText(r.channelName) || !isOptionalText(r.sourceUrl)) return false;
|
|
263
|
+
if (!isOptionalText(r.authenticatedAs)) return false;
|
|
237
264
|
if (typeof r.repo !== "string" || !REPO_SLUG.test(r.repo)) return false;
|
|
238
265
|
if (!isText(r.branch) || !isOptionalText(r.base)) return false;
|
|
239
266
|
if (!isFinite(r.createdAt)) return false;
|
|
@@ -299,6 +326,27 @@ export type RunFinishedSend =
|
|
|
299
326
|
| { kind: "no-binding"; instance: string }
|
|
300
327
|
| { kind: "failed"; instance: string; type: string; reason: string };
|
|
301
328
|
|
|
329
|
+
/** The one send per settled head (http-ingress.md item 12): best effort like
|
|
330
|
+
* `sendRunFinished` — a refusal is answered, never thrown, and the parent's
|
|
331
|
+
* bounded merge wait times out on its own. */
|
|
332
|
+
export async function sendChecksSettled(
|
|
333
|
+
workflow: WorkflowSender | undefined,
|
|
334
|
+
instance: string,
|
|
335
|
+
headSha: string,
|
|
336
|
+
settledAt: number,
|
|
337
|
+
): Promise<RunFinishedSend> {
|
|
338
|
+
if (!workflow) return { kind: "no-binding", instance };
|
|
339
|
+
const type = checksSettledEventType(headSha);
|
|
340
|
+
const payload: ChecksSettledPayload = { headSha, settledAt };
|
|
341
|
+
try {
|
|
342
|
+
const handle = await workflow.get(instance);
|
|
343
|
+
await handle.sendEvent({ type, payload });
|
|
344
|
+
return { kind: "sent", instance, type };
|
|
345
|
+
} catch (err) {
|
|
346
|
+
return { kind: "failed", instance, type, reason: err instanceof Error ? err.message : String(err) };
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
302
350
|
/** The one send per committed terminal record (run-history item 47). */
|
|
303
351
|
export async function sendRunFinished(
|
|
304
352
|
workflow: WorkflowSender | undefined,
|