@geminixiang/mikan 1.0.0-beta.62 → 1.0.0-beta.64

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 (56) hide show
  1. package/CHANGELOG.md +26 -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 +26 -121
  15. package/dist/adapters/web/admin/portal.js.map +1 -1
  16. package/dist/cli/boot.js +1 -1
  17. package/dist/cli/boot.js.map +1 -1
  18. package/dist/cli/office.d.ts.map +1 -1
  19. package/dist/cli/office.js +33 -1
  20. package/dist/cli/office.js.map +1 -1
  21. package/dist/config.d.ts +26 -11
  22. package/dist/config.d.ts.map +1 -1
  23. package/dist/config.js +103 -61
  24. package/dist/config.js.map +1 -1
  25. package/dist/harness/execution-resolver.d.ts.map +1 -1
  26. package/dist/harness/execution-resolver.js +1 -1
  27. package/dist/harness/execution-resolver.js.map +1 -1
  28. package/dist/harness/prompt.d.ts.map +1 -1
  29. package/dist/harness/prompt.js +17 -21
  30. package/dist/harness/prompt.js.map +1 -1
  31. package/dist/harness/runner.d.ts.map +1 -1
  32. package/dist/harness/runner.js +2 -2
  33. package/dist/harness/runner.js.map +1 -1
  34. package/dist/office/projection.d.ts +19 -2
  35. package/dist/office/projection.d.ts.map +1 -1
  36. package/dist/office/projection.js +67 -99
  37. package/dist/office/projection.js.map +1 -1
  38. package/dist/office/types.d.ts +7 -8
  39. package/dist/office/types.d.ts.map +1 -1
  40. package/dist/office/types.js.map +1 -1
  41. package/dist/sandbox/index.d.ts +9 -1
  42. package/dist/sandbox/index.d.ts.map +1 -1
  43. package/dist/sandbox/index.js +16 -12
  44. package/dist/sandbox/index.js.map +1 -1
  45. package/dist/sandbox/provisioner.d.ts +8 -0
  46. package/dist/sandbox/provisioner.d.ts.map +1 -1
  47. package/dist/sandbox/provisioner.js +36 -0
  48. package/dist/sandbox/provisioner.js.map +1 -1
  49. package/dist/settings-mutation.d.ts +5 -29
  50. package/dist/settings-mutation.d.ts.map +1 -1
  51. package/dist/settings-mutation.js +7 -13
  52. package/dist/settings-mutation.js.map +1 -1
  53. package/dist/types.d.ts +2 -32
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/types.js.map +1 -1
  56. 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;AA08BD,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,9 @@ 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),
