@geminixiang/mikan 1.0.0-beta.61 → 1.0.0-beta.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +16 -14
- package/dist/adapters/commands/sandbox.d.ts.map +1 -1
- package/dist/adapters/commands/sandbox.js +30 -53
- package/dist/adapters/commands/sandbox.js.map +1 -1
- package/dist/adapters/commands/types.d.ts +3 -3
- package/dist/adapters/commands/types.d.ts.map +1 -1
- package/dist/adapters/commands/types.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +15 -3
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +50 -14
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/web/admin/portal.d.ts +1 -1
- package/dist/adapters/web/admin/portal.d.ts.map +1 -1
- package/dist/adapters/web/admin/portal.js +61 -146
- package/dist/adapters/web/admin/portal.js.map +1 -1
- package/dist/adapters/web/admin/types.d.ts +6 -3
- package/dist/adapters/web/admin/types.d.ts.map +1 -1
- package/dist/adapters/web/admin/types.js.map +1 -1
- package/dist/adapters/web/server.d.ts +3 -0
- package/dist/adapters/web/server.d.ts.map +1 -1
- package/dist/adapters/web/server.js +4 -6
- package/dist/adapters/web/server.js.map +1 -1
- package/dist/cli/boot.js +1 -1
- package/dist/cli/boot.js.map +1 -1
- package/dist/cli/office.d.ts.map +1 -1
- package/dist/cli/office.js +66 -0
- package/dist/cli/office.js.map +1 -1
- package/dist/config.d.ts +13 -10
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -54
- package/dist/config.js.map +1 -1
- package/dist/env-manifest.js +3 -3
- package/dist/env-manifest.js.map +1 -1
- package/dist/events/index.d.ts +56 -34
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +114 -23
- package/dist/events/index.js.map +1 -1
- package/dist/events/scheduler.d.ts +34 -0
- package/dist/events/scheduler.d.ts.map +1 -0
- package/dist/events/scheduler.js +231 -0
- package/dist/events/scheduler.js.map +1 -0
- package/dist/harness/execution-resolver.d.ts.map +1 -1
- package/dist/harness/execution-resolver.js +1 -1
- package/dist/harness/execution-resolver.js.map +1 -1
- package/dist/harness/mcp.d.ts.map +1 -1
- package/dist/harness/mcp.js +1 -3
- package/dist/harness/mcp.js.map +1 -1
- package/dist/harness/open-connector.d.ts +21 -10
- package/dist/harness/open-connector.d.ts.map +1 -1
- package/dist/harness/open-connector.js +109 -135
- package/dist/harness/open-connector.js.map +1 -1
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +19 -23
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +26 -11
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/tools/event.d.ts +1 -1
- package/dist/harness/tools/event.d.ts.map +1 -1
- package/dist/harness/tools/event.js +19 -22
- package/dist/harness/tools/event.js.map +1 -1
- package/dist/harness/tools/index.d.ts +2 -1
- package/dist/harness/tools/index.d.ts.map +1 -1
- package/dist/harness/tools/index.js +2 -3
- package/dist/harness/tools/index.js.map +1 -1
- package/dist/main.js +17 -9
- package/dist/main.js.map +1 -1
- package/dist/office/index.d.ts +3 -2
- package/dist/office/index.d.ts.map +1 -1
- package/dist/office/index.js +3 -3
- package/dist/office/index.js.map +1 -1
- package/dist/office/projection.d.ts +19 -2
- package/dist/office/projection.d.ts.map +1 -1
- package/dist/office/projection.js +73 -100
- package/dist/office/projection.js.map +1 -1
- package/dist/office/types.d.ts +13 -10
- package/dist/office/types.d.ts.map +1 -1
- package/dist/office/types.js.map +1 -1
- package/dist/runtime/conversation-runtime.js +1 -0
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +4 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/index.d.ts +9 -1
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +16 -12
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/provisioner.d.ts +8 -0
- package/dist/sandbox/provisioner.d.ts.map +1 -1
- package/dist/sandbox/provisioner.js +36 -0
- package/dist/sandbox/provisioner.js.map +1 -1
- package/dist/settings-mutation.d.ts +5 -29
- package/dist/settings-mutation.d.ts.map +1 -1
- package/dist/settings-mutation.js +7 -13
- package/dist/settings-mutation.js.map +1 -1
- package/dist/types.d.ts +11 -27
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -1
- package/dist/events/watcher.d.ts +0 -43
- package/dist/events/watcher.d.ts.map +0 -1
- package/dist/events/watcher.js +0 -395
- package/dist/events/watcher.js.map +0 -1
|
@@ -40,5 +40,5 @@ export declare function readSkillsFromDir(skillsDir: string, source: SkillEntry[
|
|
|
40
40
|
* event-format module (files that fail validation stay visible with a null
|
|
41
41
|
* payload so operators can delete them).
|
|
42
42
|
*/
|
|
43
|
-
export declare function
|
|
43
|
+
export declare function listOfficeEvents(store: EventStore): Promise<EventSummary[]>;
|
|
44
44
|
//# sourceMappingURL=portal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../../src/adapters/web/admin/portal.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,qBAAa,uBAAwB,SAAQ,kBAAkB,CAAC,UAAU,CAAC;IACzE,MAAM,CAAC,IAAI,EAAE;QACX,QAAQ,EAAE,YAAY,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,GAAG,UAAU,CAUb;CACF;
|
|
1
|
+
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../../src/adapters/web/admin/portal.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,qBAAa,uBAAwB,SAAQ,kBAAkB,CAAC,UAAU,CAAC;IACzE,MAAM,CAAC,IAAI,EAAE;QACX,QAAQ,EAAE,YAAY,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,GAAG,UAAU,CAUb;CACF;AAoCD,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAYzD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAwGD,UAAU,sBAAsB;IAC9B,OAAO,EAAE,aAAa,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,UAAU,GAChB,sBAAsB,CAexB;AA28BD,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,GAAG,cAAc,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAwBD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,UAAU,EAAE,CAuB/F;AAqRD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAmBjF"}
|
|
@@ -16,11 +16,11 @@ export class InMemoryAdminTokenStore extends InMemoryTokenStore {
|
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
import {
|
|
19
|
+
import { loadOfficeVisibilityOverride, loadGlobalSettings, loadScopeMcpServers, resolveConversationSettings, } from "../../../config.js";
|
|
20
20
|
import { findMcpPreset, listMcpPresets, materializeMcpPreset } from "../../../harness/mcp.js";
|
|
21
21
|
import { loadMcpTools } from "../../../harness/mcp.js";
|
|
22
22
|
import { isValidMcpServerName, parseStandardMcpServers, redactMcpUrl, } from "../../../harness/mcp.js";
|
|
23
|
-
import { applyConversationSettings,
|
|
23
|
+
import { applyConversationSettings, applyOfficeVisibility, applyGlobalSettings, } from "../../../settings-mutation.js";
|
|
24
24
|
import { escapeHtml, jsonResponse as jsonRes, readJsonBody, renderPortalShell, } from "../portal-shell.js";
|
|
25
25
|
import { resolveExistingSessionFile } from "../session-view/portal.js";
|
|
26
26
|
import { PRODUCT_NAME } from "../../../platform-messages.js";
|
|
@@ -115,8 +115,8 @@ async function routePostApiRequest(req, res, url, services) {
|
|
|
115
115
|
switch (url.pathname) {
|
|
116
116
|
case "/admin/api/conversations/model":
|
|
117
117
|
return serveConversationModelUpdate(res, body, services, token);
|
|
118
|
-
case "/admin/api/conversations/
|
|
119
|
-
return
|
|
118
|
+
case "/admin/api/conversations/visibility":
|
|
119
|
+
return serveConversationVisibilityUpdate(res, body, services, token);
|
|
120
120
|
case "/admin/api/conversations/slack":
|
|
121
121
|
return serveConversationSlackUpdate(res, body, services, token);
|
|
122
122
|
case "/admin/api/conversations/session-link":
|
|
@@ -129,8 +129,6 @@ async function routePostApiRequest(req, res, url, services) {
|
|
|
129
129
|
return serveMcpServerMutation(res, body, services, token);
|
|
130
130
|
case "/admin/api/settings/model":
|
|
131
131
|
return serveGlobalModelUpdate(res, body, services);
|
|
132
|
-
case "/admin/api/settings/workspace":
|
|
133
|
-
return serveGlobalWorkspaceUpdate(res, body, services);
|
|
134
132
|
case "/admin/api/settings/sandbox":
|
|
135
133
|
return serveGlobalSandboxUpdate(res, body, services);
|
|
136
134
|
case "/admin/api/settings/slack":
|
|
@@ -443,7 +441,6 @@ function serveConversationState(res, url, services, token) {
|
|
|
443
441
|
const globalConfig = loadGlobalSettings();
|
|
444
442
|
const conversationConfig = resolveConversationSettings(office);
|
|
445
443
|
const conversationWorkspace = resolveWorkspaceProjection(office);
|
|
446
|
-
const globalWorkspaceSettings = globalConfig.sandbox?.workspace;
|
|
447
444
|
jsonRes(res, 200, {
|
|
448
445
|
conversationId,
|
|
449
446
|
provider: conversationConfig.provider,
|
|
@@ -452,13 +449,10 @@ function serveConversationState(res, url, services, token) {
|
|
|
452
449
|
globalProvider: globalConfig.provider,
|
|
453
450
|
globalModel: globalConfig.model,
|
|
454
451
|
globalThinkingLevel: globalConfig.thinkingLevel,
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
globalWorkspaceDoorPolicy: globalWorkspaceSettings?.doorPolicy ?? "isolated",
|
|
460
|
-
globalWorkspaceLayout: globalWorkspaceSettings?.layout ?? "conversation",
|
|
461
|
-
globalWorkspaceVisibility: globalWorkspaceSettings?.visibility ?? "public",
|
|
452
|
+
officeVisibility: conversationWorkspace.visibility,
|
|
453
|
+
officeVisibilitySource: conversationWorkspace.source,
|
|
454
|
+
officeVisibilityOverride: loadOfficeVisibilityOverride(office),
|
|
455
|
+
officeLegacyFull: conversationWorkspace.legacyFull,
|
|
462
456
|
slack: {
|
|
463
457
|
replyMode: conversationConfig.slack?.replyMode ?? globalConfig.slack?.replyMode ?? "top-level",
|
|
464
458
|
globalReplyMode: globalConfig.slack?.replyMode ?? "top-level",
|
|
@@ -476,9 +470,6 @@ function serveGlobalSettings(res) {
|
|
|
476
470
|
sandboxMemory: config.sandbox?.memory ?? null,
|
|
477
471
|
sandboxBoostCpus: config.sandbox?.boost?.cpus ?? null,
|
|
478
472
|
sandboxBoostMemory: config.sandbox?.boost?.memory ?? null,
|
|
479
|
-
workspaceDoorPolicy: config.sandbox?.workspace?.doorPolicy ?? null,
|
|
480
|
-
workspaceLayout: config.sandbox?.workspace?.layout ?? null,
|
|
481
|
-
workspaceVisibility: config.sandbox?.workspace?.visibility ?? null,
|
|
482
473
|
defaultSharedVault: config.sandbox?.defaultSharedVault ?? null,
|
|
483
474
|
slack: {
|
|
484
475
|
replyMode: config.slack?.replyMode ?? "top-level",
|
|
@@ -543,48 +534,9 @@ function serveConversationModelUpdate(res, body, services, token) {
|
|
|
543
534
|
jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });
|
|
544
535
|
}
|
|
545
536
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
* MEMORY.md; `trusted-shared-support-private` is the same layout with the
|
|
550
|
-
* shared MEMORY.md mounted read-only (modeled on Claude Tag's private-
|
|
551
|
-
* channel memory: read the shared pool, never write into it).
|
|
552
|
-
*/
|
|
553
|
-
function parseDoorPolicyChoice(value) {
|
|
554
|
-
switch (value) {
|
|
555
|
-
case "default":
|
|
556
|
-
return { choice: null };
|
|
557
|
-
case "isolated":
|
|
558
|
-
return { choice: { doorPolicy: "isolated" } };
|
|
559
|
-
case "trusted-shared-support":
|
|
560
|
-
return { choice: { doorPolicy: "trusted", layout: "shared-support", visibility: "public" } };
|
|
561
|
-
case "trusted-shared-support-private":
|
|
562
|
-
return {
|
|
563
|
-
choice: { doorPolicy: "trusted", layout: "shared-support", visibility: "private" },
|
|
564
|
-
};
|
|
565
|
-
case "trusted-full":
|
|
566
|
-
return { choice: { doorPolicy: "trusted", layout: "full" } };
|
|
567
|
-
default:
|
|
568
|
-
return undefined;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
function doorPolicyChoiceKey(choice) {
|
|
572
|
-
if (!choice)
|
|
573
|
-
return "default";
|
|
574
|
-
if (choice.doorPolicy === "isolated")
|
|
575
|
-
return "isolated";
|
|
576
|
-
if (choice.layout === "full")
|
|
577
|
-
return "trusted-full";
|
|
578
|
-
return choice.visibility === "private"
|
|
579
|
-
? "trusted-shared-support-private"
|
|
580
|
-
: "trusted-shared-support";
|
|
581
|
-
}
|
|
582
|
-
function serveConversationSandboxUpdate(res, body, services, token) {
|
|
583
|
-
const parsed = parseDoorPolicyChoice(body.doorPolicy);
|
|
584
|
-
if (!parsed) {
|
|
585
|
-
jsonRes(res, 400, {
|
|
586
|
-
error: "doorPolicy must be 'default', 'isolated', 'trusted-shared-support', 'trusted-shared-support-private', or 'trusted-full'",
|
|
587
|
-
});
|
|
537
|
+
function serveConversationVisibilityUpdate(res, body, services, token) {
|
|
538
|
+
if (body.visibility !== "private" && body.visibility !== "default") {
|
|
539
|
+
jsonRes(res, 400, { error: "visibility must be 'private' or 'default'" });
|
|
588
540
|
return;
|
|
589
541
|
}
|
|
590
542
|
const target = requireConversationWorkspace(res, body, services, token);
|
|
@@ -592,7 +544,7 @@ function serveConversationSandboxUpdate(res, body, services, token) {
|
|
|
592
544
|
return;
|
|
593
545
|
const { scope, workspace } = target;
|
|
594
546
|
try {
|
|
595
|
-
const result =
|
|
547
|
+
const result = applyOfficeVisibility(services.runtime, workspace.office(scope.address), body.visibility === "private" ? "private" : null);
|
|
596
548
|
if (!result.ok) {
|
|
597
549
|
jsonRes(res, 409, { error: "Conversation is busy; retry when the current run finishes" });
|
|
598
550
|
return;
|
|
@@ -603,19 +555,6 @@ function serveConversationSandboxUpdate(res, body, services, token) {
|
|
|
603
555
|
jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });
|
|
604
556
|
}
|
|
605
557
|
}
|
|
606
|
-
function serveGlobalWorkspaceUpdate(res, body, services) {
|
|
607
|
-
const parsed = parseDoorPolicyChoice(body.doorPolicy);
|
|
608
|
-
if (!parsed) {
|
|
609
|
-
jsonRes(res, 400, {
|
|
610
|
-
error: "doorPolicy must be 'default', 'isolated', 'trusted-shared-support', 'trusted-shared-support-private', or 'trusted-full'",
|
|
611
|
-
});
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
respondWithSettingsUpdate(res, () => {
|
|
615
|
-
const result = applyGlobalWorkspacePolicy(services.runtime, parsed.choice);
|
|
616
|
-
return { ok: true, staleConversations: result.staleConversations.length };
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
558
|
function serveConversationSlackUpdate(res, body, services, token) {
|
|
620
559
|
const replyMode = body.replyMode;
|
|
621
560
|
if (replyMode !== "top-level" && replyMode !== "thread") {
|
|
@@ -1289,12 +1228,14 @@ function serveSkillFile(res, url, services, token) {
|
|
|
1289
1228
|
* event-format module (files that fail validation stay visible with a null
|
|
1290
1229
|
* payload so operators can delete them).
|
|
1291
1230
|
*/
|
|
1292
|
-
export async function
|
|
1231
|
+
export async function listOfficeEvents(store) {
|
|
1293
1232
|
const entries = await store.list();
|
|
1294
1233
|
return entries.map((entry) => {
|
|
1295
1234
|
const payload = entry.payload;
|
|
1296
1235
|
return {
|
|
1297
1236
|
name: entry.filename,
|
|
1237
|
+
officePlatform: store.address.platform,
|
|
1238
|
+
officeConversationId: store.address.conversationId,
|
|
1298
1239
|
size: entry.size,
|
|
1299
1240
|
mtimeMs: entry.mtimeMs,
|
|
1300
1241
|
type: payload?.type ?? null,
|
|
@@ -1307,31 +1248,45 @@ export async function listAllEvents(store) {
|
|
|
1307
1248
|
};
|
|
1308
1249
|
});
|
|
1309
1250
|
}
|
|
1310
|
-
function requireAdminEventStore(res, services) {
|
|
1251
|
+
function requireAdminEventStore(res, services, office) {
|
|
1311
1252
|
if (!services.eventStore) {
|
|
1312
1253
|
jsonRes(res, 503, { error: "Working directory not available" });
|
|
1313
1254
|
return null;
|
|
1314
1255
|
}
|
|
1315
|
-
return services.eventStore;
|
|
1256
|
+
return services.eventStore(office);
|
|
1316
1257
|
}
|
|
1258
|
+
/** Every registered office's events, each read through its own store. */
|
|
1317
1259
|
async function serveEventsList(res, services) {
|
|
1318
|
-
const
|
|
1319
|
-
if (!
|
|
1260
|
+
const workspace = requireAdminWorkspace(res, services);
|
|
1261
|
+
if (!workspace)
|
|
1320
1262
|
return;
|
|
1321
|
-
|
|
1263
|
+
if (!services.eventStore) {
|
|
1264
|
+
jsonRes(res, 503, { error: "Working directory not available" });
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
const events = [];
|
|
1268
|
+
for (const record of listRegisteredOffices(workspace.stateDir)) {
|
|
1269
|
+
events.push(...(await listOfficeEvents(services.eventStore(workspace.office(record)))));
|
|
1270
|
+
}
|
|
1271
|
+
jsonRes(res, 200, { events });
|
|
1322
1272
|
}
|
|
1323
|
-
/** Per-conversation listing
|
|
1273
|
+
/** Per-conversation listing through that office's confined store. */
|
|
1324
1274
|
async function serveConversationEventsList(res, url, services, token) {
|
|
1325
1275
|
const scope = resolveConversationFromQuery(url, token);
|
|
1326
1276
|
if (scope.error) {
|
|
1327
1277
|
jsonRes(res, 403, { error: scope.error });
|
|
1328
1278
|
return;
|
|
1329
1279
|
}
|
|
1330
|
-
const
|
|
1280
|
+
const workspace = requireAdminWorkspace(res, services);
|
|
1281
|
+
if (!workspace)
|
|
1282
|
+
return;
|
|
1283
|
+
const store = requireAdminEventStore(res, services, workspace.office(scope.address));
|
|
1331
1284
|
if (!store)
|
|
1332
1285
|
return;
|
|
1333
|
-
|
|
1334
|
-
|
|
1286
|
+
jsonRes(res, 200, {
|
|
1287
|
+
conversationId: scope.conversationId,
|
|
1288
|
+
events: await listOfficeEvents(store),
|
|
1289
|
+
});
|
|
1335
1290
|
}
|
|
1336
1291
|
/** Delete a single event file scoped to the caller's conversation. */
|
|
1337
1292
|
async function serveConversationEventDelete(res, body, services, token) {
|
|
@@ -1348,28 +1303,20 @@ async function serveConversationEventDelete(res, body, services, token) {
|
|
|
1348
1303
|
jsonRes(res, 400, { error: "Invalid name" });
|
|
1349
1304
|
return;
|
|
1350
1305
|
}
|
|
1351
|
-
const
|
|
1352
|
-
if (!
|
|
1353
|
-
return;
|
|
1354
|
-
let payload;
|
|
1355
|
-
try {
|
|
1356
|
-
payload = (await store.read(name)).payload;
|
|
1357
|
-
}
|
|
1358
|
-
catch {
|
|
1359
|
-
jsonRes(res, 404, { error: "Event not found" });
|
|
1306
|
+
const workspace = requireAdminWorkspace(res, services);
|
|
1307
|
+
if (!workspace)
|
|
1360
1308
|
return;
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
if (payload?.conversationId !== scope.conversationId) {
|
|
1364
|
-
jsonRes(res, 403, { error: "Event does not belong to this conversation." });
|
|
1309
|
+
const store = requireAdminEventStore(res, services, workspace.office(scope.address));
|
|
1310
|
+
if (!store)
|
|
1365
1311
|
return;
|
|
1366
|
-
|
|
1312
|
+
// The store is confined to this office: another office's filename is "not found".
|
|
1367
1313
|
try {
|
|
1368
1314
|
await store.delete(name);
|
|
1369
1315
|
jsonRes(res, 200, { ok: true });
|
|
1370
1316
|
}
|
|
1371
1317
|
catch (err) {
|
|
1372
|
-
|
|
1318
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1319
|
+
jsonRes(res, /not found/.test(message) ? 404 : 500, { error: message });
|
|
1373
1320
|
}
|
|
1374
1321
|
}
|
|
1375
1322
|
// ── Utilities ──────────────────────────────────────────────────────────────────
|
|
@@ -1840,23 +1787,12 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
|
|
|
1840
1787
|
function renderReplyOptions(slack) {
|
|
1841
1788
|
return renderOptions(['top-level','thread'].map((m) => [m, m]), (slack && slack.replyMode) || 'top-level');
|
|
1842
1789
|
}
|
|
1843
|
-
function renderDoorOptions(value, channel) {
|
|
1844
|
-
return renderOptions([
|
|
1845
|
-
['default', 'Automatic — follows ' + channel + ' platform channel (public shares, private reads only, DMs isolated)'],
|
|
1846
|
-
['isolated', 'isolated — own office only'],
|
|
1847
|
-
['trusted-shared-support', 'trusted / shared-support (public) — office + shared memory, skills, events — read-write'],
|
|
1848
|
-
['trusted-shared-support-private', 'trusted / shared-support (private) — same, but shared MEMORY.md is read-only'],
|
|
1849
|
-
['trusted-full', 'trusted / full — entire workspace'],
|
|
1850
|
-
], value);
|
|
1851
|
-
}
|
|
1852
|
-
|
|
1853
1790
|
function renderSettings(data) {
|
|
1854
1791
|
const thinkingOpts = renderThinkingOptions(data.thinkingLevel);
|
|
1855
1792
|
const replyModeOpts = renderReplyOptions(data.slack);
|
|
1856
1793
|
const globalReplyMode = (data.slack && data.slack.globalReplyMode) || 'top-level';
|
|
1857
1794
|
const globalModel = [data.globalProvider, data.globalModel].filter(Boolean).join('/');
|
|
1858
1795
|
const globalModelLabel = globalModel + (data.globalThinkingLevel ? ':' + data.globalThinkingLevel : '');
|
|
1859
|
-
const doorPolicyOpts = renderDoorOptions(data.workspaceOverride || 'default', 'the');
|
|
1860
1796
|
return [
|
|
1861
1797
|
'<div class="config-grid">',
|
|
1862
1798
|
renderConfigCard('Model', [
|
|
@@ -1865,11 +1801,19 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
|
|
|
1865
1801
|
'<p class="muted-note">Global default: ' + escHtml(globalModelLabel) + '</p>',
|
|
1866
1802
|
].join(''), 'saveModel', 'Save model', 'model-save-result'),
|
|
1867
1803
|
|
|
1868
|
-
renderConfigCard('Office
|
|
1869
|
-
'<div class="config-row"><label>
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1804
|
+
renderConfigCard('Office visibility', [
|
|
1805
|
+
'<div class="config-row"><label>Visibility</label><select id="m-visibility">' +
|
|
1806
|
+
renderOptions([
|
|
1807
|
+
['default', 'Follow the Slack conversation type (default)'],
|
|
1808
|
+
['private', 'Private — treat this public channel as private'],
|
|
1809
|
+
], data.officeVisibilityOverride === 'private' ? 'private' : 'default') + '</select></div>',
|
|
1810
|
+
'<p class="muted-note">Effective: <strong>' + escHtml(data.officeVisibility) + '</strong> · ' + escHtml(
|
|
1811
|
+
data.officeVisibilitySource === 'override' ? 'set here'
|
|
1812
|
+
: data.officeVisibilitySource === 'platform' ? 'from the Slack conversation type'
|
|
1813
|
+
: 'conversation type unknown; private until observed') + '</p>',
|
|
1814
|
+
'<p class="muted-note">Public offices can be read by every other office and may write shared MEMORY.md and skills. Private offices (private channels, DMs) are visible only to themselves and read shared knowledge without writing it. Nothing can be made more visible than Slack allows.</p>',
|
|
1815
|
+
(data.officeLegacyFull ? '<p class="muted-note">This office still declares the retired <code>full</code> door policy; it no longer widens access.</p>' : ''),
|
|
1816
|
+
].join(''), 'saveVisibility', 'Save visibility', 'mount-save-result'),
|
|
1873
1817
|
renderConfigCard('Slack', [
|
|
1874
1818
|
'<div class="config-row"><label>Reply mode</label><select id="m-slack-reply-mode">' + replyModeOpts + '</select></div>',
|
|
1875
1819
|
'<p class="muted-note">Global default: ' + escHtml(globalReplyMode) + '</p>',
|
|
@@ -1898,10 +1842,10 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
|
|
|
1898
1842
|
await saveConversationSetting(btn, result, 'slack', { replyMode }, 'Save Slack');
|
|
1899
1843
|
}
|
|
1900
1844
|
|
|
1901
|
-
async function
|
|
1902
|
-
const
|
|
1845
|
+
async function saveVisibility(btn) {
|
|
1846
|
+
const visibility = document.getElementById('m-visibility').value;
|
|
1903
1847
|
const result = document.getElementById('mount-save-result');
|
|
1904
|
-
await saveConversationSetting(btn, result, '
|
|
1848
|
+
await saveConversationSetting(btn, result, 'visibility', { visibility }, 'Save visibility', loadSettings);
|
|
1905
1849
|
}
|
|
1906
1850
|
|
|
1907
1851
|
function saveConversationSetting(btn, result, setting, values, label, onSaved) {
|
|
@@ -2666,14 +2610,6 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
|
|
|
2666
2610
|
function renderGlobalSettings(data) {
|
|
2667
2611
|
const thinkingOpts = renderThinkingOptions(data.thinkingLevel);
|
|
2668
2612
|
const replyModeOpts = renderReplyOptions(data.slack);
|
|
2669
|
-
const gDoorKey = !data.workspaceDoorPolicy
|
|
2670
|
-
? 'default'
|
|
2671
|
-
: (data.workspaceDoorPolicy === 'isolated'
|
|
2672
|
-
? 'isolated'
|
|
2673
|
-
: (data.workspaceLayout === 'full'
|
|
2674
|
-
? 'trusted-full'
|
|
2675
|
-
: ((data.workspaceVisibility || 'public') === 'private' ? 'trusted-shared-support-private' : 'trusted-shared-support')));
|
|
2676
|
-
const gDoorPolicyOpts = renderDoorOptions(gDoorKey, 'each');
|
|
2677
2613
|
return [
|
|
2678
2614
|
'<div class="config-grid">',
|
|
2679
2615
|
renderConfigCard('Default model', [
|
|
@@ -2686,10 +2622,6 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
|
|
|
2686
2622
|
'<div class="config-row"><label>Boost CPUs</label><input id="g-bcpus" placeholder="2" value="' + escAttr(data.sandboxBoostCpus || '') + '"></div>',
|
|
2687
2623
|
'<div class="config-row"><label>Boost Mem</label><input id="g-bmem" placeholder="4g" value="' + escAttr(data.sandboxBoostMemory || '') + '"></div>',
|
|
2688
2624
|
].join(''), 'saveGlobalSandbox', 'Save sandbox', 'g-sandbox-result'),
|
|
2689
|
-
renderConfigCard('Office door policy', [
|
|
2690
|
-
'<div class="config-row"><label>Default</label><select id="g-door-policy">' + gDoorPolicyOpts + '</select></div>',
|
|
2691
|
-
'<p class="muted-note">Applies to offices without their own policy. Affected offices rebuild their sandbox container with the new mounts on the next message; container contents are preserved.</p>',
|
|
2692
|
-
].join(''), 'saveGlobalWorkspace', 'Save door policy', 'g-workspace-result'),
|
|
2693
2625
|
renderConfigCard('Slack', [
|
|
2694
2626
|
'<div class="config-row"><label>Reply mode</label><select id="g-slack-reply-mode">' + replyModeOpts + '</select></div>',
|
|
2695
2627
|
].join(''), 'saveGlobalSlack', 'Save Slack', 'g-slack-result'),
|
|
@@ -2727,23 +2659,6 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
|
|
|
2727
2659
|
await saveSetting(btn, result, 'settings/sandbox', { cpus, memory, boostCpus, boostMemory }, 'Save sandbox');
|
|
2728
2660
|
}
|
|
2729
2661
|
|
|
2730
|
-
async function saveGlobalWorkspace(btn) {
|
|
2731
|
-
const doorPolicy = document.getElementById('g-door-policy').value;
|
|
2732
|
-
const result = document.getElementById('g-workspace-result');
|
|
2733
|
-
btn.disabled = true; btn.textContent = 'Saving…'; result.style.display = 'none';
|
|
2734
|
-
try {
|
|
2735
|
-
const data = await apiPost('/admin/api/settings/workspace', { doorPolicy });
|
|
2736
|
-
result.style.display = 'block'; result.className = 'inline-result ok';
|
|
2737
|
-
result.textContent = data.staleConversations > 0
|
|
2738
|
-
? 'Saved ✓ (' + data.staleConversations + ' busy conversation(s) refresh after their current run)'
|
|
2739
|
-
: 'Saved ✓';
|
|
2740
|
-
} catch (err) {
|
|
2741
|
-
result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;
|
|
2742
|
-
} finally {
|
|
2743
|
-
btn.disabled = false; btn.textContent = 'Save door policy';
|
|
2744
|
-
}
|
|
2745
|
-
}
|
|
2746
|
-
|
|
2747
2662
|
async function saveGlobalSlack(btn) {
|
|
2748
2663
|
const replyMode = document.getElementById('g-slack-reply-mode').value;
|
|
2749
2664
|
const result = document.getElementById('g-slack-result');
|