@geminixiang/mikan 1.0.0-beta.62 → 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.
Files changed (51) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +13 -13
  3. package/dist/adapters/commands/sandbox.d.ts.map +1 -1
  4. package/dist/adapters/commands/sandbox.js +30 -53
  5. package/dist/adapters/commands/sandbox.js.map +1 -1
  6. package/dist/adapters/commands/types.d.ts +3 -3
  7. package/dist/adapters/commands/types.d.ts.map +1 -1
  8. package/dist/adapters/commands/types.js.map +1 -1
  9. package/dist/adapters/slack/bot.d.ts +8 -0
  10. package/dist/adapters/slack/bot.d.ts.map +1 -1
  11. package/dist/adapters/slack/bot.js +32 -2
  12. package/dist/adapters/slack/bot.js.map +1 -1
  13. package/dist/adapters/web/admin/portal.d.ts.map +1 -1
  14. package/dist/adapters/web/admin/portal.js +28 -121
  15. package/dist/adapters/web/admin/portal.js.map +1 -1
  16. package/dist/config.d.ts +13 -10
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js +31 -50
  19. package/dist/config.js.map +1 -1
  20. package/dist/harness/execution-resolver.d.ts.map +1 -1
  21. package/dist/harness/execution-resolver.js +1 -1
  22. package/dist/harness/execution-resolver.js.map +1 -1
  23. package/dist/harness/prompt.d.ts.map +1 -1
  24. package/dist/harness/prompt.js +17 -21
  25. package/dist/harness/prompt.js.map +1 -1
  26. package/dist/harness/runner.d.ts.map +1 -1
  27. package/dist/harness/runner.js +2 -2
  28. package/dist/harness/runner.js.map +1 -1
  29. package/dist/office/projection.d.ts +19 -2
  30. package/dist/office/projection.d.ts.map +1 -1
  31. package/dist/office/projection.js +73 -98
  32. package/dist/office/projection.js.map +1 -1
  33. package/dist/office/types.d.ts +13 -8
  34. package/dist/office/types.d.ts.map +1 -1
  35. package/dist/office/types.js.map +1 -1
  36. package/dist/sandbox/index.d.ts +9 -1
  37. package/dist/sandbox/index.d.ts.map +1 -1
  38. package/dist/sandbox/index.js +16 -12
  39. package/dist/sandbox/index.js.map +1 -1
  40. package/dist/sandbox/provisioner.d.ts +8 -0
  41. package/dist/sandbox/provisioner.d.ts.map +1 -1
  42. package/dist/sandbox/provisioner.js +36 -0
  43. package/dist/sandbox/provisioner.js.map +1 -1
  44. package/dist/settings-mutation.d.ts +5 -29
  45. package/dist/settings-mutation.d.ts.map +1 -1
  46. package/dist/settings-mutation.js +7 -13
  47. package/dist/settings-mutation.js.map +1 -1
  48. package/dist/types.d.ts +5 -23
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/types.js.map +1 -1
  51. package/package.json +1 -1
@@ -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;AAsCD,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;AA0GD,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;AA8gCD,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"}
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 { loadConversationWorkspaceOverride, loadGlobalSettings, loadScopeMcpServers, resolveConversationSettings, } from "../../../config.js";
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, applyConversationWorkspacePolicy, applyGlobalSettings, applyGlobalWorkspacePolicy, } from "../../../settings-mutation.js";
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/sandbox":
119
- return serveConversationSandboxUpdate(res, body, services, token);
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
- workspaceDoorPolicy: conversationWorkspace.doorPolicy,
456
- workspaceLayout: conversationWorkspace.layout,
457
- workspaceVisibility: conversationWorkspace.visibility,
458
- workspaceOverride: doorPolicyChoiceKey(loadConversationWorkspaceOverride(office)),
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
- * Wire values for a door-policy selection; "default" clears the office's
548
- * override. `trusted-shared-support` keeps the historical read-write shared
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 = applyConversationWorkspacePolicy(services.runtime, workspace.office(scope.address), parsed.choice);
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") {
@@ -1848,23 +1787,12 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
1848
1787
  function renderReplyOptions(slack) {
1849
1788
  return renderOptions(['top-level','thread'].map((m) => [m, m]), (slack && slack.replyMode) || 'top-level');
1850
1789
  }