462
455
  slack: {
463
456
  replyMode: conversationConfig.slack?.replyMode ?? globalConfig.slack?.replyMode ?? "top-level",
464
457
  globalReplyMode: globalConfig.slack?.replyMode ?? "top-level",
@@ -476,9 +469,6 @@ function serveGlobalSettings(res) {
476
469
  sandboxMemory: config.sandbox?.memory ?? null,
477
470
  sandboxBoostCpus: config.sandbox?.boost?.cpus ?? null,
478
471
  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
472
  defaultSharedVault: config.sandbox?.defaultSharedVault ?? null,
483
473
  slack: {
484
474
  replyMode: config.slack?.replyMode ?? "top-level",
@@ -543,48 +533,9 @@ function serveConversationModelUpdate(res, body, services, token) {
543
533
  jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });
544
534
  }
545
535
  }
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
- });
536
+ function serveConversationVisibilityUpdate(res, body, services, token) {
537
+ if (body.visibility !== "private" && body.visibility !== "default") {
538
+ jsonRes(res, 400, { error: "visibility must be 'private' or 'default'" });
588
539
  return;
589
540
  }
590
541
  const target = requireConversationWorkspace(res, body, services, token);
@@ -592,7 +543,7 @@ function serveConversationSandboxUpdate(res, body, services, token) {
592
543
  return;
593
544
  const { scope, workspace } = target;
594
545
  try {
595
- const result = applyConversationWorkspacePolicy(services.runtime, workspace.office(scope.address), parsed.choice);
546
+ const result = applyOfficeVisibility(services.runtime, workspace.office(scope.address), body.visibility === "private" ? "private" : null);
596
547
  if (!result.ok) {
597
548
  jsonRes(res, 409, { error: "Conversation is busy; retry when the current run finishes" });
598
549
  return;
@@ -603,19 +554,6 @@ function serveConversationSandboxUpdate(res, body, services, token) {
603
554
  jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });
604
555
  }
605
556
  }
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
557
  function serveConversationSlackUpdate(res, body, services, token) {
620
558
  const replyMode = body.replyMode;
621
559
  if (replyMode !== "top-level" && replyMode !== "thread") {
@@ -1848,23 +1786,12 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
1848
1786
  function renderReplyOptions(slack) {
1849
1787
  return renderOptions(['top-level','thread'].map((m) => [m, m]), (slack && slack.replyMode) || 'top-level');
1850
1788
  }
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
1789
  function renderSettings(data) {
1862
1790
  const thinkingOpts = renderThinkingOptions(data.thinkingLevel);
1863
1791
  const replyModeOpts = renderReplyOptions(data.slack);
1864
1792
  const globalReplyMode = (data.slack && data.slack.globalReplyMode) || 'top-level';
1865
1793
  const globalModel = [data.globalProvider, data.globalModel].filter(Boolean).join('/');
1866
1794
  const globalModelLabel = globalModel + (data.globalThinkingLevel ? ':' + data.globalThinkingLevel : '');
1867
- const doorPolicyOpts = renderDoorOptions(data.workspaceOverride || 'default', 'the');
1868
1795
  return [
1869
1796
  '<div class="config-grid">',
1870
1797
  renderConfigCard('Model', [
@@ -1873,11 +1800,18 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
1873
1800
  '<p class="muted-note">Global default: ' + escHtml(globalModelLabel) + '</p>',
1874
1801
  ].join(''), 'saveModel', 'Save model', 'model-save-result'),
1875
1802
 
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'),
1803
+ renderConfigCard('Office visibility', [
1804
+ '<div class="config-row"><label>Visibility</label><select id="m-visibility">' +
1805
+ renderOptions([
1806
+ ['default', 'Follow the Slack conversation type (default)'],
1807
+ ['private', 'Private — treat this public channel as private'],
1808
+ ], data.officeVisibilityOverride === 'private' ? 'private' : 'default') + '</select></div>',
1809
+ '<p class="muted-note">Effective: <strong>' + escHtml(data.officeVisibility) + '</strong> · ' + escHtml(
1810
+ data.officeVisibilitySource === 'override' ? 'set here'
1811
+ : data.officeVisibilitySource === 'platform' ? 'from the Slack conversation type'
1812
+ : 'conversation type unknown; private until observed') + '</p>',
1813
+ '<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>',
1814
+ ].join(''), 'saveVisibility', 'Save visibility', 'mount-save-result'),
1881
1815
  renderConfigCard('Slack', [
1882
1816
  '<div class="config-row"><label>Reply mode</label><select id="m-slack-reply-mode">' + replyModeOpts + '</select></div>',
1883
1817
  '<p class="muted-note">Global default: ' + escHtml(globalReplyMode) + '</p>',
@@ -1906,10 +1840,10 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
1906
1840
  await saveConversationSetting(btn, result, 'slack', { replyMode }, 'Save Slack');
1907
1841
  }
1908
1842
 
1909
- async function saveDoorPolicy(btn) {
1910
- const doorPolicy = document.getElementById('m-door-policy').value;
1843
+ async function saveVisibility(btn) {
1844
+ const visibility = document.getElementById('m-visibility').value;
1911
1845
  const result = document.getElementById('mount-save-result');
1912
- await saveConversationSetting(btn, result, 'sandbox', { doorPolicy }, 'Save door policy', loadSettings);
1846
+ await saveConversationSetting(btn, result, 'visibility', { visibility }, 'Save visibility', loadSettings);
1913
1847
  }
1914
1848
 
1915
1849
  function saveConversationSetting(btn, result, setting, values, label, onSaved) {
@@ -2674,14 +2608,6 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
2674
2608
  function renderGlobalSettings(data) {
2675
2609
  const thinkingOpts = renderThinkingOptions(data.thinkingLevel);
2676
2610
  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
2611
  return [
2686
2612
  '<div class="config-grid">',
2687
2613
  renderConfigCard('Default model', [
@@ -2694,10 +2620,6 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
2694
2620
  '<div class="config-row"><label>Boost CPUs</label><input id="g-bcpus" placeholder="2" value="' + escAttr(data.sandboxBoostCpus || '') + '"></div>',
2695
2621
  '<div class="config-row"><label>Boost Mem</label><input id="g-bmem" placeholder="4g" value="' + escAttr(data.sandboxBoostMemory || '') + '"></div>',
2696
2622
  ].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
2623
  renderConfigCard('Slack', [
2702
2624
  '<div class="config-row"><label>Reply mode</label><select id="g-slack-reply-mode">' + replyModeOpts + '</select></div>',
2703
2625
  ].join(''), 'saveGlobalSlack', 'Save Slack', 'g-slack-result'),
@@ -2735,23 +2657,6 @@ const adminViewScript = ` let activeConversationKey = defaultConversationKey;
2735
2657
  await saveSetting(btn, result, 'settings/sandbox', { cpus, memory, boostCpus, boostMemory }, 'Save sandbox');
2736
2658
  }
2737
2659
 
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
2660
  async function saveGlobalSlack(btn) {
2756
2661
  const replyMode = document.getElementById('g-slack-reply-mode').value;
2757
2662
  const result = document.getElementById('g-slack-result');