@alisio/server 0.1.0-alpha.8 → 0.1.1
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/bridges/interaction-bridge.js +13 -4
- package/dist/host/goal.d.ts +36 -0
- package/dist/host/goal.js +172 -0
- package/dist/host/plan.d.ts +10 -0
- package/dist/host/plan.js +45 -0
- package/dist/host/presets.d.ts +1 -1
- package/dist/host/presets.js +13 -4
- package/dist/host/run-scheduler.d.ts +25 -2
- package/dist/host/run-scheduler.js +18 -3
- package/dist/host/sessions.d.ts +10 -1
- package/dist/host/sessions.js +26 -5
- package/dist/host/workspace-host.d.ts +19 -4
- package/dist/host/workspace-host.js +63 -7
- package/dist/http/errors.js +7 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +178 -10
- package/dist/routes/changelog.d.ts +9 -0
- package/dist/routes/changelog.js +32 -0
- package/dist/routes/commands.d.ts +8 -0
- package/dist/routes/commands.js +137 -12
- package/dist/routes/goal.d.ts +21 -0
- package/dist/routes/goal.js +121 -0
- package/dist/routes/management.d.ts +12 -2
- package/dist/routes/management.js +49 -6
- package/dist/routes/plugin-views.d.ts +22 -0
- package/dist/routes/plugin-views.js +96 -0
- package/dist/routes/sessions.js +2 -0
- package/dist/routes/tasks.d.ts +5 -0
- package/dist/routes/tasks.js +70 -0
- package/dist/web/assets/AgentPicker-CgYzrrsh.js +1 -0
- package/dist/web/assets/AgentsModal-DQQp4Vj3.js +2 -0
- package/dist/web/assets/ArtifactPanel-I6u3qByq.js +2 -0
- package/dist/web/assets/BtwPanel-GypuLgxx.js +1 -0
- package/dist/web/assets/ChangelogDialog-BicA9ah6.css +1 -0
- package/dist/web/assets/ChangelogDialog-Cv0qoFca.js +1 -0
- package/dist/web/assets/CopyButton-B3PSPdbl.js +1 -0
- package/dist/web/assets/GoalBar-CHV3_kfx.css +1 -0
- package/dist/web/assets/GoalBar-DBE7KAva.js +1 -0
- package/dist/web/assets/MemoryTab-BDfJaFot.js +2 -0
- package/dist/web/assets/MemoryTab-BMdPbUkv.css +1 -0
- package/dist/web/assets/PermissionsMenu-BgOVGPRL.js +1 -0
- package/dist/web/assets/PlanReviewPanel-BNJgw4ah.js +1 -0
- package/dist/web/assets/PlanReviewPanel-DIB4EV2K.css +1 -0
- package/dist/web/assets/SettingsModal-D9zkXUeA.js +1 -0
- package/dist/web/assets/SpreadsheetPanel-C3BQhxhv.js +1 -0
- package/dist/web/assets/TasksTab-D8nzSXEr.js +1 -0
- package/dist/web/assets/TasksTab-xvZOft9V.css +1 -0
- package/dist/web/assets/TrajectoryTab-CH7ttdZT.js +1 -0
- package/dist/web/assets/TrajectoryTab-PJHG3yJv.css +1 -0
- package/dist/web/assets/{abnfDiagram-VCTEODGH-BSbQI796.js → abnfDiagram-VCTEODGH-B8huo-Kk.js} +1 -1
- package/dist/web/assets/{agents.module-B4txg5O-.js → agents.module-YUJKpT3J.js} +2 -2
- package/dist/web/assets/app-D6BT6vS-.js +3 -0
- package/dist/web/assets/architecture-7GRP2DOG-DnGQjmPz.js +1 -0
- package/dist/web/assets/{architectureDiagram-5GKGNRK7-B_aO4VWn.js → architectureDiagram-5GKGNRK7-BqGd8I5j.js} +1 -1
- package/dist/web/assets/{blockDiagram-I7D4REHJ-D0iOY295.js → blockDiagram-I7D4REHJ-DtQSxJUd.js} +1 -1
- package/dist/web/assets/{c4Diagram-7LVT6UL2-CQpmIVVf.js → c4Diagram-7LVT6UL2-BuNBp5yh.js} +1 -1
- package/dist/web/assets/channel-CEI3etVU.js +1 -0
- package/dist/web/assets/{chunk-4HAMMTFA-Y_4-541N.js → chunk-4HAMMTFA-390Mn_il.js} +1 -1
- package/dist/web/assets/{chunk-75Z2AOVW-4xYGp387.js → chunk-75Z2AOVW-Chht6Xhu.js} +1 -1
- package/dist/web/assets/chunk-DU6HZSFF-CMLEkaIG.js +125 -0
- package/dist/web/assets/{chunk-F27PBJKO-Cl_dLboe.js → chunk-F27PBJKO-SKMSua5B.js} +1 -1
- package/dist/web/assets/{chunk-GMAD6QVW-CjWWJjqH.js → chunk-GMAD6QVW-Df-qsmXX.js} +1 -1
- package/dist/web/assets/{chunk-GVQU2GXP-DsUbfXw0.js → chunk-GVQU2GXP-7PgapOOA.js} +1 -1
- package/dist/web/assets/{chunk-IMKFNOWR-CaH0S04F.js → chunk-IMKFNOWR-DRbZAlkh.js} +1 -1
- package/dist/web/assets/{chunk-L3NEJ4N5-BXAFNAb0.js → chunk-L3NEJ4N5-3E0ssqUP.js} +1 -1
- package/dist/web/assets/{chunk-OSK3NFVY-7Pr5dXXm.js → chunk-OSK3NFVY-B1GP22y4.js} +1 -1
- package/dist/web/assets/{chunk-P2QGCYS3-BbUBGz5z.js → chunk-P2QGCYS3-T_PO2L1c.js} +1 -1
- package/dist/web/assets/{chunk-POPQ4Y6H-CzsriQoR.js → chunk-POPQ4Y6H-DiREf_on.js} +1 -1
- package/dist/web/assets/{chunk-PWAF6VOD-tT3Jq6dq.js → chunk-PWAF6VOD-yOR4r5Wg.js} +1 -1
- package/dist/web/assets/{chunk-SHT3W25Y-DZj7IKKK.js → chunk-SHT3W25Y-LqpptdEy.js} +1 -1
- package/dist/web/assets/{chunk-SVP7TREG-DvDxDsmp.js → chunk-SVP7TREG-BkiLiJog.js} +1 -1
- package/dist/web/assets/{chunk-TICWLB2K-Bc1tYRg0.js → chunk-TICWLB2K-F9gzgGhl.js} +1 -1
- package/dist/web/assets/classDiagram-ZZMXUADV-B7WS1Q75.js +1 -0
- package/dist/web/assets/classDiagram-v2-VYDZK3BY-B7WS1Q75.js +1 -0
- package/dist/web/assets/{cynefin-OW5HDTMX-DnntdLgu.js → cynefin-OW5HDTMX-B_NT3eSJ.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-5FMLGOSQ-C-L_BMup.js → cynefinDiagram-5FMLGOSQ-DpNbosPc.js} +1 -1
- package/dist/web/assets/{dagre-GXQ25YYZ-Bnq701MK.js → dagre-GXQ25YYZ-BgaTchbz.js} +1 -1
- package/dist/web/assets/{diagram-S7CK7UJ4-CNM_tSLn.js → diagram-S7CK7UJ4-BC0d5yAz.js} +1 -1
- package/dist/web/assets/{diagram-UQ7AKVKN-426C_diL.js → diagram-UQ7AKVKN-Bjm2wIY2.js} +1 -1
- package/dist/web/assets/{diagram-VSXAHHWV-t87gH2-E.js → diagram-VSXAHHWV-BcCWYw5W.js} +1 -1
- package/dist/web/assets/{diagram-VX7I27RA-DIRLLYsO.js → diagram-VX7I27RA-CzGzOQ_X.js} +1 -1
- package/dist/web/assets/{diagram-Z3DM3KII-RkCiIzTw.js → diagram-Z3DM3KII-CJZ8iKLl.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-PWID7BFC-BxwCYlSo.js → ebnfDiagram-PWID7BFC-DKTo52mJ.js} +1 -1
- package/dist/web/assets/{engine-BvPI6I9U.js → engine-DE1KkajI.js} +4 -4
- package/dist/web/assets/{erDiagram-RLTQ6QDP-CjSDwe_l.js → erDiagram-RLTQ6QDP-Cssct0LD.js} +1 -1
- package/dist/web/assets/es-Bz5daKQI.js +3 -0
- package/dist/web/assets/eventmodeling-NTZA5JFV-Cro5xJnm.js +1 -0
- package/dist/web/assets/flowDiagram-HODETNUW-BiyE5zC5.js +1 -0
- package/dist/web/assets/{ganttDiagram-EL5Y4UJY-CVCoGOMO.js → ganttDiagram-EL5Y4UJY-DO1wNnfK.js} +1 -1
- package/dist/web/assets/{gitGraph-4MIJSDKK-G0WgwH1G.js → gitGraph-4MIJSDKK-CjTm6VaR.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-WWUBYQGX-91LuiqmR.js → gitGraphDiagram-WWUBYQGX-DoNpr-oE.js} +1 -1
- package/dist/web/assets/goal-BaR-xr88.js +1 -0
- package/dist/web/assets/{highlight-CTIGnBaH.js → highlight-C4F9bqUR.js} +1 -1
- package/dist/web/assets/i18n-UlAtkmCh.js +3 -0
- package/dist/web/assets/{icons-DIySg7KB.js → icons-BED7nKDs.js} +1 -1
- package/dist/web/assets/index-BTLOG0A7.css +1 -0
- package/dist/web/assets/index-CueRFPg9.js +74 -0
- package/dist/web/assets/{info-A6RAGUB7-Cd1A2Eag.js → info-A6RAGUB7-D0RLRe9r.js} +1 -1
- package/dist/web/assets/{infoDiagram-27XIBGKW-BS-OvxCz.js → infoDiagram-27XIBGKW-Xvh_yq1U.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-5VMMS53U-Bv6pOCVs.js → ishikawaDiagram-5VMMS53U-CKMcZ3YE.js} +1 -1
- package/dist/web/assets/{journeyDiagram-3NMN7TZE-B1wOa8hE.js → journeyDiagram-3NMN7TZE-CH4U_78p.js} +1 -1
- package/dist/web/assets/jsxRuntime-BPMqVzHG.js +1 -0
- package/dist/web/assets/{kanban-definition-UXKFOSKX-BEGlHqwg.js → kanban-definition-UXKFOSKX-YDba8pTP.js} +1 -1
- package/dist/web/assets/{line-DacvQsry.js → line-5g6gTA1Q.js} +1 -1
- package/dist/web/assets/{mermaid-parser.core-nJHzUWWd.js → mermaid-parser.core-DgCR7nMS.js} +3 -3
- package/dist/web/assets/{mindmap-definition-YA3MSWOX-DYdF-ojf.js → mindmap-definition-YA3MSWOX-BFhIglWE.js} +1 -1
- package/dist/web/assets/{packet-AYTQ26CC-DBiUCtRk.js → packet-AYTQ26CC-Bx6BMrJt.js} +1 -1
- package/dist/web/assets/{pegDiagram-XKGWAZYB-MdKS7UKA.js → pegDiagram-XKGWAZYB-DfFISLjH.js} +1 -1
- package/dist/web/assets/{pie-WAS4IAKB-CZpqMsqb.js → pie-WAS4IAKB-LV0HnA-W.js} +1 -1
- package/dist/web/assets/{pieDiagram-E7YTZNPT-CovIn7J1.js → pieDiagram-E7YTZNPT-CepfvSOf.js} +1 -1
- package/dist/web/assets/preload-helper-B3nfOi5I.js +1 -0
- package/dist/web/assets/{quadrantDiagram-AXDQQJYC-DW5EcMtk.js → quadrantDiagram-AXDQQJYC-xPm2UUev.js} +1 -1
- package/dist/web/assets/{radar-RG4KPBEZ-CN_aPDyn.js → radar-RG4KPBEZ-V5htrwTl.js} +1 -1
- package/dist/web/assets/{railroad-74A4TZTK-C6cv8Byh.js → railroad-74A4TZTK-b1KQjCKl.js} +1 -1
- package/dist/web/assets/railroad-abnf-HS5TGJTU-DGo9EEg0.js +1 -0
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-pz5FmZJB.js +1 -0
- package/dist/web/assets/railroad-peg-WCYAUIDC-CaGbhEvZ.js +1 -0
- package/dist/web/assets/{railroadDiagram-O6MQD6OU-ph8nMiZB.js → railroadDiagram-O6MQD6OU-C7eNLTRf.js} +1 -1
- package/dist/web/assets/{requirementDiagram-BXWQKSXE-BGVse3WU.js → requirementDiagram-BXWQKSXE-CDkBY9hC.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-P5KCCOFB-BlqSlLfF.js → sankeyDiagram-P5KCCOFB-D3kcagKm.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-WJ2MYXX4-DVZcPeDh.js → sequenceDiagram-WJ2MYXX4-4bVDlu88.js} +1 -1
- package/dist/web/assets/settings-DTaiQjCk.css +1 -0
- package/dist/web/assets/settings.module-DoTtRfeo.js +1 -0
- package/dist/web/assets/shared-BLXABM7S.js +1 -0
- package/dist/web/assets/{stateDiagram-D77RDMKH-C71hZhx8.js → stateDiagram-D77RDMKH-ByCmUnvJ.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-MP3YSRHH-CRiIHTdb.js +1 -0
- package/dist/web/assets/{swimlanes-42K2YHIH-BBbsmiO3.js → swimlanes-42K2YHIH-C836H1FT.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-VR7AAH4N-CK7iFVSI.js +8 -0
- package/dist/web/assets/tasks-bt4HCPLT.js +1 -0
- package/dist/web/assets/{timeline-definition-24CTP7MA-C0hBvrpl.js → timeline-definition-24CTP7MA-C4pJeiqC.js} +1 -1
- package/dist/web/assets/{treeView-Q6P3EWNA-D3YSHcSl.js → treeView-Q6P3EWNA-LZesboxH.js} +1 -1
- package/dist/web/assets/{treemap-WGGIJYW6-CGGxdU_V.js → treemap-WGGIJYW6-Cl6Q6_3w.js} +1 -1
- package/dist/web/assets/{vennDiagram-4TSXK5OY-Bddm4uv_.js → vennDiagram-4TSXK5OY-Beflgatq.js} +1 -1
- package/dist/web/assets/view-C6h2Ru4M.js +2 -0
- package/dist/web/assets/view-CMC_gonE.js +1 -0
- package/dist/web/assets/view-CN5B3WOk.js +1 -0
- package/dist/web/assets/{view-C_yQ0o_1.js → view-Cp9Y-lvL.js} +1 -1
- package/dist/web/assets/view-CqbEmEgS.js +5 -0
- package/dist/web/assets/view-DT0FGd26.js +1 -0
- package/dist/web/assets/view-DfL_xTXC.js +6 -0
- package/dist/web/assets/{view-Dzj8qJWx.js → view-DlDHrSuL.js} +2 -2
- package/dist/web/assets/view-rB_-ym6G.js +1 -0
- package/dist/web/assets/visible-DLChI0F-.js +1 -0
- package/dist/web/assets/{wardley-WFR3VGLG-DA15PMFL.js → wardley-WFR3VGLG-BPBKdRq1.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-VM6X3IG4-DdznHZAA.js → wardleyDiagram-VM6X3IG4-BoH1N_OA.js} +1 -1
- package/dist/web/assets/{xychartDiagram-S5SC5T6Z-CoDcKI66.js → xychartDiagram-S5SC5T6Z-B9h0fFPk.js} +1 -1
- package/dist/web/index.html +9 -5
- package/package.json +4 -4
- package/dist/web/assets/AgentPicker-BjlBiN4-.js +0 -1
- package/dist/web/assets/AgentsModal-Byee_0pe.js +0 -2
- package/dist/web/assets/ArtifactPanel-BcSTmXfm.js +0 -2
- package/dist/web/assets/BtwPanel-B2-T36dM.js +0 -1
- package/dist/web/assets/SettingsModal-CJ9ylIBw.js +0 -1
- package/dist/web/assets/SpreadsheetPanel-CE0J9nlK.js +0 -1
- package/dist/web/assets/app-Bg0oN1mF.js +0 -2
- package/dist/web/assets/architecture-7GRP2DOG-Cmrq8Mal.js +0 -1
- package/dist/web/assets/channel-8oC5JRJN.js +0 -1
- package/dist/web/assets/chunk-DU6HZSFF-DXftN_bq.js +0 -125
- package/dist/web/assets/classDiagram-ZZMXUADV-BAAKVLjZ.js +0 -1
- package/dist/web/assets/classDiagram-v2-VYDZK3BY-BAAKVLjZ.js +0 -1
- package/dist/web/assets/eventmodeling-NTZA5JFV-D6SC9raY.js +0 -1
- package/dist/web/assets/flowDiagram-HODETNUW-CmC03NQq.js +0 -1
- package/dist/web/assets/index-CRb-14T4.css +0 -1
- package/dist/web/assets/index-z9ytfY6a.js +0 -74
- package/dist/web/assets/jsxRuntime-Dibtq2co.js +0 -5
- package/dist/web/assets/railroad-abnf-HS5TGJTU-qNOnds0e.js +0 -1
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-CiAajbqk.js +0 -1
- package/dist/web/assets/railroad-peg-WCYAUIDC-DWNjc-vb.js +0 -1
- package/dist/web/assets/shared-AIBQ1IP1.js +0 -1
- package/dist/web/assets/shared-DuS6eVxB.css +0 -1
- package/dist/web/assets/stateDiagram-v2-MP3YSRHH-B_lVvrO8.js +0 -1
- package/dist/web/assets/swimlanesDiagram-VR7AAH4N-_7TOzzT1.js +0 -8
- package/dist/web/assets/view-B9FRCDjf.js +0 -1
- package/dist/web/assets/view-BMxu6rtp.js +0 -1
- package/dist/web/assets/view-BoqU6MqN.js +0 -1
- package/dist/web/assets/view-D7N7RCo7.js +0 -2
- package/dist/web/assets/view-DNVoQwdm.js +0 -6
- package/dist/web/assets/view-DXUVAhlp.js +0 -5
- package/dist/web/assets/view-DeXp47AF.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { stat } from "node:fs/promises";
|
|
2
|
-
import { createApplication, findWorkspace, resolveTrust, workspaceKey, } from "@alisio/core";
|
|
2
|
+
import { createApplication, findWorkspace, ReloadFailedError, ReloadRefusedError, reloadApplication, resolveTrust, validateReloadConfig, workspaceKey, } from "@alisio/core";
|
|
3
3
|
import { HttpError } from "../http/errors.js";
|
|
4
4
|
const MISSING_ERRNO = new Set(["ENOENT", "ENOTDIR", "EACCES", "EPERM", "ELOOP"]);
|
|
5
5
|
const missing = (path) => new HttpError("workspace_missing", `Workspace folder not found: ${path}`, { path });
|
|
@@ -76,22 +76,25 @@ export class WorkspaceHost {
|
|
|
76
76
|
this.opening.set(id, promise);
|
|
77
77
|
return promise;
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Builds the `Application` of a workspace: launch flags are explicit, one-run trust like in the
|
|
81
|
+
* terminal; otherwise the trust store decides and a workspace that would need a prompt opens
|
|
82
|
+
* untrusted.
|
|
83
|
+
*/
|
|
84
|
+
async build(id, path) {
|
|
80
85
|
const base = this.options.base;
|
|
81
|
-
// Launch flags are explicit, one-run trust like in the terminal; otherwise the trust store
|
|
82
|
-
// decides and a workspace that would need a prompt opens untrusted.
|
|
83
86
|
const explicit = !!base.trustProject || !!base.config;
|
|
84
87
|
const trust = explicit ? undefined : await resolveTrust(path);
|
|
85
88
|
const trusted = explicit || !!trust?.trusted;
|
|
86
|
-
let app;
|
|
87
89
|
try {
|
|
88
|
-
app = await (this.options.create ?? createApplication)({
|
|
90
|
+
const app = await (this.options.create ?? createApplication)({
|
|
89
91
|
...base,
|
|
90
92
|
trustProject: explicit ? base.trustProject : trusted,
|
|
91
93
|
cwd: path,
|
|
92
94
|
approvalSource: "web",
|
|
93
95
|
...(this.options.wire?.(id, path) ?? {}),
|
|
94
96
|
});
|
|
97
|
+
return { app, trusted, untrustedResources: !trusted && !!trust?.hasProjectResources };
|
|
95
98
|
}
|
|
96
99
|
catch (error) {
|
|
97
100
|
// The folder vanished between the check and the open (the core canonicalizes it).
|
|
@@ -100,12 +103,15 @@ export class WorkspaceHost {
|
|
|
100
103
|
throw missing(path);
|
|
101
104
|
throw error;
|
|
102
105
|
}
|
|
106
|
+
}
|
|
107
|
+
async create(id, path) {
|
|
108
|
+
const { app, trusted, untrustedResources } = await this.build(id, path);
|
|
103
109
|
const entry = {
|
|
104
110
|
id,
|
|
105
111
|
path,
|
|
106
112
|
app,
|
|
107
113
|
trusted,
|
|
108
|
-
untrustedResources
|
|
114
|
+
untrustedResources,
|
|
109
115
|
lastUsed: this.now(),
|
|
110
116
|
};
|
|
111
117
|
if (this.closed) {
|
|
@@ -163,6 +169,56 @@ export class WorkspaceHost {
|
|
|
163
169
|
await this.close(id);
|
|
164
170
|
return this.openPath(entry.path);
|
|
165
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* `/reload` for one open workspace: validate, build the new app NEXT TO the current one and
|
|
174
|
+
* only then swap, so a broken configuration leaves the workspace and its sessions untouched
|
|
175
|
+
* (unlike `recycle`, which closes first). The caller refuses while runs are active (`busy`).
|
|
176
|
+
* SSE subscribers are unaffected: they read the shared store.
|
|
177
|
+
*/
|
|
178
|
+
async reload(id, guard = {}) {
|
|
179
|
+
const entry = this.open.get(id);
|
|
180
|
+
if (!entry)
|
|
181
|
+
throw new HttpError("not_found", "Workspace is not open");
|
|
182
|
+
const base = this.options.base;
|
|
183
|
+
let built;
|
|
184
|
+
try {
|
|
185
|
+
return await reloadApplication({
|
|
186
|
+
current: entry.app,
|
|
187
|
+
...(guard.busy ? { busy: guard.busy } : {}),
|
|
188
|
+
validate: async () => {
|
|
189
|
+
const explicit = !!base.trustProject || !!base.config;
|
|
190
|
+
const trust = explicit ? undefined : await resolveTrust(entry.path);
|
|
191
|
+
await validateReloadConfig({
|
|
192
|
+
...base,
|
|
193
|
+
cwd: entry.path,
|
|
194
|
+
trustProject: explicit ? base.trustProject : !!trust?.trusted,
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
create: async () => {
|
|
198
|
+
const next = await this.build(id, entry.path);
|
|
199
|
+
built = next;
|
|
200
|
+
return next.app;
|
|
201
|
+
},
|
|
202
|
+
swap: (next) => {
|
|
203
|
+
if (this.closed || this.open.get(id) !== entry)
|
|
204
|
+
throw new Error("The workspace was closed while reloading");
|
|
205
|
+
this.options.onClose?.(entry);
|
|
206
|
+
entry.app = next;
|
|
207
|
+
entry.trusted = built?.trusted ?? entry.trusted;
|
|
208
|
+
entry.untrustedResources = built?.untrustedResources ?? entry.untrustedResources;
|
|
209
|
+
entry.lastUsed = this.now();
|
|
210
|
+
this.options.onOpen?.(entry);
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (error instanceof ReloadRefusedError)
|
|
216
|
+
throw new HttpError("runs_active", error.message);
|
|
217
|
+
if (error instanceof ReloadFailedError)
|
|
218
|
+
throw new HttpError("validation_failed", `Reload failed; the current session is unchanged: ${error.message}`, { stage: error.stage });
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
166
222
|
/** Closes every app in parallel (each close is capped by the core's teardown timeouts). */
|
|
167
223
|
async closeAll() {
|
|
168
224
|
this.closed = true;
|
package/dist/http/errors.js
CHANGED
|
@@ -34,6 +34,13 @@ export const STATUS = {
|
|
|
34
34
|
dataset_unsupported: 415,
|
|
35
35
|
query_rejected: 400,
|
|
36
36
|
query_timeout: 408,
|
|
37
|
+
view_failed: 502,
|
|
38
|
+
view_timeout: 504,
|
|
39
|
+
view_too_large: 502,
|
|
40
|
+
task_not_found: 404,
|
|
41
|
+
goal_not_found: 404,
|
|
42
|
+
goal_conflict: 409,
|
|
43
|
+
goal_disabled: 409,
|
|
37
44
|
internal: 500,
|
|
38
45
|
};
|
|
39
46
|
/** A typed API failure; routes throw it and the server renders it as an `ApiError` body. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ServerResponse } from "node:http";
|
|
2
|
+
import { type AppOptions } from "@alisio/core";
|
|
2
3
|
import { type FolderPicker } from "./host/folder-picker.ts";
|
|
3
4
|
import { type ServerAppOptions } from "./host/workspace-host.ts";
|
|
4
5
|
import { type Logger } from "./log.ts";
|
|
@@ -53,6 +54,13 @@ export interface ServerOptions {
|
|
|
53
54
|
* tests. Always off when the server is bound for remote access.
|
|
54
55
|
*/
|
|
55
56
|
folderPicker?: FolderPicker;
|
|
57
|
+
/** Limits of plugin data views (`GET /api/sessions/:sid/views/…`): 5 s and 1 MiB by default. */
|
|
58
|
+
views?: {
|
|
59
|
+
timeoutMs?: number;
|
|
60
|
+
maxBytes?: number;
|
|
61
|
+
};
|
|
62
|
+
/** Background-task runtime knobs (notification timing, kill grace, limits): tests tune them. */
|
|
63
|
+
tasks?: Pick<NonNullable<AppOptions["tasks"]>, "timing" | "sweepDelayMs" | "killGraceMs" | "maxPerProcess">;
|
|
56
64
|
}
|
|
57
65
|
export interface RunningServer {
|
|
58
66
|
host: string;
|
package/dist/index.js
CHANGED
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
6
|
import { createServer } from "node:http";
|
|
7
7
|
import { dirname, join } from "node:path";
|
|
8
|
-
import { AnalysisJobs, ArtifactStore, BlobStore, CapabilityGrants, SQLiteStore, stateHome, } from "@alisio/core";
|
|
8
|
+
import { AnalysisJobs, ArtifactStore, BackgroundTaskStore, BlobStore, CapabilityGrants, GoalStore, SQLiteStore, stateHome, } from "@alisio/core";
|
|
9
9
|
import { AuthGuard, isLoopbackHost } from "./auth/guard.js";
|
|
10
10
|
import { newSecret } from "./auth/token.js";
|
|
11
11
|
import { redactViewPath } from "./auth/view-token.js";
|
|
12
12
|
import { ApprovalBridge } from "./bridges/approval-bridge.js";
|
|
13
13
|
import { InteractionBridge } from "./bridges/interaction-bridge.js";
|
|
14
14
|
import { createNativePicker } from "./host/folder-picker.js";
|
|
15
|
+
import { GoalDriver } from "./host/goal.js";
|
|
16
|
+
import { followUpPlanRun } from "./host/plan.js";
|
|
15
17
|
import { RunScheduler } from "./host/run-scheduler.js";
|
|
16
18
|
import { SessionService } from "./host/sessions.js";
|
|
17
19
|
import { WorkspaceHost, workspaceId } from "./host/workspace-host.js";
|
|
@@ -25,18 +27,22 @@ import { registerArtifactViewRoutes, VIEW_PREFIX, viewerBaseHeaders, } from "./r
|
|
|
25
27
|
import { registerArtifactRoutes } from "./routes/artifacts.js";
|
|
26
28
|
import { registerBlobRoutes } from "./routes/blobs.js";
|
|
27
29
|
import { registerCapabilityRoutes } from "./routes/capabilities.js";
|
|
30
|
+
import { registerChangelogRoutes } from "./routes/changelog.js";
|
|
28
31
|
import { registerCommandRoutes } from "./routes/commands.js";
|
|
29
32
|
import { registerDatasetRoutes } from "./routes/datasets.js";
|
|
30
33
|
import { registerEventRoutes } from "./routes/events.js";
|
|
31
34
|
import { registerFileRoutes } from "./routes/files.js";
|
|
32
35
|
import { registerFolderRoutes } from "./routes/folders.js";
|
|
36
|
+
import { registerGoalRoutes } from "./routes/goal.js";
|
|
33
37
|
import { registerHealthRoutes } from "./routes/health.js";
|
|
34
38
|
import { registerManagementRoutes, WorkspaceRecycler } from "./routes/management.js";
|
|
39
|
+
import { registerPluginViewRoutes } from "./routes/plugin-views.js";
|
|
35
40
|
import { registerPromptRoutes } from "./routes/prompts.js";
|
|
36
41
|
import { registerProviderRoutes } from "./routes/providers.js";
|
|
37
42
|
import { registerSessionViewRoutes } from "./routes/session-views.js";
|
|
38
43
|
import { registerSessionRoutes } from "./routes/sessions.js";
|
|
39
44
|
import { registerSideQuestionRoutes } from "./routes/side-questions.js";
|
|
45
|
+
import { registerTaskRoutes } from "./routes/tasks.js";
|
|
40
46
|
import { registerWorkspaceRoutes } from "./routes/workspaces.js";
|
|
41
47
|
import { SseHub } from "./sse/hub.js";
|
|
42
48
|
import { InflightTracker } from "./sse/inflight.js";
|
|
@@ -93,21 +99,60 @@ export async function startServer(options = {}) {
|
|
|
93
99
|
// process become interrupted before any client lists them.
|
|
94
100
|
catalog.interruptRuns();
|
|
95
101
|
catalog.interruptStale();
|
|
102
|
+
// Background tasks of a dead server or TUI process become `lost` (a live process's are kept).
|
|
103
|
+
new BackgroundTaskStore(catalog.db).markLost(Date.now());
|
|
104
|
+
// A goal left `active` by a process that is gone pauses (reason `restart`); it never resumes by
|
|
105
|
+
// itself, the user decides.
|
|
106
|
+
new GoalStore(catalog.db).pauseOrphans(Date.now());
|
|
96
107
|
let shutdown;
|
|
97
108
|
let sessions;
|
|
98
109
|
const inflight = new InflightTracker();
|
|
99
110
|
let recycler;
|
|
111
|
+
let goalDriver;
|
|
100
112
|
const scheduler = new RunScheduler({
|
|
101
113
|
...(options.maxConcurrentRuns ? { maxConcurrent: options.maxConcurrentRuns } : {}),
|
|
102
|
-
onChange: (job, status) => {
|
|
114
|
+
onChange: (job, status, outcome) => {
|
|
103
115
|
if (status === "finished") {
|
|
104
116
|
inflight.clear(job.sessionId, job.runId);
|
|
105
117
|
// A deferred plugin change applies once the workspace has no runs left.
|
|
106
118
|
setImmediate(() => recycler?.idle(job.workspaceId));
|
|
119
|
+
// A finished-task notification held back because this session was busy may go now.
|
|
120
|
+
setImmediate(() => job.app.tasks.sessionIdle(job.sessionId));
|
|
121
|
+
// An approved plan starts its implementation run once the plan run is over.
|
|
122
|
+
if (sessions && !job.tool)
|
|
123
|
+
try {
|
|
124
|
+
followUpPlanRun({
|
|
125
|
+
job,
|
|
126
|
+
cancelled: !!outcome?.cancelled,
|
|
127
|
+
catalog,
|
|
128
|
+
sessions,
|
|
129
|
+
scheduler,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
logger.error("plan_follow_up_failed", {
|
|
134
|
+
sessionId: job.sessionId,
|
|
135
|
+
error: error instanceof Error ? error.message : String(error),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// The run is folded into the session's goal (tokens, turns, breakers), and the goal may
|
|
139
|
+
// continue: the pump runs after this tick so the plan follow-up above (if any) goes first.
|
|
140
|
+
if (outcome && !job.tool)
|
|
141
|
+
try {
|
|
142
|
+
goalDriver?.settle(job, outcome);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
logger.error("goal_settle_failed", {
|
|
146
|
+
sessionId: job.sessionId,
|
|
147
|
+
error: error instanceof Error ? error.message : String(error),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
setImmediate(() => goalDriver?.pump(job.sessionId));
|
|
107
151
|
}
|
|
108
152
|
else
|
|
109
153
|
inflight.mark(job.sessionId, job.runId, status);
|
|
110
154
|
sessions?.notify(job.sessionId);
|
|
155
|
+
goalDriver?.refresh(job.sessionId);
|
|
111
156
|
},
|
|
112
157
|
});
|
|
113
158
|
const workspaceOf = (sessionId) => {
|
|
@@ -140,6 +185,7 @@ export async function startServer(options = {}) {
|
|
|
140
185
|
approvals: approvals?.pending(sessionId) ?? [],
|
|
141
186
|
interactions: interactions?.pending(sessionId) ?? [],
|
|
142
187
|
},
|
|
188
|
+
...(goalDriver?.info(sessionId) ? { goal: goalDriver.info(sessionId) } : {}),
|
|
143
189
|
};
|
|
144
190
|
},
|
|
145
191
|
messagesAfter: (sessionId, after) => catalog.messagesPage(sessionId, { after, limit: 200 }),
|
|
@@ -148,10 +194,62 @@ export async function startServer(options = {}) {
|
|
|
148
194
|
...(options.heartbeatMs ? { heartbeatMs: options.heartbeatMs } : {}),
|
|
149
195
|
...(options.coalesceMs ? { coalesceMs: options.coalesceMs } : {}),
|
|
150
196
|
});
|
|
197
|
+
/** Whether a workspace's application has live background tasks (it must not be closed). */
|
|
198
|
+
const tasksLive = (id) => (workspaces.get(id)?.app.tasks.liveCount() ?? 0) > 0;
|
|
199
|
+
/**
|
|
200
|
+
* The finished-task notification: a normal run of the owner session whose request id is the
|
|
201
|
+
* batch id (like the plan approval's `plan-<id>`), so the same batch can never start two runs.
|
|
202
|
+
* `runner.enqueue` would only park the text until the next run, so the wake-up goes through the
|
|
203
|
+
* scheduler. Busy sessions (a run, an approval or question, another process holding the
|
|
204
|
+
* session) answer `busy` and the core retries; archived or missing ones answer `skip`.
|
|
205
|
+
*/
|
|
206
|
+
const wakeOwner = (workspaceKey, request) => {
|
|
207
|
+
if (closing || !sessions)
|
|
208
|
+
return "skip";
|
|
209
|
+
let session;
|
|
210
|
+
try {
|
|
211
|
+
session = catalog.get(request.sessionId);
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return "skip";
|
|
215
|
+
}
|
|
216
|
+
const opened = workspaces.get(workspaceKey);
|
|
217
|
+
if (session.parentId || session.archivedAt || !opened)
|
|
218
|
+
return "skip";
|
|
219
|
+
if (catalog.lockedBy(session.id) ||
|
|
220
|
+
scheduler.busy(session.id) ||
|
|
221
|
+
opened.app.runner.isRunning(session.id) ||
|
|
222
|
+
approvals?.awaiting(session.id) ||
|
|
223
|
+
interactions?.awaiting(session.id))
|
|
224
|
+
return "busy";
|
|
225
|
+
const correlationId = randomUUID();
|
|
226
|
+
const { run, created } = sessions.beginRun({
|
|
227
|
+
id: randomUUID(),
|
|
228
|
+
session: session.id,
|
|
229
|
+
status: "queued",
|
|
230
|
+
requestId: request.requestId,
|
|
231
|
+
correlationId,
|
|
232
|
+
model: session.model,
|
|
233
|
+
});
|
|
234
|
+
if (!created)
|
|
235
|
+
return "started";
|
|
236
|
+
const service = sessions;
|
|
237
|
+
scheduler.submit({
|
|
238
|
+
runId: run.id,
|
|
239
|
+
sessionId: session.id,
|
|
240
|
+
workspaceId: opened.id,
|
|
241
|
+
app: opened.app,
|
|
242
|
+
text: request.text,
|
|
243
|
+
display: request.display,
|
|
244
|
+
correlationId,
|
|
245
|
+
options: () => service.runOptions(session.id),
|
|
246
|
+
});
|
|
247
|
+
return "started";
|
|
248
|
+
};
|
|
151
249
|
const workspaces = new WorkspaceHost({
|
|
152
250
|
base,
|
|
153
251
|
catalog,
|
|
154
|
-
wire: () => ({
|
|
252
|
+
wire: (id) => ({
|
|
155
253
|
onEvent: (event) => {
|
|
156
254
|
inflight.apply(event);
|
|
157
255
|
hub.publish(event);
|
|
@@ -165,12 +263,31 @@ export async function startServer(options = {}) {
|
|
|
165
263
|
...(approvals
|
|
166
264
|
? { approve: approvals.handler, approveExternalDirectory: approvals.directoryHandler }
|
|
167
265
|
: {}),
|
|
266
|
+
tasks: {
|
|
267
|
+
...(options.tasks ?? {}),
|
|
268
|
+
onChange: (task, root) => {
|
|
269
|
+
hub.toSession(root, { t: "tasks_changed", sessionId: root, task });
|
|
270
|
+
// A goal waiting for background tasks continues once the last one is over.
|
|
271
|
+
if (task.status !== "running" && task.status !== "queued" && task.status !== "stopping")
|
|
272
|
+
setImmediate(() => goalDriver?.pump(root));
|
|
273
|
+
else
|
|
274
|
+
goalDriver?.refresh(root);
|
|
275
|
+
// A deferred recycle (a plugin change) goes ahead once the last task is over.
|
|
276
|
+
if (task.status !== "running" && task.status !== "queued" && task.status !== "stopping") {
|
|
277
|
+
const owner = workspaceOf(root);
|
|
278
|
+
if (owner)
|
|
279
|
+
setImmediate(() => recycler?.idle(owner));
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
wake: (request) => wakeOwner(id, request),
|
|
283
|
+
},
|
|
284
|
+
goals: { onChange: (sessionId) => goalDriver?.refresh(sessionId) },
|
|
168
285
|
}),
|
|
169
286
|
onOpen: (entry) => {
|
|
170
287
|
if (interactions)
|
|
171
288
|
entry.app.plugins.setInteractiveUI(interactions.uiFor(entry.id));
|
|
172
289
|
},
|
|
173
|
-
busy: (id) => scheduler.busyWorkspace(id) || hub.watchesWorkspace(id),
|
|
290
|
+
busy: (id) => scheduler.busyWorkspace(id) || hub.watchesWorkspace(id) || tasksLive(id),
|
|
174
291
|
...(options.maxOpenWorkspaces ? { maxOpen: options.maxOpenWorkspaces } : {}),
|
|
175
292
|
...(options.idleEvictMs ? { idleEvictMs: options.idleEvictMs } : {}),
|
|
176
293
|
...(options.defaultWorkspace ? { defaultWorkspace: options.defaultWorkspace } : {}),
|
|
@@ -192,7 +309,10 @@ export async function startServer(options = {}) {
|
|
|
192
309
|
runOf: (id) => scheduler.job(id)?.runId,
|
|
193
310
|
...(options.approvalGraceMs !== undefined ? { graceMs: options.approvalGraceMs } : {}),
|
|
194
311
|
...(options.approvalTimeoutMs !== undefined ? { timeoutMs: options.approvalTimeoutMs } : {}),
|
|
195
|
-
onChange: (root) =>
|
|
312
|
+
onChange: (root) => {
|
|
313
|
+
service.notify(root);
|
|
314
|
+
goalDriver?.refresh(root);
|
|
315
|
+
},
|
|
196
316
|
});
|
|
197
317
|
interactions = new InteractionBridge({
|
|
198
318
|
hub,
|
|
@@ -200,8 +320,37 @@ export async function startServer(options = {}) {
|
|
|
200
320
|
workspaceOf,
|
|
201
321
|
...(options.approvalGraceMs !== undefined ? { graceMs: options.approvalGraceMs } : {}),
|
|
202
322
|
...(options.approvalTimeoutMs !== undefined ? { timeoutMs: options.approvalTimeoutMs } : {}),
|
|
203
|
-
onOpen: (id) =>
|
|
204
|
-
|
|
323
|
+
onOpen: (id) => {
|
|
324
|
+
service.notify(id);
|
|
325
|
+
goalDriver?.refresh(id);
|
|
326
|
+
},
|
|
327
|
+
onChange: (root) => {
|
|
328
|
+
if (!root)
|
|
329
|
+
return;
|
|
330
|
+
service.notify(root);
|
|
331
|
+
goalDriver?.refresh(root);
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
goalDriver = new GoalDriver({
|
|
335
|
+
catalog,
|
|
336
|
+
sessions: () => service,
|
|
337
|
+
scheduler: () => scheduler,
|
|
338
|
+
workspaces: () => workspaces,
|
|
339
|
+
awaiting: (root) => approvals?.awaiting(root)
|
|
340
|
+
? "approval"
|
|
341
|
+
: interactions?.awaiting(root)
|
|
342
|
+
? "question"
|
|
343
|
+
: undefined,
|
|
344
|
+
toSession: (sessionId, frame) => hub.toSession(sessionId, frame),
|
|
345
|
+
closing: () => closing,
|
|
346
|
+
log: (event, data) => logger.error(event, data),
|
|
347
|
+
});
|
|
348
|
+
// A session option (the agent, say) changed: the plan-mode wait of a goal may be over.
|
|
349
|
+
service.bind({
|
|
350
|
+
onOptions: (sessionId) => {
|
|
351
|
+
goalDriver?.refresh(sessionId);
|
|
352
|
+
setImmediate(() => goalDriver?.pump(sessionId));
|
|
353
|
+
},
|
|
205
354
|
});
|
|
206
355
|
const stats = () => ({
|
|
207
356
|
shuttingDown: closing,
|
|
@@ -228,6 +377,13 @@ export async function startServer(options = {}) {
|
|
|
228
377
|
registerWorkspaceRoutes(router, { workspaces, catalog, scheduler });
|
|
229
378
|
registerSessionRoutes(router, { catalog, workspaces, sessions, scheduler });
|
|
230
379
|
registerSessionViewRoutes(router, { catalog, sessions });
|
|
380
|
+
registerPluginViewRoutes(router, {
|
|
381
|
+
sessions,
|
|
382
|
+
workspaces,
|
|
383
|
+
logger,
|
|
384
|
+
...(options.views?.timeoutMs !== undefined ? { timeoutMs: options.views.timeoutMs } : {}),
|
|
385
|
+
...(options.views?.maxBytes !== undefined ? { maxBytes: options.views.maxBytes } : {}),
|
|
386
|
+
});
|
|
231
387
|
registerFileRoutes(router, { workspaces, catalog, sessions });
|
|
232
388
|
registerBlobRoutes(router, { blobs });
|
|
233
389
|
registerArtifactRoutes(router, {
|
|
@@ -251,16 +407,28 @@ export async function startServer(options = {}) {
|
|
|
251
407
|
toSession: (sessionId, frame) => hub.toSession(sessionId, frame),
|
|
252
408
|
});
|
|
253
409
|
registerPromptRoutes(router, { sessions, scheduler });
|
|
254
|
-
|
|
255
|
-
registerSideQuestionRoutes(router, { sessions });
|
|
256
|
-
registerApprovalRoutes(router, { approvals, interactions });
|
|
410
|
+
registerGoalRoutes(router, { sessions, goals: goalDriver });
|
|
257
411
|
const management = {
|
|
258
412
|
workspaces,
|
|
259
413
|
scheduler,
|
|
414
|
+
tasksLive,
|
|
260
415
|
base,
|
|
261
416
|
broadcast: (frame) => hub.broadcast(frame),
|
|
262
417
|
};
|
|
263
418
|
recycler = new WorkspaceRecycler(management);
|
|
419
|
+
const reloader = recycler;
|
|
420
|
+
registerChangelogRoutes(router, { version: options.version ?? "dev" });
|
|
421
|
+
registerCommandRoutes(router, {
|
|
422
|
+
sessions,
|
|
423
|
+
scheduler,
|
|
424
|
+
workspaces,
|
|
425
|
+
reload: (workspaceId) => reloader.reload(workspaceId),
|
|
426
|
+
...(goalDriver ? { goals: goalDriver } : {}),
|
|
427
|
+
version: options.version ?? "dev",
|
|
428
|
+
});
|
|
429
|
+
registerSideQuestionRoutes(router, { sessions });
|
|
430
|
+
registerTaskRoutes(router, { sessions });
|
|
431
|
+
registerApprovalRoutes(router, { approvals, interactions });
|
|
264
432
|
registerManagementRoutes(router, management, recycler);
|
|
265
433
|
registerAgentDefinitionRoutes(router, management, recycler);
|
|
266
434
|
registerProviderRoutes(router, management, recycler);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Router } from "../http/router.ts";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /api/changelog?version=&lastSeen=`: the shipped `CHANGELOG.md` entries (offline, parsed at
|
|
4
|
+
* build time), the newest five or the one `version` names, plus `news` when `lastSeen` is older
|
|
5
|
+
* than the running version. Same auth, Host and Origin rules as every other `/api` route.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerChangelogRoutes(router: Router, options: {
|
|
8
|
+
version: string;
|
|
9
|
+
}): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { changelogNews, loadChangelog, selectEntries } from "@alisio/core";
|
|
2
|
+
import { HttpError } from "../http/errors.js";
|
|
3
|
+
const MAX_QUERY = 100;
|
|
4
|
+
/**
|
|
5
|
+
* `GET /api/changelog?version=&lastSeen=`: the shipped `CHANGELOG.md` entries (offline, parsed at
|
|
6
|
+
* build time), the newest five or the one `version` names, plus `news` when `lastSeen` is older
|
|
7
|
+
* than the running version. Same auth, Host and Origin rules as every other `/api` route.
|
|
8
|
+
*/
|
|
9
|
+
export function registerChangelogRoutes(router, options) {
|
|
10
|
+
router.get("/api/changelog", ({ url }) => {
|
|
11
|
+
const text = (name) => {
|
|
12
|
+
const value = url.searchParams.get(name)?.trim();
|
|
13
|
+
if (value && value.length > MAX_QUERY)
|
|
14
|
+
throw new HttpError("validation_failed", "Invalid query parameter", { fields: [name] });
|
|
15
|
+
return value || undefined;
|
|
16
|
+
};
|
|
17
|
+
const version = text("version");
|
|
18
|
+
const lastSeen = text("lastSeen");
|
|
19
|
+
const entries = loadChangelog();
|
|
20
|
+
const selected = selectEntries(entries, { ...(version ? { version } : {}), limit: 5 });
|
|
21
|
+
const news = changelogNews({ entries, current: options.version, lastSeen });
|
|
22
|
+
const body = {
|
|
23
|
+
current: options.version,
|
|
24
|
+
entries: selected.entries,
|
|
25
|
+
found: selected.found,
|
|
26
|
+
...(news.show && news.latest
|
|
27
|
+
? { news: { latest: news.latest, versions: news.versions } }
|
|
28
|
+
: {}),
|
|
29
|
+
};
|
|
30
|
+
return { body };
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ReloadReport } from "@alisio/sdk";
|
|
2
|
+
import type { GoalDriver } from "../host/goal.ts";
|
|
1
3
|
import type { RunScheduler } from "../host/run-scheduler.ts";
|
|
2
4
|
import type { SessionService } from "../host/sessions.ts";
|
|
3
5
|
import type { WorkspaceHost } from "../host/workspace-host.ts";
|
|
@@ -18,4 +20,10 @@ export declare function registerCommandRoutes(router: Router, ctx: {
|
|
|
18
20
|
scheduler: RunScheduler;
|
|
19
21
|
workspaces: WorkspaceHost;
|
|
20
22
|
recent?: RecentRequests;
|
|
23
|
+
/** `/reload` of a workspace (validate, build next to the current app, swap, announce). */
|
|
24
|
+
reload?: (workspaceId: string) => Promise<ReloadReport>;
|
|
25
|
+
/** The running Alisio version (the CLI's), for `/changelog`. */
|
|
26
|
+
version?: string;
|
|
27
|
+
/** `/goal`: the driver that makes a goal continue and reports what it waits for. */
|
|
28
|
+
goals?: Pick<GoalDriver, "info" | "pump" | "refresh">;
|
|
21
29
|
}): void;
|