1851
- function renderDoorOptions(value, channel) {
1852
- return renderOptions([
1853
- ['default', 'Automatic — follows ' + channel + ' platform channel (public shares, private reads only, DMs isolated)'],
1854
- ['isolated', 'isolated — own office only'],
1855
- ['trusted-shared-support', 'trusted / shared-support (public) — office + shared memory, skills, events — read-write'],
1856
- ['trusted-shared-support-private', 'trusted / shared-support (private) — same, but shared MEMORY.md is read-only'],
1857
- ['trusted-full', 'trusted / full — entire workspace'],
1858
- ], value);
1859
- }
1860
-
1861
1790
  function renderSettings(data) {
1862
1791
  const thinkingOpts = renderThinkingOptions(data.thinkingLevel);
1863
1792
  const replyModeOpts = renderReplyOptions(data.slack);
1864
1793
  const globalReplyMode = (data.slack && data.slack.globalReplyMode) || 'top-level';
1865
1794
  const globalModel = [data.globalProvider, data.globalModel].filter(Boolean).join('/');
1866
1795
  const globalModelLabel = globalModel + (data.globalThinkingLevel ? ':' + data.globalThinkingLevel : '');
1867
- const doorPolicyOpts = renderDoorOptions(data.workspaceOverride || 'default', 'the');
1868
1796
  return [
1869
1797
  '<div class="config-grid">',
1870
1798
  renderConfigCard('Model', [
@@ -1873,11 +1801,19 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
1873
1801
  '<p class="muted-note">Global default: ' + escHtml(globalModelLabel) + '</p>',
1874
1802
  ].join(''), 'saveModel', 'Save model', 'model-save-result'),
1875
1803
 
1876
- renderConfigCard('Office data policy', [
1877
- '<div class="config-row"><label>Door policy</label><select id="m-door-policy">' + doorPolicyOpts + '</select></div>',
1878
- '<p class="muted-note">Effective: ' + escHtml(data.workspaceDoorPolicy + ' / ' + data.workspaceLayout + ' / ' + (data.workspaceVisibility || 'public')) + '</p>',
1879
- '<p class="muted-note">Changing the policy rebuilds the office sandbox container with the new mounts on its next message; the container contents are preserved.</p>',
1880
- ].join(''), 'saveDoorPolicy', 'Save door policy', 'mount-save-result'),
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'),
1881
1817
  renderConfigCard('Slack', [
1882
1818
  '<div class="config-row"><label>Reply mode</label><select id="m-slack-reply-mode">' + replyModeOpts + '</select></div>',
1883
1819
  '<p class="muted-note">Global default: ' + escHtml(globalReplyMode) + '</p>',
@@ -1906,10 +1842,10 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
1906
1842
  await saveConversationSetting(btn, result, 'slack', { replyMode }, 'Save Slack');
1907
1843
  }
1908
1844
 
1909
- async function saveDoorPolicy(btn) {
1910
- const doorPolicy = document.getElementById('m-door-policy').value;
1845
+ async function saveVisibility(btn) {
1846
+ const visibility = document.getElementById('m-visibility').value;
1911
1847
  const result = document.getElementById('mount-save-result');
1912
- await saveConversationSetting(btn, result, 'sandbox', { doorPolicy }, 'Save door policy', loadSettings);
1848
+ await saveConversationSetting(btn, result, 'visibility', { visibility }, 'Save visibility', loadSettings);
1913
1849
  }
1914
1850
 
1915
1851
  function saveConversationSetting(btn, result, setting, values, label, onSaved) {
@@ -2674,14 +2610,6 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
2674
2610
  function renderGlobalSettings(data) {
2675
2611
  const thinkingOpts = renderThinkingOptions(data.thinkingLevel);
2676
2612
  const replyModeOpts = renderReplyOptions(data.slack);
2677
- const gDoorKey = !data.workspaceDoorPolicy
2678
- ? 'default'
2679
- : (data.workspaceDoorPolicy === 'isolated'
2680
- ? 'isolated'
2681
- : (data.workspaceLayout === 'full'
2682
- ? 'trusted-full'
2683
- : ((data.workspaceVisibility || 'public') === 'private' ? 'trusted-shared-support-private' : 'trusted-shared-support')));
2684
- const gDoorPolicyOpts = renderDoorOptions(gDoorKey, 'each');
2685
2613
  return [
2686
2614
  '<div class="config-grid">',
2687
2615
  renderConfigCard('Default model', [
@@ -2694,10 +2622,6 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
2694
2622
  '<div class="config-row"><label>Boost CPUs</label><input id="g-bcpus" placeholder="2" value="' + escAttr(data.sandboxBoostCpus || '') + '"></div>',
2695
2623
  '<div class="config-row"><label>Boost Mem</label><input id="g-bmem" placeholder="4g" value="' + escAttr(data.sandboxBoostMemory || '') + '"></div>',
2696
2624
  ].join(''), 'saveGlobalSandbox', 'Save sandbox', 'g-sandbox-result'),
2697
- renderConfigCard('Office door policy', [
2698
- '<div class="config-row"><label>Default</label><select id="g-door-policy">' + gDoorPolicyOpts + '</select></div>',
2699
- '<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>',
2700
- ].join(''), 'saveGlobalWorkspace', 'Save door policy', 'g-workspace-result'),
2701
2625
  renderConfigCard('Slack', [
2702
2626
  '<div class="config-row"><label>Reply mode</label><select id="g-slack-reply-mode">' + replyModeOpts + '</select></div>',
2703
2627
  ].join(''), 'saveGlobalSlack', 'Save Slack', 'g-slack-result'),
@@ -2735,23 +2659,6 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
2735
2659
  await saveSetting(btn, result, 'settings/sandbox', { cpus, memory, boostCpus, boostMemory }, 'Save sandbox');
2736
2660
  }
2737
2661
 
2738
- async function saveGlobalWorkspace(btn) {
2739
- const doorPolicy = document.getElementById('g-door-policy').value;
2740
- const result = document.getElementById('g-workspace-result');
2741
- btn.disabled = true; btn.textContent = 'Saving…'; result.style.display = 'none';
2742
- try {
2743
- const data = await apiPost('/admin/api/settings/workspace', { doorPolicy });
2744
- result.style.display = 'block'; result.className = 'inline-result ok';
2745
- result.textContent = data.staleConversations > 0
2746
- ? 'Saved ✓ (' + data.staleConversations + ' busy conversation(s) refresh after their current run)'
2747
- : 'Saved ✓';
2748
- } catch (err) {
2749
- result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;
2750
- } finally {
2751
- btn.disabled = false; btn.textContent = 'Save door policy';
2752
- }
2753
- }
2754
-
2755
2662
  async function saveGlobalSlack(btn) {
2756
2663
  const replyMode = document.getElementById('g-slack-reply-mode').value;
2757
2664
  const result = document.getElementById('g-slack-result');