code-workspace-zhuiyi 0.1.0-beta.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.
Files changed (98) hide show
  1. package/.env.example +3 -0
  2. package/LICENSE +21 -0
  3. package/README.md +168 -0
  4. package/README.zh-CN.md +168 -0
  5. package/artifacts/manifest.json +183 -0
  6. package/artifacts/templates/USER_GUIDE.template.md +1 -0
  7. package/artifacts/templates/agents/WORKSPACE_GUARD.md.template +73 -0
  8. package/artifacts/templates/agents/skills/code-workspace-resolve-branch/SKILL.md +88 -0
  9. package/artifacts/templates/agents/skills/code-workspace-resolve-branch/evals/evals.json +45 -0
  10. package/artifacts/templates/claude/commands/code-workspace/add-projects.md +23 -0
  11. package/artifacts/templates/codex/hooks.json +86 -0
  12. package/artifacts/templates/codex/skills/code-workspace-add-projects/SKILL.md +28 -0
  13. package/artifacts/templates/user-guide/en-US.md +97 -0
  14. package/artifacts/templates/user-guide/zh-CN.md +97 -0
  15. package/assets/i18n-icon.svg +1 -0
  16. package/assets/logo-vector.svg +30 -0
  17. package/assets/request_tip.mp3 +0 -0
  18. package/assets/session_finish.mp3 +0 -0
  19. package/bin/code-workspace.js +11 -0
  20. package/docs/extension-architecture.zh-CN.md +429 -0
  21. package/docs/extensions.md +64 -0
  22. package/docs/extensions.zh-CN.md +64 -0
  23. package/extensions/openspec-workspace/1.0.0/artifacts/claude/SKILL.md +16 -0
  24. package/extensions/openspec-workspace/1.0.0/artifacts/codex/SKILL.md +16 -0
  25. package/extensions/openspec-workspace/1.0.0/init.js +54 -0
  26. package/extensions/openspec-workspace/1.0.0/manifest.json +27 -0
  27. package/extensions/zhuiyi-jira-mcp/0.1.0/artifacts/claude/server.json +14 -0
  28. package/extensions/zhuiyi-jira-mcp/0.1.0/artifacts/codex/config.toml +11 -0
  29. package/extensions/zhuiyi-jira-mcp/0.1.0/init.js +53 -0
  30. package/extensions/zhuiyi-jira-mcp/0.1.0/lib/archive.js +196 -0
  31. package/extensions/zhuiyi-jira-mcp/0.1.0/manifest.json +38 -0
  32. package/extensions/zhuiyi-jira-mcp/0.1.0/release.json +15 -0
  33. package/package.json +58 -0
  34. package/schemas/extension-init-context-v1.json +39 -0
  35. package/schemas/extension-init-result-v1.json +42 -0
  36. package/schemas/extension-manifest-v1.json +55 -0
  37. package/schemas/extension-manifest-v2.json +84 -0
  38. package/schemas/extension-manifest-v3.json +84 -0
  39. package/spec/extension/v1/specification.en-US.md +171 -0
  40. package/spec/extension/v1/specification.zh-CN.md +170 -0
  41. package/src/cli/commands/completion.js +203 -0
  42. package/src/cli/commands/extension.js +193 -0
  43. package/src/cli/commands/help.js +36 -0
  44. package/src/cli/commands/init.js +200 -0
  45. package/src/cli/commands/monitor.js +62 -0
  46. package/src/cli/commands/permissions.js +33 -0
  47. package/src/cli/commands/project-branch-update.js +107 -0
  48. package/src/cli/commands/project-branch.js +433 -0
  49. package/src/cli/commands/project.js +259 -0
  50. package/src/cli/commands/update.js +146 -0
  51. package/src/cli/commands/workspace.js +24 -0
  52. package/src/cli/confirmation.js +22 -0
  53. package/src/cli/parser.js +108 -0
  54. package/src/cli/registry.js +108 -0
  55. package/src/cli/renderer.js +20 -0
  56. package/src/cli/result.js +118 -0
  57. package/src/cli.js +76 -0
  58. package/src/core/assets.js +83 -0
  59. package/src/core/config.js +378 -0
  60. package/src/core/diagnostics.js +20 -0
  61. package/src/core/directory-digest.js +34 -0
  62. package/src/core/doctor.js +115 -0
  63. package/src/core/errors.js +10 -0
  64. package/src/core/extension-artifacts-legacy.js +180 -0
  65. package/src/core/extension-artifacts.js +310 -0
  66. package/src/core/extensions.js +1216 -0
  67. package/src/core/fs.js +32 -0
  68. package/src/core/init-lock-holder.js +30 -0
  69. package/src/core/init-lock.js +159 -0
  70. package/src/core/init.js +160 -0
  71. package/src/core/initializer.js +233 -0
  72. package/src/core/language.js +102 -0
  73. package/src/core/managed-files.js +334 -0
  74. package/src/core/migration.js +68 -0
  75. package/src/core/permissions/claude.js +92 -0
  76. package/src/core/permissions/codex.js +126 -0
  77. package/src/core/permissions/common.js +44 -0
  78. package/src/core/permissions/index.js +163 -0
  79. package/src/core/project-branch-update.js +424 -0
  80. package/src/core/project-configuration.js +55 -0
  81. package/src/core/project.js +674 -0
  82. package/src/core/tools.js +34 -0
  83. package/src/core/transaction.js +132 -0
  84. package/src/core/validation.js +186 -0
  85. package/src/i18n/index.js +11 -0
  86. package/src/i18n/interpolate.js +7 -0
  87. package/src/i18n/locales/en-US.js +10 -0
  88. package/src/i18n/locales/zh-CN.js +11 -0
  89. package/src/i18n/registry.js +42 -0
  90. package/src/index.js +25 -0
  91. package/src/init/plan.js +12 -0
  92. package/src/init/ui.js +61 -0
  93. package/src/init/wizard.js +97 -0
  94. package/src/monitor/i18n/index.js +33 -0
  95. package/src/monitor/i18n/locales/en-US.js +85 -0
  96. package/src/monitor/i18n/locales/zh-CN.js +79 -0
  97. package/src/monitor/index.js +344 -0
  98. package/src/monitor/page.js +118 -0
@@ -0,0 +1,118 @@
1
+ const { DEFAULT_MONITOR_LANGUAGE, MONITOR_LOCALES, MONITOR_MESSAGES, getMonitorLocale } = require("./i18n");
2
+
3
+ const DEFAULT_MONITOR_MESSAGES = getMonitorLocale(DEFAULT_MONITOR_LANGUAGE).messages;
4
+
5
+ function escapeHtml(value) {
6
+ return String(value)
7
+ .replaceAll("&", "&")
8
+ .replaceAll("<", "&lt;")
9
+ .replaceAll(">", "&gt;")
10
+ .replaceAll('"', "&quot;");
11
+ }
12
+
13
+ const monitorLanguages = MONITOR_LOCALES.map((locale) => ({
14
+ value: locale.code,
15
+ label: locale.label,
16
+ }));
17
+
18
+ const PAGE_TEMPLATE = `<!doctype html>
19
+ <html lang="en-US">
20
+ <head>
21
+ <meta charset="utf-8">
22
+ <meta name="viewport" content="width=device-width,initial-scale=1">
23
+ <meta name="color-scheme" content="dark">
24
+ <title>Code Workspace Monitor</title>
25
+ <style>
26
+ :root{--ink:#080b0c;--panel:#101516;--panel2:#151b1c;--line:#293233;--muted:#819091;--paper:#e8efeb;--lime:#c7ff43;--amber:#ffbf47;--red:#ff6b5d;--cyan:#54d9d0;--brand-rgb:25,174,184;--brand-deep-rgb:7,82,140;--r:12px}
27
+ *{box-sizing:border-box}html,body{margin:0;min-height:100%;background:var(--ink);color:var(--paper)}body{font:14px/1.45 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;background-image:linear-gradient(rgba(255,255,255,.022) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.022) 1px,transparent 1px);background-size:32px 32px}
28
+ button{font:inherit}.shell{max-width:1680px;margin:auto;padding:24px}.topbar{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:4px 0 24px;border-bottom:1px solid var(--line)}
29
+ .brand{display:flex;gap:14px;align-items:center;min-width:0}.brand-copy{min-width:0}.brand-mark{position:relative;width:42px;height:42px;flex:none;filter:drop-shadow(0 0 11px rgba(var(--brand-rgb),.2))}.brand-mark:after{content:"";position:absolute;inset:11px;border-radius:50%;background:rgba(var(--brand-rgb),.13);animation:mark-pulse 2.8s ease-out infinite}.brand-mark img{position:relative;z-index:1;display:block;width:100%;height:100%;object-fit:contain}.eyebrow{color:var(--lime);font-size:11px;letter-spacing:.18em;text-transform:uppercase;white-space:nowrap}.brand h1{font:600 clamp(20px,2.2vw,30px)/1 Georgia,serif;margin:4px 0 0;letter-spacing:-.02em;white-space:nowrap}
30
+ .controls{display:flex;align-items:center;gap:10px;flex:none}.control-toggle{display:inline-flex;align-items:center;gap:8px;min-height:32px;border:1px solid var(--line);border-radius:999px;background:var(--panel);color:var(--muted);padding:7px 11px;cursor:pointer;text-transform:uppercase;font-size:10px;letter-spacing:.1em;transition:border-color .18s,color .18s,background-color .18s,box-shadow .18s}.control-toggle:hover,.control-toggle:focus-visible{border-color:var(--muted);color:var(--paper);outline:none}.language-toggle{border-color:rgba(var(--brand-rgb),.36);color:#71dce1;background:linear-gradient(110deg,rgba(var(--brand-rgb),.1),rgba(var(--brand-deep-rgb),.12))}.language-toggle:hover,.language-toggle:focus-visible{border-color:rgba(84,217,208,.7);color:#a7f4f1;box-shadow:0 0 18px rgba(var(--brand-rgb),.09)}.language-icon{display:block;width:14px;height:14px;flex:none;background:currentColor;mask:url('/assets/i18n-icon.svg') center/contain no-repeat;-webkit-mask:url('/assets/i18n-icon.svg') center/contain no-repeat}.sound-toggle:disabled{cursor:wait;opacity:.72}.sound-toggle[aria-pressed="true"]{border-color:#53652c;color:var(--lime);background:#151d12}.sound-icon{font-size:13px;line-height:1}.connection{display:flex;align-items:center;gap:9px;color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.08em}.dot{width:8px;height:8px;border-radius:50%;background:var(--amber);box-shadow:0 0 14px currentColor}.connection.live .dot{background:var(--lime);color:var(--lime)}
31
+ .metrics{display:grid;grid-template-columns:repeat(4,minmax(120px,1fr));gap:1px;background:var(--line);border:1px solid var(--line);margin:18px 0}.metric{background:var(--panel);padding:18px}.metric b{font:500 clamp(25px,3vw,40px)/1 Georgia,serif}.metric span{display:block;color:var(--muted);font-size:10px;letter-spacing:.14em;text-transform:uppercase;margin-top:8px}
32
+ .grid{display:grid;grid-template-columns:minmax(250px,320px) minmax(420px,1fr) minmax(310px,420px);gap:14px;min-height:calc(100vh - 230px)}.panel{background:rgba(16,21,22,.94);border:1px solid var(--line);border-radius:var(--r);min-width:0;overflow:hidden}.panel-head{display:flex;justify-content:space-between;align-items:center;height:48px;padding:0 15px;border-bottom:1px solid var(--line)}.panel-head h2{display:flex;align-items:center;gap:8px;font-size:11px;text-transform:uppercase;letter-spacing:.16em;margin:0}.panel-icon{width:15px;height:15px;flex:none;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}.workspace-icon{color:var(--lime)}.execution-icon{color:var(--cyan)}.signal-icon{color:var(--amber)}.count{color:var(--muted);font-size:11px}
33
+ .workspace-list{padding:8px}.workspace-entry{position:relative;margin:2px 0}.workspace{position:relative;width:100%;min-width:0;overflow:hidden;border:0;border-left:2px solid transparent;background:transparent;color:inherit;text-align:left;padding:13px 40px 13px 12px;cursor:pointer;transition:.18s}.workspace:hover{background:var(--panel2)}.workspace.has-approval{background:linear-gradient(100deg,rgba(255,191,71,.1),transparent 72%)}.workspace.has-complete:not(.has-approval){background:linear-gradient(100deg,rgba(199,255,67,.075),transparent 72%)}.workspace.active{background:#18201d;border-left-color:var(--lime)}.workspace.signal-arrived:after{content:"";position:absolute;inset:0;background:linear-gradient(105deg,transparent 25%,rgba(199,255,67,.2) 50%,transparent 75%);transform:translateX(-120%);animation:signal-sweep .85s ease-out}.workspace.has-approval .alert-badge.approval:before{content:"";width:5px;height:5px;border-radius:50%;background:var(--amber);box-shadow:0 0 0 0 rgba(255,191,71,.5);animation:approval-breathe 2.4s ease-out infinite}.workspace-menu{position:absolute;z-index:4;top:7px;right:7px}.workspace-menu-trigger{display:grid;place-items:center;width:27px;height:27px;border:0;border-radius:6px;background:transparent;color:var(--muted);cursor:pointer;font-size:18px;line-height:1;opacity:0;visibility:hidden;transform:translateX(4px);transition:.16s}.workspace-entry:hover .workspace-menu-trigger,.workspace-entry:focus-within .workspace-menu-trigger,.workspace-menu.open .workspace-menu-trigger{opacity:1;visibility:visible;transform:none}.workspace-menu-trigger:hover,.workspace-menu-trigger:focus-visible,.workspace-menu.open .workspace-menu-trigger{background:#202829;color:var(--paper);outline:1px solid #465354}.workspace-menu-popover{position:absolute;top:33px;right:0;min-width:130px;padding:5px;border:1px solid #3a4748;border-radius:8px;background:rgba(16,21,22,.98);box-shadow:0 12px 30px rgba(0,0,0,.46);backdrop-filter:blur(10px);opacity:0;visibility:hidden;pointer-events:none;transform:translateY(-4px);transition:.14s}.workspace-menu.flip .workspace-menu-popover{top:auto;bottom:33px;transform:translateY(4px)}.workspace-menu.open .workspace-menu-popover{opacity:1;visibility:visible;pointer-events:auto;transform:none}.workspace-menu-item{display:flex;align-items:center;gap:8px;width:100%;border:0;border-radius:5px;background:transparent;color:var(--muted);padding:8px 9px;text-align:left;cursor:pointer;font-size:11px;white-space:nowrap}.workspace-menu-item:hover,.workspace-menu-item:focus-visible{background:#291715;color:var(--red);outline:none}.workspace-menu-icon{font-size:14px}.workspace-top{display:flex;justify-content:space-between;align-items:center;gap:10px;min-height:17px}.workspace-name{font-weight:700;overflow:hidden;text-overflow:ellipsis}.workspace-meta{color:var(--muted);font-size:11px;margin-top:5px}.workspace-alerts{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}.alert-badge{display:inline-flex;align-items:center;gap:5px;border:1px solid currentColor;border-radius:999px;padding:2px 7px;font-size:9px;letter-spacing:.05em}.alert-badge.approval{color:var(--amber)}.alert-badge.complete{color:var(--lime)}.status{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:10px;letter-spacing:.08em;text-transform:uppercase;white-space:nowrap}.status:before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}.status.running,.status.active,.status.recent_complete{color:var(--lime)}.status.waiting_approval{color:var(--amber)}.status.inactive,.status.stopped,.status.ended,.status.session_ended{color:var(--muted)}
34
+ .stage{padding:20px}.workspace-title{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;margin-bottom:20px}.workspace-title h2{font:500 clamp(24px,3vw,42px)/1 Georgia,serif;margin:0}.uuid{color:var(--muted);font-size:10px;margin-top:9px;overflow-wrap:anywhere}.sessions{display:grid;gap:12px}.session{border:1px solid var(--line);border-radius:8px;background:var(--panel2);overflow:hidden}.session.inactive{border-color:#3a4445;background:#131819}.session-head{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 14px;border-bottom:1px solid var(--line)}.session-copy{min-width:0}.session-id{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-meta{color:var(--muted);font-size:10px;margin-top:4px}.session-meta.inactive{color:#a6b1b1}.session-actions{display:flex;align-items:center;gap:10px;flex:none}.session-delete{display:grid;place-items:center;width:27px;height:27px;border:0;border-radius:6px;background:transparent;color:var(--muted);cursor:pointer;font-size:16px;opacity:0;transition:.16s}.session:hover .session-delete,.session:focus-within .session-delete{opacity:1}.session-delete:hover,.session-delete:focus-visible{background:#291715;color:var(--red);outline:1px solid #60342f}.turns{padding:7px 14px 13px}.turn{display:grid;grid-template-columns:18px minmax(0,1fr) auto;gap:10px;align-items:start;padding:9px 0;position:relative}.turn:not(:last-child):after{content:"";position:absolute;left:7px;top:25px;bottom:-5px;width:1px;background:var(--line)}.turn-node{width:15px;height:15px;border:3px solid var(--panel2);outline:1px solid var(--line);border-radius:50%;background:var(--cyan);z-index:1}.turn-title{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.turn-detail{color:var(--muted);font-size:11px;margin-top:3px}.empty{display:grid;place-items:center;text-align:center;min-height:260px;padding:30px;color:var(--muted)}.empty strong{display:block;color:var(--paper);font:500 24px Georgia,serif;margin-bottom:8px}
35
+ .events{max-height:calc(100vh - 280px);overflow:auto}.event{padding:13px 15px;border-bottom:1px solid var(--line)}.event-top{display:flex;align-items:center;justify-content:space-between;gap:12px}.event-type{color:var(--cyan);font-size:11px;font-weight:700}.event time{color:var(--muted);font-size:10px}.event-path{margin-top:7px;font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.event-path span{color:var(--muted)}
36
+ @keyframes signal-sweep{to{transform:translateX(120%)}}@keyframes approval-breathe{60%{box-shadow:0 0 0 6px rgba(255,191,71,0)}to{box-shadow:0 0 0 0 rgba(255,191,71,0)}}@keyframes mark-pulse{0%,45%{transform:scale(.55);opacity:.45}78%,100%{transform:scale(1.65);opacity:0}}
37
+ @media(max-width:1100px){.grid{grid-template-columns:260px 1fr}.activity{grid-column:1/-1}.events{max-height:420px}}@media(max-width:720px){.shell{padding:14px}.topbar{gap:14px}.brand h1{font-size:18px}.control-label{display:none}.control-toggle{width:32px;height:32px;justify-content:center;padding:0}.controls{gap:8px}.connection span{display:none}.metrics{grid-template-columns:1fr 1fr}.grid{display:block}.panel{margin-bottom:12px}.workspace-panel{max-height:300px}.workspace-title{display:block}.workspace-title .status{margin-top:12px}}@media(max-width:600px){.metrics{display:none}.grid{min-height:calc(100vh - 100px)}}@media(max-width:400px){.shell{padding:10px}.topbar{gap:10px;padding:2px 0 14px}.brand-copy{display:none}.brand-mark{width:38px;height:38px}.controls{gap:6px}.connection{gap:0}.dot{width:7px;height:7px}.panel-head{padding:0 12px}.stage{padding:14px}}@media(hover:none),(pointer:coarse){.workspace-menu-trigger{opacity:.72;visibility:visible;transform:none}.session-delete{opacity:.8}}
38
+ @media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
39
+ </style>
40
+ </head>
41
+ <body>
42
+ <main class="shell">
43
+ <header class="topbar"><div class="brand"><div class="brand-mark" aria-hidden="true"><img src="/assets/logo-vector.svg" alt=""></div><div class="brand-copy"><div id="eyebrow" class="eyebrow">${escapeHtml(DEFAULT_MONITOR_MESSAGES.eyebrow)}</div><h1 id="page-heading">${escapeHtml(DEFAULT_MONITOR_MESSAGES.title)}</h1></div></div><div class="controls"><button id="language-toggle" class="control-toggle language-toggle" type="button"><span class="language-icon" aria-hidden="true"></span><span class="control-label language-label">${escapeHtml(getMonitorLocale(DEFAULT_MONITOR_LANGUAGE).label)}</span></button><button id="sound-toggle" class="control-toggle sound-toggle" type="button" aria-pressed="true"><span class="sound-icon" aria-hidden="true">&#9835;</span><span class="control-label sound-label">${escapeHtml(DEFAULT_MONITOR_MESSAGES.soundOn)}</span></button><div id="connection" class="connection"><i class="dot"></i><span>${escapeHtml(DEFAULT_MONITOR_MESSAGES.connecting)}</span></div></div></header>
44
+ <section id="metrics" class="metrics" aria-label="${escapeHtml(DEFAULT_MONITOR_MESSAGES.summary)}"><div class="metric"><b id="m-workspaces">0</b><span id="metric-workspaces">${escapeHtml(DEFAULT_MONITOR_MESSAGES.workspaces)}</span></div><div class="metric"><b id="m-sessions">0</b><span id="metric-sessions">${escapeHtml(DEFAULT_MONITOR_MESSAGES.sessions)}</span></div><div class="metric"><b id="m-turns">0</b><span id="metric-turns">${escapeHtml(DEFAULT_MONITOR_MESSAGES.turns)}</span></div><div class="metric"><b id="m-active">0</b><span id="metric-active">${escapeHtml(DEFAULT_MONITOR_MESSAGES.active)}</span></div></section>
45
+ <section class="grid">
46
+ <aside class="panel workspace-panel"><div class="panel-head"><h2><svg class="panel-icon workspace-icon" aria-hidden="true" viewBox="0 0 16 16"><rect x="1.5" y="2" width="5" height="5" rx="1"/><rect x="9.5" y="2" width="5" height="5" rx="1"/><rect x="1.5" y="9" width="5" height="5" rx="1"/><rect x="9.5" y="9" width="5" height="5" rx="1"/></svg><span id="workspace-title">${escapeHtml(DEFAULT_MONITOR_MESSAGES.workspaces)}</span></h2><span id="workspace-count" class="count">0</span></div><div id="workspaces" class="workspace-list"></div></aside>
47
+ <section class="panel"><div class="panel-head"><h2><svg class="panel-icon execution-icon" aria-hidden="true" viewBox="0 0 16 16"><path d="M3 2.5h10v11H3z"/><path d="m5.5 6 2 2-2 2M9 10h2"/></svg><span id="execution-title">${escapeHtml(DEFAULT_MONITOR_MESSAGES.execution)}</span></h2><span id="updated" class="count">${escapeHtml(DEFAULT_MONITOR_MESSAGES.waitingData)}</span></div><div id="stage" class="stage"></div></section>
48
+ <aside class="panel activity"><div class="panel-head"><h2><svg class="panel-icon signal-icon" aria-hidden="true" viewBox="0 0 16 16"><circle cx="8" cy="8" r="1.2"/><path d="M5.2 5.2a4 4 0 0 0 0 5.6M10.8 5.2a4 4 0 0 1 0 5.6M3.1 3.1a7 7 0 0 0 0 9.8M12.9 3.1a7 7 0 0 1 0 9.8"/></svg><span id="signals-title">${escapeHtml(DEFAULT_MONITOR_MESSAGES.signals)}</span></h2><span id="event-count" class="count">0</span></div><div id="events" class="events"></div></aside>
49
+ </section>
50
+ </main>
51
+ <script>
52
+ const SOUND_KEY='code-workspace-monitor-sound';
53
+ const LANGUAGE_KEY='code-workspace-monitor-language';
54
+ const ALERT_KEY='code-workspace-monitor-workspace-alerts';
55
+ const LEGACY_INBOX_KEY='code-workspace-monitor-signal-inbox';
56
+ const SOUND_FILES={'approval.requested':'/assets/request_tip.mp3','turn.stopped':'/assets/session_finish.mp3'};
57
+ const MESSAGES=__MONITOR_MESSAGES__;
58
+ const LANGUAGES=__MONITOR_LANGUAGES__;
59
+ const DEFAULT_LANGUAGE=__DEFAULT_MONITOR_LANGUAGE__;
60
+ const savedLanguage=localStorage.getItem(LANGUAGE_KEY);
61
+ const state={data:{workspaces:[],events:[]},selected:null,language:MESSAGES[savedLanguage]?savedLanguage:DEFAULT_LANGUAGE,soundEnabled:localStorage.getItem(SOUND_KEY)!=='off',soundReady:false,soundLoading:false,audio:null,sounds:{},heard:new Set(),lastCompletionAt:0,alerts:new Map(),arrivals:new Set()};
62
+ const $=id=>document.getElementById(id); const el=(tag,cls,text)=>{const node=document.createElement(tag);if(cls)node.className=cls;if(text!==undefined)node.textContent=text;return node};
63
+ const message=(template,values={})=>String(template).replace(/\{([^{}]+)\}/g,(match,key)=>Object.prototype.hasOwnProperty.call(values,key)?values[key]:match);
64
+ const messages=()=>MESSAGES[state.language];
65
+ const short=id=>id&&id.length>16?id.slice(0,8)+'…'+id.slice(-5):id||'—';
66
+ const ago=value=>{const m=messages();if(!value)return m.never;const seconds=Math.max(0,Math.floor((Date.now()-new Date(value))/1000));if(seconds<5)return m.justNow;if(seconds<60)return message(m.seconds,{count:seconds});if(seconds<3600)return message(m.minutes,{count:Math.floor(seconds/60)});return message(m.hours,{count:Math.floor(seconds/3600)})};
67
+ function status(value){const key=String(value||'IDLE');return el('span','status '+key.toLowerCase(),messages().status[key]||key)}
68
+ function applyLanguage(){const m=messages();document.documentElement.lang=state.language;document.title=m.title;$('page-heading').textContent=m.title;$('eyebrow').textContent=m.eyebrow;$('metrics').setAttribute('aria-label',m.summary);$('metric-workspaces').textContent=m.workspaces;$('metric-sessions').textContent=m.sessions;$('metric-turns').textContent=m.turns;$('metric-active').textContent=m.active;$('workspace-title').textContent=m.workspaces;$('execution-title').textContent=m.execution;$('signals-title').textContent=m.signals;renderLanguage();renderSound();render()}
69
+ function workspaceStatus(workspace,alert){const sessions=Object.values(workspace.sessions||{}),turns=[];for(const session of sessions)if(session.status==='ACTIVE')turns.push(...Object.values(session.turns||{}));if(turns.some(turn=>turn.status==='WAITING_APPROVAL'))return 'WAITING_APPROVAL';if(turns.some(turn=>turn.status==='RUNNING'))return 'RUNNING';if(alert?.complete)return 'RECENT_COMPLETE';if(sessions.some(session=>session.status==='ACTIVE'))return 'ACTIVE';if(sessions.length&&sessions.every(session=>session.status==='ENDED'))return 'ENDED';if(sessions.length)return 'INACTIVE';return null}
70
+ function closeWorkspaceMenus(returnFocus=false){for(const menu of document.querySelectorAll('.workspace-menu.open')){menu.classList.remove('open','flip');const trigger=menu.querySelector('.workspace-menu-trigger');trigger.setAttribute('aria-expanded','false');menu.querySelector('.workspace-menu-popover').setAttribute('aria-hidden','true');if(returnFocus)trigger.focus()}}
71
+ function render(){const ws=state.data.workspaces||[],events=state.data.events||[];if(!state.selected||!ws.some(x=>x.uuid===state.selected))state.selected=ws[0]?.uuid||null;
72
+ const m=messages();
73
+ const fallback={workspaces:ws.length,sessions:0,activeSessions:0,turns:0};for(const w of ws)for(const s of Object.values(w.sessions||{})){fallback.sessions++;if(s.status==='ACTIVE')fallback.activeSessions++;fallback.turns+=Object.keys(s.turns||{}).length}const summary=state.data.summary||fallback;
74
+ const pending=[...state.alerts.values()].filter(alert=>approvalCount(alert)||alert.complete).length;$('m-workspaces').textContent=summary.workspaces;$('m-sessions').textContent=summary.sessions;$('m-turns').textContent=summary.turns;$('m-active').textContent=summary.activeSessions;$('workspace-count').textContent=message(m.nodes,{count:ws.length})+(pending?message(m.pending,{count:pending}):'');$('event-count').textContent=message(m.events,{count:events.length});$('updated').textContent=state.data.serverTime?message(m.updated,{value:ago(state.data.serverTime)}):m.waitingData;
75
+ const priority=alert=>approvalCount(alert)?2:alert?.complete?1:0;const ordered=ws.slice().sort((a,b)=>priority(state.alerts.get(b.uuid))-priority(state.alerts.get(a.uuid))||(b.updatedAt||'').localeCompare(a.updatedAt||''));const list=$('workspaces');list.replaceChildren();for(const w of ordered){const entry=el('div','workspace-entry');const alert=state.alerts.get(w.uuid),approvals=approvalCount(alert);const button=el('button','workspace'+(w.uuid===state.selected?' active':'')+(approvals?' has-approval':'')+(alert?.complete?' has-complete':''));button.type='button';button.onclick=()=>{acknowledgeWorkspace(w.uuid);state.selected=w.uuid;render()};const top=el('div','workspace-top');top.append(el('span','workspace-name',w.name));const currentStatus=workspaceStatus(w,alert);if(currentStatus)top.append(status(currentStatus));const ss=Object.values(w.sessions||{}),activeSessions=w.activeSessionCount??ss.filter(session=>session.status==='ACTIVE').length;button.append(top,el('div','workspace-meta',message(m.workspaceMeta,{active:activeSessions,sessions:w.sessionCount??ss.length,signals:w.eventCount,updated:ago(w.updatedAt)})));if(approvals||alert?.complete){const alerts=el('div','workspace-alerts');if(approvals)alerts.append(el('span','alert-badge approval',message(m.approval,{count:approvals})));if(alert.complete)alerts.append(el('span','alert-badge complete',message(m.complete,{count:alert.complete})));button.append(alerts)}if(state.arrivals.delete(w.uuid)){button.classList.add('signal-arrived');setTimeout(()=>button.classList.remove('signal-arrived'),900)}const menu=el('div','workspace-menu');const trigger=el('button','workspace-menu-trigger','⋮');trigger.type='button';trigger.title=w.name+' '+m.actions;trigger.setAttribute('aria-label',w.name+' '+m.actions);trigger.setAttribute('aria-haspopup','menu');trigger.setAttribute('aria-expanded','false');const popover=el('div','workspace-menu-popover');popover.setAttribute('role','menu');popover.setAttribute('aria-hidden','true');const remove=el('button','workspace-menu-item');remove.type='button';remove.setAttribute('role','menuitem');remove.append(el('span','workspace-menu-icon','×'),document.createTextNode(m.removeWorkspace));remove.onclick=async event=>{event.stopPropagation();closeWorkspaceMenus();await removeWorkspace(w)};trigger.onclick=event=>{event.stopPropagation();const opening=!menu.classList.contains('open');closeWorkspaceMenus();if(opening){menu.classList.add('open');trigger.setAttribute('aria-expanded','true');popover.setAttribute('aria-hidden','false');const panel=$('workspaces').getBoundingClientRect(),rect=menu.getBoundingClientRect();if(panel.bottom-rect.bottom<54)menu.classList.add('flip');remove.focus()}};popover.append(remove);menu.append(trigger,popover);entry.append(button,menu);list.append(entry)}if(!ws.length)list.append(el('div','empty',m.emptyWorkspaces));
76
+ renderStage(ws.find(w=>w.uuid===state.selected));renderEvents(events);
77
+ }
78
+ function renderStage(w){const m=messages(),stage=$('stage');stage.replaceChildren();if(!w){const box=el('div','empty');const copy=el('div');copy.append(el('strong','',m.waitingAgent),document.createTextNode(m.waitingAgentDetail));box.append(copy);stage.append(box);return}const title=el('div','workspace-title');const heading=el('div');heading.append(el('h2','',w.name),el('div','uuid',w.uuid));const rank={ACTIVE:0,INACTIVE:1,ENDED:2},sessions=Object.values(w.sessions||{}).sort((a,b)=>(rank[a.status]??9)-(rank[b.status]??9)||(b.lastSignalAt||b.updatedAt||'').localeCompare(a.lastSignalAt||a.updatedAt||''));title.append(heading,status(workspaceStatus(w,null)||'IDLE'));stage.append(title);const body=el('div','sessions');if(!sessions.length)body.append(el('div','empty',m.noSessions));for(const s of sessions){const card=el('article','session'+(s.status==='INACTIVE'?' inactive':''));const head=el('div','session-head'),copy=el('div','session-copy');copy.append(el('div','session-id',m.session+' / '+short(s.id)));const detail=el('div','session-meta'+(s.status==='INACTIVE'?' inactive':''),message(m.lastSignal,{value:ago(s.lastSignalAt||s.updatedAt)}));if(s.status==='INACTIVE')detail.append(document.createTextNode(' · '+m.inactiveReason));copy.append(detail);const actions=el('div','session-actions'),remove=el('button','session-delete','×');remove.type='button';remove.title=m.removeSession;remove.setAttribute('aria-label',m.removeSession+' '+short(s.id));remove.onclick=()=>removeSession(w,s);actions.append(status(s.status),remove);head.append(copy,actions);card.append(head);const turns=el('div','turns');const values=Object.values(s.turns||{}).sort((a,b)=>(b.updatedAt||'').localeCompare(a.updatedAt||''));if(!values.length)turns.append(el('div','turn-detail',m.noTurns));for(const t of values){const row=el('div','turn');row.append(el('i','turn-node'));const turnCopy=el('div');turnCopy.append(el('div','turn-title',m.turn+' / '+short(t.id)),el('div','turn-detail',(t.tool?.name?m.tool+' '+t.tool.name+' · ':'')+message(m.signalsCount,{count:t.eventCount})+' · '+ago(t.updatedAt)));row.append(turnCopy,status(t.status));turns.append(row)}card.append(turns);body.append(card)}stage.append(body)}
79
+ function renderEvents(events){const m=messages(),target=$('events');target.replaceChildren();for(const event of events.slice(0,100)){const row=el('article','event');const top=el('div','event-top');top.append(el('span','event-type',m.event[event.eventType]||event.eventType),el('time','',new Date(event.timestamp).toLocaleTimeString(state.language)));const path=el('div','event-path');path.append(document.createTextNode(event.workspace.name+' '),el('span','', '/ '+short(event.session.id)+(event.turn?.id?' / '+short(event.turn.id):'')));row.append(top,path);target.append(row)}if(!events.length)target.append(el('div','empty',m.noEvents))}
80
+ function renderLanguage(){const current=LANGUAGES.find(language=>language.value===state.language)||LANGUAGES[0],button=$('language-toggle'),description=messages().language+': '+current.label;button.title=description;button.setAttribute('aria-label',description);button.querySelector('.language-label').textContent=current.label}
81
+ function renderSound(){const m=messages(),button=$('sound-toggle');button.disabled=state.soundLoading;button.setAttribute('aria-busy',String(state.soundLoading));button.setAttribute('aria-pressed',String(state.soundEnabled));button.title=state.soundLoading?m.soundLoadingTitle:state.soundEnabled&&!state.soundReady?m.soundFirstUse:state.soundEnabled?m.soundDisable:m.soundEnable;button.querySelector('.sound-label').textContent=state.soundLoading?m.soundLoading:state.soundEnabled?m.soundOn:m.soundOff}
82
+ function toggleLanguage(){const current=LANGUAGES.findIndex(language=>language.value===state.language),next=current<0?0:(current+1)%LANGUAGES.length;state.language=LANGUAGES[next].value;localStorage.setItem(LANGUAGE_KEY,state.language);applyLanguage()}
83
+ async function enableSound(){const Audio=window.AudioContext||window.webkitAudioContext;if(!Audio)return false;state.audio=state.audio||new Audio();try{await state.audio.resume();if(!Object.keys(state.sounds).length){const entries=await Promise.all(Object.entries(SOUND_FILES).map(async([type,url])=>{const response=await fetch(url);if(!response.ok)throw new Error(messages().soundUnavailable);return [type,await state.audio.decodeAudioData(await response.arrayBuffer())]}));state.sounds=Object.fromEntries(entries)}state.soundReady=state.audio.state==='running'}catch(error){state.soundReady=false;console.warn(messages().soundWarning,error.message)}return state.soundReady}
84
+ function playSound(type){const buffer=state.sounds[type];if(!state.soundEnabled||!state.soundReady||!state.audio||!buffer)return;const source=state.audio.createBufferSource();source.buffer=buffer;source.connect(state.audio.destination);source.start()}
85
+ function approvalCount(alert){return Array.isArray(alert?.approval)?alert.approval.length:Math.max(0,Number(alert?.approval)||0)}
86
+ function persistAlerts(){try{localStorage.setItem(ALERT_KEY,JSON.stringify([...state.alerts.entries()]))}catch{}}
87
+ function ensureAlert(uuid){const current=state.alerts.get(uuid);if(current){if(!Array.isArray(current.approval))current.approval=Array.from({length:approvalCount(current)},()=>({legacy:true}));return current}const alert={approval:[],complete:0};state.alerts.set(uuid,alert);return alert}
88
+ function addLegacyAlert(uuid,type,count=1){if(!uuid)return;const alert=ensureAlert(uuid),amount=Math.max(1,Number(count)||1);if(type==='approval')for(let index=0;index<amount;index++)alert.approval.push({legacy:true});if(type==='complete')alert.complete+=amount}
89
+ function acknowledgeWorkspace(uuid){const alert=state.alerts.get(uuid);if(!alert)return;alert.complete=0;if(!approvalCount(alert))state.alerts.delete(uuid);persistAlerts()}
90
+ function clearWorkspaceAlerts(uuid){if(state.alerts.delete(uuid))persistAlerts()}
91
+ function clearSessionAlerts(uuid,sessionId){const alert=state.alerts.get(uuid);if(!alert||!Array.isArray(alert.approval))return;const before=alert.approval.length;alert.approval=alert.approval.filter(item=>item.legacy||item.sessionId!==sessionId);if(!approvalCount(alert)&&!alert.complete)state.alerts.delete(uuid);if(alert.approval?.length!==before)persistAlerts()}
92
+ function reconcileSessionAlerts(){let changed=false;const workspaces=new Map((state.data.workspaces||[]).map(workspace=>[workspace.uuid,workspace]));for(const [uuid,alert] of state.alerts){if(!Array.isArray(alert.approval))continue;const sessions=workspaces.get(uuid)?.sessions||{},before=alert.approval.length;alert.approval=alert.approval.filter(item=>item.legacy||(item.sessionId&&sessions[item.sessionId]?.status==='ACTIVE'));if(alert.approval.length!==before)changed=true;if(!approvalCount(alert)&&!alert.complete){state.alerts.delete(uuid);changed=true}}if(changed)persistAlerts()}
93
+ function restoreAlerts(){try{const saved=JSON.parse(localStorage.getItem(ALERT_KEY)||'[]');if(Array.isArray(saved))for(const [uuid,value] of saved)if(uuid&&value){const approval=Array.isArray(value.approval)?value.approval.filter(Boolean):Array.from({length:Math.max(0,Number(value.approval)||0)},()=>({legacy:true})),complete=Math.max(0,Number(value.complete)||0);if(approval.length||complete)state.alerts.set(uuid,{approval,complete})}const legacy=JSON.parse(localStorage.getItem(LEGACY_INBOX_KEY)||'[]');if(Array.isArray(legacy))for(const item of legacy){const type=item?.eventType==='approval.requested'?'approval':item?.eventType==='turn.stopped'?'complete':null;if(type)addLegacyAlert(item?.workspace?.uuid,type,item?.count)}if(Array.isArray(legacy)&&legacy.length)persistAlerts();localStorage.removeItem(LEGACY_INBOX_KEY)}catch{localStorage.removeItem(ALERT_KEY);localStorage.removeItem(LEGACY_INBOX_KEY)}}
94
+ function recordApproval(event){const uuid=event.workspace?.uuid;if(!uuid)return;ensureAlert(uuid).approval.push({sessionId:event.session?.id||null,turnId:event.turn?.id||null,toolName:event.tool?.name||null,at:event.timestamp||new Date().toISOString()});state.arrivals.add(uuid);persistAlerts()}
95
+ function recordCompletion(event){const uuid=event.workspace?.uuid;if(!uuid)return;ensureAlert(uuid).complete+=1;state.arrivals.add(uuid);persistAlerts()}
96
+ function reconcileApprovals(event){const uuid=event.workspace?.uuid,alert=state.alerts.get(uuid);if(!alert||!approvalCount(alert))return;const approvals=ensureAlert(uuid).approval;let changed=false;if(event.eventType==='tool.completed'){let index=approvals.findIndex(item=>item.turnId===event.turn?.id&&item.toolName===event.tool?.name);if(index<0)index=approvals.findIndex(item=>item.turnId===event.turn?.id);if(index<0)index=approvals.findIndex(item=>item.legacy);if(index>=0){approvals.splice(index,1);changed=true}}else if(event.eventType==='turn.stopped'){const before=approvals.length;alert.approval=approvals.filter(item=>item.turnId&&item.turnId!==event.turn?.id);changed=alert.approval.length!==before}else if(event.eventType==='session.ended'){const before=approvals.length;alert.approval=approvals.filter(item=>item.sessionId&&item.sessionId!==event.session?.id);changed=alert.approval.length!==before}if(changed){if(!approvalCount(alert)&&!alert.complete)state.alerts.delete(uuid);persistAlerts()}}
97
+ function notify(event){if(!event||!event.eventId||state.heard.has(event.eventId))return;state.heard.add(event.eventId);if(state.heard.size>500)state.heard.delete(state.heard.values().next().value);if(event.eventType==='approval.requested'){recordApproval(event);playSound(event.eventType)}if(['tool.completed','turn.stopped','session.ended'].includes(event.eventType))reconcileApprovals(event);if(event.eventType==='turn.stopped'){recordCompletion(event);const now=Date.now();if(now-state.lastCompletionAt>=500){state.lastCompletionAt=now;playSound(event.eventType)}}}
98
+ async function toggleSound(){if(state.soundLoading)return;if(state.soundEnabled&&state.soundReady){state.soundEnabled=false;state.soundReady=false;if(state.audio?.state==='running')await state.audio.suspend()}else{state.soundEnabled=true;state.soundLoading=true;renderSound();if(!await enableSound())state.soundEnabled=false;state.soundLoading=false}localStorage.setItem(SOUND_KEY,state.soundEnabled?'on':'off');renderSound()}
99
+ async function activatePreferredSound(event){if(event?.target?.closest?.('#sound-toggle')||!state.soundEnabled||state.soundReady||state.soundLoading)return;state.soundLoading=true;renderSound();const ready=await enableSound();state.soundLoading=false;renderSound();if(ready){document.removeEventListener('pointerdown',activatePreferredSound,true);document.removeEventListener('keydown',activatePreferredSound,true)}}
100
+ async function removeWorkspace(workspace){if(!window.confirm(message(messages().removeConfirm,{name:workspace.name})))return;const response=await fetch('/api/v1/workspaces/'+encodeURIComponent(workspace.uuid),{method:'DELETE'});if(!response.ok)return;clearWorkspaceAlerts(workspace.uuid);await refresh()}
101
+ async function removeSession(workspace,session){const m=messages(),template=session.status==='ACTIVE'?m.removeActiveSessionConfirm:m.removeSessionConfirm;if(!window.confirm(message(template,{id:short(session.id)})))return;const response=await fetch('/api/v1/workspaces/'+encodeURIComponent(workspace.uuid)+'/sessions/'+encodeURIComponent(session.id),{method:'DELETE'});if(!response.ok)return;clearSessionAlerts(workspace.uuid,session.id);await refresh()}
102
+ async function refresh(){try{const response=await fetch('/api/v1/snapshot',{cache:'no-store'});if(!response.ok)throw new Error();state.data=await response.json();reconcileSessionAlerts();render();setConnection(true)}catch{setConnection(false)}}
103
+ function setConnection(live){const node=$('connection');node.classList.toggle('live',live);node.querySelector('span').textContent=live?messages().live:messages().reconnecting}
104
+ function handleUpdate(message){try{notify(JSON.parse(message.data).event)}catch{}refresh()}
105
+ function connect(){const stream=new EventSource('/api/v1/stream');stream.onopen=()=>setConnection(true);stream.addEventListener('update',handleUpdate);stream.onerror=()=>setConnection(false)}
106
+ $('language-toggle').addEventListener('click',toggleLanguage);$('sound-toggle').addEventListener('click',toggleSound);document.addEventListener('pointerdown',activatePreferredSound,true);document.addEventListener('keydown',activatePreferredSound,true);document.addEventListener('click',()=>closeWorkspaceMenus());document.addEventListener('keydown',event=>{if(event.key==='Escape')closeWorkspaceMenus(true)});restoreAlerts();applyLanguage();refresh();connect();setInterval(refresh,10000);
107
+ </script>
108
+ </body>
109
+ </html>`;
110
+
111
+ function renderMonitorPage() {
112
+ return PAGE_TEMPLATE
113
+ .replace("__MONITOR_MESSAGES__", JSON.stringify(MONITOR_MESSAGES).replaceAll("<", "\\u003c"))
114
+ .replace("__MONITOR_LANGUAGES__", JSON.stringify(monitorLanguages).replaceAll("<", "\\u003c"))
115
+ .replace("__DEFAULT_MONITOR_LANGUAGE__", JSON.stringify(DEFAULT_MONITOR_LANGUAGE));
116
+ }
117
+
118
+ module.exports = { renderMonitorPage };