instar 0.28.77 → 0.28.79
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/dashboard/index.html +354 -11
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +6 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/playbook.d.ts.map +1 -1
- package/dist/commands/playbook.js +2 -1
- package/dist/commands/playbook.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +136 -9
- package/dist/commands/server.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +5 -3
- package/dist/commands/setup.js.map +1 -1
- package/dist/core/Config.d.ts.map +1 -1
- package/dist/core/Config.js +2 -1
- package/dist/core/Config.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +4 -5
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts +38 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +157 -23
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/UpdateChecker.d.ts.map +1 -1
- package/dist/core/UpdateChecker.js +3 -1
- package/dist/core/UpdateChecker.js.map +1 -1
- package/dist/core/UpgradeGuideProcessor.d.ts.map +1 -1
- package/dist/core/UpgradeGuideProcessor.js +3 -1
- package/dist/core/UpgradeGuideProcessor.js.map +1 -1
- package/dist/core/types.d.ts +18 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
- package/dist/lifeline/ServerSupervisor.js +3 -1
- package/dist/lifeline/ServerSupervisor.js.map +1 -1
- package/dist/memory/SemanticMemory.d.ts +9 -0
- package/dist/memory/SemanticMemory.d.ts.map +1 -1
- package/dist/memory/SemanticMemory.js +131 -0
- package/dist/memory/SemanticMemory.js.map +1 -1
- package/dist/monitoring/TokenLedger.d.ts +39 -0
- package/dist/monitoring/TokenLedger.d.ts.map +1 -1
- package/dist/monitoring/TokenLedger.js +110 -13
- package/dist/monitoring/TokenLedger.js.map +1 -1
- package/dist/monitoring/TokenLedgerPoller.d.ts.map +1 -1
- package/dist/monitoring/TokenLedgerPoller.js +8 -8
- package/dist/monitoring/TokenLedgerPoller.js.map +1 -1
- package/dist/scheduler/JobRunHistory.d.ts +6 -0
- package/dist/scheduler/JobRunHistory.d.ts.map +1 -1
- package/dist/scheduler/JobRunHistory.js +11 -0
- package/dist/scheduler/JobRunHistory.js.map +1 -1
- package/dist/scheduler/JobScheduler.d.ts +23 -0
- package/dist/scheduler/JobScheduler.d.ts.map +1 -1
- package/dist/scheduler/JobScheduler.js +84 -0
- package/dist/scheduler/JobScheduler.js.map +1 -1
- package/dist/server/AgentServer.d.ts +4 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +14 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +8 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +154 -0
- package/dist/server/routes.js.map +1 -1
- package/dist/threadline/BackfillCore.d.ts +70 -0
- package/dist/threadline/BackfillCore.d.ts.map +1 -0
- package/dist/threadline/BackfillCore.js +117 -0
- package/dist/threadline/BackfillCore.js.map +1 -0
- package/dist/threadline/ListenerSessionManager.d.ts +35 -0
- package/dist/threadline/ListenerSessionManager.d.ts.map +1 -1
- package/dist/threadline/ListenerSessionManager.js +41 -0
- package/dist/threadline/ListenerSessionManager.js.map +1 -1
- package/dist/threadline/TelegramBridge.d.ts +140 -0
- package/dist/threadline/TelegramBridge.d.ts.map +1 -0
- package/dist/threadline/TelegramBridge.js +224 -0
- package/dist/threadline/TelegramBridge.js.map +1 -0
- package/dist/threadline/ThreadlineBootstrap.d.ts.map +1 -1
- package/dist/threadline/ThreadlineBootstrap.js +3 -2
- package/dist/threadline/ThreadlineBootstrap.js.map +1 -1
- package/dist/threadline/ThreadlineMCPServer.d.ts.map +1 -1
- package/dist/threadline/ThreadlineMCPServer.js +5 -0
- package/dist/threadline/ThreadlineMCPServer.js.map +1 -1
- package/dist/threadline/ThreadlineObservability.d.ts +95 -0
- package/dist/threadline/ThreadlineObservability.d.ts.map +1 -0
- package/dist/threadline/ThreadlineObservability.js +310 -0
- package/dist/threadline/ThreadlineObservability.js.map +1 -0
- package/dist/threadline/relay/ConnectionManager.d.ts.map +1 -1
- package/dist/threadline/relay/ConnectionManager.js +34 -7
- package/dist/threadline/relay/ConnectionManager.js.map +1 -1
- package/package.json +1 -1
- package/scripts/pre-push-gate.js +26 -0
- package/scripts/threadline-bridge-backfill.mjs +379 -0
- package/src/data/builtin-manifest.json +65 -65
- package/upgrades/0.28.78.md +90 -0
- package/upgrades/0.28.79.md +67 -0
- package/upgrades/side-effects/0.28.79.md +310 -0
- package/upgrades/side-effects/assembler-context-endpoint.md +67 -0
- package/upgrades/side-effects/post-update-migrator-path-fix.md +52 -0
- package/upgrades/side-effects/semantic-memory-corruption-recovery.md +98 -0
- package/upgrades/side-effects/threadline-bridge-backfill.md +203 -0
- package/upgrades/side-effects/threadline-observability-tab.md +206 -0
- package/upgrades/side-effects/threadline-tg-bridge-module.md +196 -0
- package/upgrades/side-effects/token-ledger-bounded-scan.md +230 -0
- package/upgrades/side-effects/url-pathname-path-encoding-fix.md +45 -0
package/dashboard/index.html
CHANGED
|
@@ -52,6 +52,12 @@
|
|
|
52
52
|
padding: 12px 20px;
|
|
53
53
|
border-bottom: 1px solid var(--border);
|
|
54
54
|
background: var(--bg-panel);
|
|
55
|
+
position: relative;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Hamburger toggle — visible only on mobile, sits in the header row */
|
|
59
|
+
.nav-toggle {
|
|
60
|
+
display: none;
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
.header-left {
|
|
@@ -2206,9 +2212,26 @@
|
|
|
2206
2212
|
font-size: 14px;
|
|
2207
2213
|
}
|
|
2208
2214
|
|
|
2215
|
+
/* Compact terminal action row — only essential keys inline,
|
|
2216
|
+
rest collapse into an overflow scroll strip */
|
|
2209
2217
|
.terminal-actions {
|
|
2210
2218
|
gap: 4px;
|
|
2211
|
-
flex-wrap:
|
|
2219
|
+
flex-wrap: nowrap;
|
|
2220
|
+
overflow-x: auto;
|
|
2221
|
+
-webkit-overflow-scrolling: touch;
|
|
2222
|
+
scrollbar-width: none;
|
|
2223
|
+
}
|
|
2224
|
+
.terminal-actions::-webkit-scrollbar { display: none; }
|
|
2225
|
+
|
|
2226
|
+
.terminal-actions .action-btn {
|
|
2227
|
+
flex-shrink: 0;
|
|
2228
|
+
min-height: 36px; /* slightly smaller than 44 since these are arrow keys */
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
/* The arrow-key cluster compresses tighter to leave room */
|
|
2232
|
+
.terminal-actions .action-btn.action-arrow {
|
|
2233
|
+
padding: 6px 10px;
|
|
2234
|
+
min-width: 36px;
|
|
2212
2235
|
}
|
|
2213
2236
|
|
|
2214
2237
|
.terminal-header {
|
|
@@ -2285,14 +2308,62 @@
|
|
|
2285
2308
|
padding: 12px 14px;
|
|
2286
2309
|
}
|
|
2287
2310
|
|
|
2288
|
-
/*
|
|
2289
|
-
.
|
|
2311
|
+
/* Hamburger toggle — visible in header row on mobile */
|
|
2312
|
+
.nav-toggle {
|
|
2313
|
+
display: flex;
|
|
2314
|
+
align-items: center;
|
|
2315
|
+
gap: 8px;
|
|
2290
2316
|
margin-left: 12px;
|
|
2317
|
+
padding: 8px 12px;
|
|
2318
|
+
min-height: 40px;
|
|
2319
|
+
background: var(--bg);
|
|
2320
|
+
border: 1px solid var(--border);
|
|
2321
|
+
border-radius: 6px;
|
|
2322
|
+
color: var(--text);
|
|
2323
|
+
font-size: 14px;
|
|
2324
|
+
font-weight: 500;
|
|
2325
|
+
cursor: pointer;
|
|
2326
|
+
}
|
|
2327
|
+
.nav-toggle:hover { background: var(--bg-hover); }
|
|
2328
|
+
.nav-toggle[aria-expanded="true"] { background: var(--bg-active); border-color: var(--accent); }
|
|
2329
|
+
|
|
2330
|
+
/* On mobile the tab-bar becomes a vertical dropdown panel,
|
|
2331
|
+
hidden by default and toggled via the .nav-open class on .app */
|
|
2332
|
+
.tab-bar {
|
|
2333
|
+
position: absolute;
|
|
2334
|
+
top: 100%; /* below the header row */
|
|
2335
|
+
left: 0;
|
|
2336
|
+
right: 0;
|
|
2337
|
+
flex-direction: column;
|
|
2338
|
+
margin-left: 0;
|
|
2339
|
+
padding: 8px;
|
|
2340
|
+
gap: 4px;
|
|
2341
|
+
background: var(--bg-panel);
|
|
2342
|
+
border-bottom: 1px solid var(--border);
|
|
2343
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
|
|
2344
|
+
z-index: 100;
|
|
2345
|
+
overflow-x: visible;
|
|
2346
|
+
max-height: calc(100vh - 60px);
|
|
2347
|
+
overflow-y: auto;
|
|
2348
|
+
display: none;
|
|
2349
|
+
}
|
|
2350
|
+
.app.nav-open .tab-bar {
|
|
2351
|
+
display: flex;
|
|
2291
2352
|
}
|
|
2292
2353
|
|
|
2293
2354
|
.tab-bar .tab {
|
|
2294
|
-
|
|
2295
|
-
|
|
2355
|
+
width: 100%;
|
|
2356
|
+
text-align: left;
|
|
2357
|
+
border-radius: 6px;
|
|
2358
|
+
padding: 12px 14px;
|
|
2359
|
+
font-size: 15px;
|
|
2360
|
+
min-height: 44px;
|
|
2361
|
+
border-bottom: 1px solid var(--border);
|
|
2362
|
+
margin-bottom: 0;
|
|
2363
|
+
}
|
|
2364
|
+
.tab-bar .tab.active {
|
|
2365
|
+
background: var(--bg-active);
|
|
2366
|
+
border-color: var(--accent);
|
|
2296
2367
|
}
|
|
2297
2368
|
|
|
2298
2369
|
/* File viewer mobile */
|
|
@@ -2385,6 +2456,41 @@
|
|
|
2385
2456
|
.jobs-detail-content {
|
|
2386
2457
|
padding: 14px;
|
|
2387
2458
|
}
|
|
2459
|
+
|
|
2460
|
+
/* Filter chips and sort select were below 32px — bump to comfortable tap size */
|
|
2461
|
+
.jobs-filter-chip {
|
|
2462
|
+
padding: 8px 12px;
|
|
2463
|
+
font-size: 12px;
|
|
2464
|
+
min-height: 36px;
|
|
2465
|
+
}
|
|
2466
|
+
.jobs-sort {
|
|
2467
|
+
font-size: 13px;
|
|
2468
|
+
padding: 6px 8px;
|
|
2469
|
+
min-height: 36px;
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
/* Modal — explicit mobile rule instead of relying on max-width: 90vw fallback */
|
|
2473
|
+
.modal-dialog, .modal-content {
|
|
2474
|
+
width: calc(100vw - 24px);
|
|
2475
|
+
max-width: 100%;
|
|
2476
|
+
margin: 12px;
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
@media (max-width: 480px) {
|
|
2481
|
+
/* Even tighter — phone-only refinements */
|
|
2482
|
+
.header h1 { font-size: 14px; }
|
|
2483
|
+
.nav-toggle { padding: 6px 10px; font-size: 13px; }
|
|
2484
|
+
|
|
2485
|
+
/* Terminal action row — drop arrow keys to icon-only at very narrow widths */
|
|
2486
|
+
.terminal-actions .action-btn.action-arrow {
|
|
2487
|
+
padding: 6px 8px;
|
|
2488
|
+
min-width: 30px;
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
/* Jobs summary cards stack tighter */
|
|
2492
|
+
.jobs-summary-card { padding: 4px 2px; min-width: 40px; }
|
|
2493
|
+
.jobs-summary-val { font-size: 14px; }
|
|
2388
2494
|
}
|
|
2389
2495
|
</style>
|
|
2390
2496
|
</head>
|
|
@@ -2406,7 +2512,8 @@
|
|
|
2406
2512
|
<div class="header-left">
|
|
2407
2513
|
<img class="logo" src="/dashboard/logo.png" alt="Instar">
|
|
2408
2514
|
<h1>Instar Dashboard</h1>
|
|
2409
|
-
<
|
|
2515
|
+
<button class="nav-toggle" id="navToggle" aria-label="Open navigation menu" aria-expanded="false" onclick="toggleNavMenu()">☰ <span id="navToggleLabel">Sessions</span></button>
|
|
2516
|
+
<nav class="tab-bar" id="tabBar">
|
|
2410
2517
|
<button class="tab active" data-tab="sessions" onclick="switchTab('sessions')">Sessions <span class="tab-count" id="tabSessionCount">0</span></button>
|
|
2411
2518
|
<button class="tab" data-tab="files" onclick="switchTab('files')">Files</button>
|
|
2412
2519
|
<button class="tab" data-tab="dropzone" onclick="switchTab('dropzone')">Send Content</button>
|
|
@@ -2946,9 +3053,34 @@
|
|
|
2946
3053
|
<div id="tlBridgeError" style="color:var(--err, #c44);font-size:12px;display:none"></div>
|
|
2947
3054
|
</div>
|
|
2948
3055
|
|
|
2949
|
-
<!--
|
|
2950
|
-
<div style="border:1px
|
|
2951
|
-
|
|
3056
|
+
<!-- Conversation observability — threads list + message stream + search -->
|
|
3057
|
+
<div style="border:1px solid var(--border);border-radius:8px;padding:0;display:flex;flex-direction:column;min-height:480px">
|
|
3058
|
+
<!-- Toolbar -->
|
|
3059
|
+
<div style="display:flex;gap:8px;align-items:center;padding:12px 16px;border-bottom:1px solid var(--border)">
|
|
3060
|
+
<div style="font-weight:600">Conversations</div>
|
|
3061
|
+
<div style="flex:1"></div>
|
|
3062
|
+
<input type="search" id="tlObsSearchInput" placeholder="search messages…" style="padding:6px 8px;font-size:12px;width:220px" oninput="tlObsSearchDebounced(this.value)" />
|
|
3063
|
+
<select id="tlObsHasTopicFilter" onchange="tlObsLoadThreads()" style="padding:6px 8px;font-size:12px">
|
|
3064
|
+
<option value="">all threads</option>
|
|
3065
|
+
<option value="yes">with Telegram topic</option>
|
|
3066
|
+
<option value="no">without Telegram topic</option>
|
|
3067
|
+
</select>
|
|
3068
|
+
<input type="text" id="tlObsRemoteFilter" placeholder="agent filter" style="padding:6px 8px;font-size:12px;width:140px" oninput="tlObsLoadThreadsDebounced()" />
|
|
3069
|
+
<button onclick="tlObsLoadThreads()" style="padding:6px 10px;font-size:12px">Refresh</button>
|
|
3070
|
+
</div>
|
|
3071
|
+
|
|
3072
|
+
<!-- Two-pane: threads list + active thread -->
|
|
3073
|
+
<div style="display:grid;grid-template-columns:280px 1fr;flex:1;min-height:420px">
|
|
3074
|
+
<ul id="tlObsThreadsList" style="list-style:none;padding:0;margin:0;border-right:1px solid var(--border);overflow-y:auto;max-height:520px">
|
|
3075
|
+
<li style="padding:16px;color:var(--text-dim);font-size:12px">Loading…</li>
|
|
3076
|
+
</ul>
|
|
3077
|
+
<div id="tlObsConversation" style="padding:16px;overflow-y:auto;max-height:520px;display:flex;flex-direction:column;gap:10px">
|
|
3078
|
+
<div style="color:var(--text-dim);font-size:12px;font-style:italic">Select a thread on the left to view the conversation.</div>
|
|
3079
|
+
</div>
|
|
3080
|
+
</div>
|
|
3081
|
+
|
|
3082
|
+
<!-- Search results -->
|
|
3083
|
+
<div id="tlObsSearchResults" style="display:none;border-top:1px solid var(--border);padding:12px 16px;max-height:280px;overflow-y:auto"></div>
|
|
2952
3084
|
</div>
|
|
2953
3085
|
</div>
|
|
2954
3086
|
|
|
@@ -3445,7 +3577,7 @@
|
|
|
3445
3577
|
brightCyan: '#99f6e4',
|
|
3446
3578
|
brightWhite: '#eee',
|
|
3447
3579
|
},
|
|
3448
|
-
fontSize: window.innerWidth <= 768 ? 11 : 13,
|
|
3580
|
+
fontSize: window.innerWidth <= 480 ? 10 : window.innerWidth <= 768 ? 11 : 13,
|
|
3449
3581
|
fontFamily: "'SF Mono', 'Fira Code', 'JetBrains Mono', 'Cascadia Code', monospace",
|
|
3450
3582
|
cursorBlink: false,
|
|
3451
3583
|
cursorStyle: 'underline',
|
|
@@ -3463,6 +3595,12 @@
|
|
|
3463
3595
|
});
|
|
3464
3596
|
resizeObserver.observe(container);
|
|
3465
3597
|
|
|
3598
|
+
// Refit on window resize / orientation change — phone rotation may not
|
|
3599
|
+
// trigger ResizeObserver if the parent grid keeps its size.
|
|
3600
|
+
window.addEventListener('resize', () => {
|
|
3601
|
+
try { fitAddon.fit(); } catch {}
|
|
3602
|
+
});
|
|
3603
|
+
|
|
3466
3604
|
// Initial fit after a tick (container needs to be visible)
|
|
3467
3605
|
requestAnimationFrame(() => {
|
|
3468
3606
|
try { fitAddon.fit(); } catch {}
|
|
@@ -4008,7 +4146,10 @@
|
|
|
4008
4146
|
id: 'threadline',
|
|
4009
4147
|
panels: ['threadlineTab'],
|
|
4010
4148
|
display: ['flex'],
|
|
4011
|
-
onActivate: () => {
|
|
4149
|
+
onActivate: () => {
|
|
4150
|
+
if (typeof loadThreadlineBridgeConfig === 'function') loadThreadlineBridgeConfig();
|
|
4151
|
+
if (typeof tlObsLoadThreads === 'function') tlObsLoadThreads();
|
|
4152
|
+
},
|
|
4012
4153
|
},
|
|
4013
4154
|
{
|
|
4014
4155
|
id: 'secrets',
|
|
@@ -4024,6 +4165,51 @@
|
|
|
4024
4165
|
},
|
|
4025
4166
|
];
|
|
4026
4167
|
|
|
4168
|
+
function toggleNavMenu() {
|
|
4169
|
+
const app = document.querySelector('.app');
|
|
4170
|
+
const toggle = document.getElementById('navToggle');
|
|
4171
|
+
const open = app.classList.toggle('nav-open');
|
|
4172
|
+
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
4173
|
+
}
|
|
4174
|
+
|
|
4175
|
+
function updateNavToggleLabel(tabName) {
|
|
4176
|
+
// Read the tab name from the actual button so we don't drift when
|
|
4177
|
+
// tabs get renamed in the registry. Strip the trailing count badge
|
|
4178
|
+
// ("Jobs 3" → "Jobs") by ignoring child element text.
|
|
4179
|
+
const labelEl = document.getElementById('navToggleLabel');
|
|
4180
|
+
if (!labelEl) return;
|
|
4181
|
+
const tabBtn = document.querySelector(`.tab-bar .tab[data-tab="${tabName}"]`);
|
|
4182
|
+
let text = tabName;
|
|
4183
|
+
if (tabBtn) {
|
|
4184
|
+
// Clone the button, strip count badges, then read trimmed text.
|
|
4185
|
+
const clone = tabBtn.cloneNode(true);
|
|
4186
|
+
clone.querySelectorAll('.tab-count').forEach(el => el.remove());
|
|
4187
|
+
text = clone.textContent.trim() || tabName;
|
|
4188
|
+
}
|
|
4189
|
+
labelEl.textContent = text;
|
|
4190
|
+
}
|
|
4191
|
+
|
|
4192
|
+
function closeNavMenu() {
|
|
4193
|
+
const app = document.querySelector('.app');
|
|
4194
|
+
if (!app || !app.classList.contains('nav-open')) return;
|
|
4195
|
+
app.classList.remove('nav-open');
|
|
4196
|
+
const toggle = document.getElementById('navToggle');
|
|
4197
|
+
if (toggle) toggle.setAttribute('aria-expanded', 'false');
|
|
4198
|
+
}
|
|
4199
|
+
|
|
4200
|
+
// Close the mobile menu on Escape or on tap outside the tab bar.
|
|
4201
|
+
document.addEventListener('keydown', (e) => {
|
|
4202
|
+
if (e.key === 'Escape') closeNavMenu();
|
|
4203
|
+
});
|
|
4204
|
+
document.addEventListener('click', (e) => {
|
|
4205
|
+
const app = document.querySelector('.app');
|
|
4206
|
+
if (!app || !app.classList.contains('nav-open')) return;
|
|
4207
|
+
const tabBar = document.querySelector('.tab-bar');
|
|
4208
|
+
const toggle = document.getElementById('navToggle');
|
|
4209
|
+
if (tabBar?.contains(e.target) || toggle?.contains(e.target)) return;
|
|
4210
|
+
closeNavMenu();
|
|
4211
|
+
});
|
|
4212
|
+
|
|
4027
4213
|
function switchTab(tabName) {
|
|
4028
4214
|
if (tabName === currentTab) return;
|
|
4029
4215
|
|
|
@@ -4038,6 +4224,11 @@
|
|
|
4038
4224
|
btn.classList.toggle('active', btn.dataset.tab === tabName);
|
|
4039
4225
|
});
|
|
4040
4226
|
|
|
4227
|
+
updateNavToggleLabel(tabName);
|
|
4228
|
+
document.querySelector('.app').classList.remove('nav-open');
|
|
4229
|
+
const navToggle = document.getElementById('navToggle');
|
|
4230
|
+
if (navToggle) navToggle.setAttribute('aria-expanded', 'false');
|
|
4231
|
+
|
|
4041
4232
|
// Hide all panels
|
|
4042
4233
|
for (const tab of TAB_REGISTRY) {
|
|
4043
4234
|
for (const panelId of tab.panels) {
|
|
@@ -4303,6 +4494,158 @@
|
|
|
4303
4494
|
wire('tlBridgeMirrorExisting', 'mirrorExisting');
|
|
4304
4495
|
});
|
|
4305
4496
|
|
|
4497
|
+
// ── Threadline observability — threads list + conversation view ──
|
|
4498
|
+
let tlObsActiveThreadId = null;
|
|
4499
|
+
let tlObsLoadThreadsTimer = null;
|
|
4500
|
+
let tlObsSearchTimer = null;
|
|
4501
|
+
|
|
4502
|
+
function tlObsLoadThreadsDebounced() {
|
|
4503
|
+
if (tlObsLoadThreadsTimer) clearTimeout(tlObsLoadThreadsTimer);
|
|
4504
|
+
tlObsLoadThreadsTimer = setTimeout(tlObsLoadThreads, 300);
|
|
4505
|
+
}
|
|
4506
|
+
|
|
4507
|
+
function tlObsSearchDebounced(value) {
|
|
4508
|
+
if (tlObsSearchTimer) clearTimeout(tlObsSearchTimer);
|
|
4509
|
+
tlObsSearchTimer = setTimeout(() => tlObsRunSearch(value), 300);
|
|
4510
|
+
}
|
|
4511
|
+
|
|
4512
|
+
async function tlObsLoadThreads() {
|
|
4513
|
+
const list = document.getElementById('tlObsThreadsList');
|
|
4514
|
+
if (!list) return;
|
|
4515
|
+
const remoteAgent = document.getElementById('tlObsRemoteFilter')?.value?.trim() || '';
|
|
4516
|
+
const hasTopic = document.getElementById('tlObsHasTopicFilter')?.value || '';
|
|
4517
|
+
const params = new URLSearchParams();
|
|
4518
|
+
if (remoteAgent) params.set('remoteAgent', remoteAgent);
|
|
4519
|
+
if (hasTopic) params.set('hasTopic', hasTopic);
|
|
4520
|
+
try {
|
|
4521
|
+
const resp = await apiFetch('/threadline/observability/threads?' + params.toString());
|
|
4522
|
+
const threads = resp.threads || [];
|
|
4523
|
+
if (threads.length === 0) {
|
|
4524
|
+
list.innerHTML = '<li style="padding:16px;color:var(--text-dim);font-size:12px;font-style:italic">No threads yet.</li>';
|
|
4525
|
+
return;
|
|
4526
|
+
}
|
|
4527
|
+
list.innerHTML = threads.map(t => tlObsRenderThreadRow(t)).join('');
|
|
4528
|
+
} catch (err) {
|
|
4529
|
+
list.innerHTML = `<li style="padding:16px;color:var(--red)">Error: ${escapeHtml(err.message || String(err))}</li>`;
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
function tlObsRenderThreadRow(t) {
|
|
4534
|
+
const lastSeen = t.lastSeen ? fmtRelTime(t.lastSeen) : '—';
|
|
4535
|
+
const bridgeBadge = t.bridge
|
|
4536
|
+
? '<span style="display:inline-block;padding:1px 6px;border-radius:8px;background:#3b82f6;color:#fff;font-size:10px;margin-left:6px">TG</span>'
|
|
4537
|
+
: '';
|
|
4538
|
+
const spawnBadge = t.hasSpawnedSession
|
|
4539
|
+
? '<span style="display:inline-block;padding:1px 6px;border-radius:8px;background:#16a34a;color:#fff;font-size:10px;margin-left:4px">S</span>'
|
|
4540
|
+
: '';
|
|
4541
|
+
const isActive = tlObsActiveThreadId === t.threadId ? 'background:rgba(59,130,246,0.08);' : '';
|
|
4542
|
+
return `
|
|
4543
|
+
<li onclick="tlObsLoadThread('${t.threadId.replace(/'/g, "\\'")}')"
|
|
4544
|
+
style="padding:10px 12px;border-bottom:1px solid var(--border);cursor:pointer;${isActive}">
|
|
4545
|
+
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
4546
|
+
<div style="font-weight:600;font-size:13px">${escapeHtml(t.remoteAgentName)}${bridgeBadge}${spawnBadge}</div>
|
|
4547
|
+
<div style="font-size:11px;color:var(--text-dim)">${escapeHtml(lastSeen)}</div>
|
|
4548
|
+
</div>
|
|
4549
|
+
<div style="font-size:11px;color:var(--text-dim);margin-top:2px;font-family:monospace">
|
|
4550
|
+
${escapeHtml(t.threadId.slice(0, 16))}…
|
|
4551
|
+
</div>
|
|
4552
|
+
<div style="font-size:11px;color:var(--text-dim);margin-top:2px">
|
|
4553
|
+
${t.messageCount} msgs · ${t.inboundCount} in / ${t.outboundCount} out
|
|
4554
|
+
${typeof t.avgResponseLatencyMs === 'number' ? ' · ~' + Math.round(t.avgResponseLatencyMs / 1000) + 's reply' : ''}
|
|
4555
|
+
</div>
|
|
4556
|
+
</li>
|
|
4557
|
+
`;
|
|
4558
|
+
}
|
|
4559
|
+
|
|
4560
|
+
async function tlObsLoadThread(threadId) {
|
|
4561
|
+
tlObsActiveThreadId = threadId;
|
|
4562
|
+
tlObsLoadThreads(); // Re-render threads list to highlight active row
|
|
4563
|
+
const conv = document.getElementById('tlObsConversation');
|
|
4564
|
+
if (!conv) return;
|
|
4565
|
+
conv.innerHTML = '<div style="color:var(--text-dim);font-size:12px">Loading…</div>';
|
|
4566
|
+
try {
|
|
4567
|
+
const detail = await apiFetch(`/threadline/observability/threads/${encodeURIComponent(threadId)}`);
|
|
4568
|
+
conv.innerHTML = tlObsRenderConversation(detail);
|
|
4569
|
+
} catch (err) {
|
|
4570
|
+
conv.innerHTML = `<div style="color:var(--red);font-size:12px">Error: ${escapeHtml(err.message || String(err))}</div>`;
|
|
4571
|
+
}
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4574
|
+
function tlObsRenderConversation(detail) {
|
|
4575
|
+
const header = `
|
|
4576
|
+
<div style="border-bottom:1px solid var(--border);padding-bottom:10px;margin-bottom:10px">
|
|
4577
|
+
<div style="font-weight:600;font-size:14px">${escapeHtml(detail.remoteAgentName)}</div>
|
|
4578
|
+
<div style="font-family:monospace;font-size:11px;color:var(--text-dim)">${escapeHtml(detail.threadId)}</div>
|
|
4579
|
+
<div style="display:flex;gap:14px;font-size:11px;color:var(--text-dim);margin-top:6px;flex-wrap:wrap">
|
|
4580
|
+
<span>${detail.messageCount} messages</span>
|
|
4581
|
+
<span>${detail.inboundCount} in / ${detail.outboundCount} out</span>
|
|
4582
|
+
<span>first: ${escapeHtml(fmtRelTime(detail.firstSeen))}</span>
|
|
4583
|
+
<span>last: ${escapeHtml(fmtRelTime(detail.lastSeen))}</span>
|
|
4584
|
+
${typeof detail.avgResponseLatencyMs === 'number' ? '<span>avg reply: ' + Math.round(detail.avgResponseLatencyMs/1000) + 's</span>' : ''}
|
|
4585
|
+
${detail.bridge ? '<span>📨 topic ' + detail.bridge.topicId + '</span>' : '<span style="color:var(--text-dim);font-style:italic">no Telegram topic</span>'}
|
|
4586
|
+
${detail.hasSpawnedSession ? '<span>🧵 spawn-session</span>' : ''}
|
|
4587
|
+
</div>
|
|
4588
|
+
</div>
|
|
4589
|
+
`;
|
|
4590
|
+
const messages = (detail.messages || []).map(m => tlObsRenderMessage(m)).join('');
|
|
4591
|
+
return header + messages;
|
|
4592
|
+
}
|
|
4593
|
+
|
|
4594
|
+
function tlObsRenderMessage(m) {
|
|
4595
|
+
const isIn = m.direction === 'in';
|
|
4596
|
+
const bg = isIn ? 'rgba(99,102,241,0.10)' : 'rgba(34,197,94,0.10)';
|
|
4597
|
+
const border = isIn ? '#6366f1' : '#22c55e';
|
|
4598
|
+
const arrow = isIn ? '←' : '→';
|
|
4599
|
+
const meta = `${escapeHtml(m.timestamp)} · ${escapeHtml(m.id.slice(0, 8))}${m.outcome ? ' · ' + escapeHtml(m.outcome) : ''} · trust:${escapeHtml(m.trustLevel)}`;
|
|
4600
|
+
return `
|
|
4601
|
+
<div style="border-left:3px solid ${border};background:${bg};padding:8px 10px;border-radius:4px">
|
|
4602
|
+
<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:4px">
|
|
4603
|
+
<div style="font-weight:600;font-size:12px">
|
|
4604
|
+
${arrow} ${escapeHtml(m.remoteAgentName)}
|
|
4605
|
+
</div>
|
|
4606
|
+
<div style="font-size:11px;color:var(--text-dim)">${escapeHtml(fmtRelTime(m.timestamp))}</div>
|
|
4607
|
+
</div>
|
|
4608
|
+
<div style="font-size:13px;white-space:pre-wrap;word-break:break-word;line-height:1.4">${escapeHtml(m.text)}</div>
|
|
4609
|
+
<div style="font-family:monospace;font-size:10px;color:var(--text-dim);margin-top:4px">${meta}</div>
|
|
4610
|
+
</div>
|
|
4611
|
+
`;
|
|
4612
|
+
}
|
|
4613
|
+
|
|
4614
|
+
async function tlObsRunSearch(query) {
|
|
4615
|
+
const panel = document.getElementById('tlObsSearchResults');
|
|
4616
|
+
if (!panel) return;
|
|
4617
|
+
const q = (query || '').trim();
|
|
4618
|
+
if (!q) { panel.style.display = 'none'; return; }
|
|
4619
|
+
panel.style.display = 'block';
|
|
4620
|
+
panel.innerHTML = '<div style="color:var(--text-dim);font-size:12px">Searching…</div>';
|
|
4621
|
+
try {
|
|
4622
|
+
const resp = await apiFetch('/threadline/observability/search?q=' + encodeURIComponent(q) + '&limit=30');
|
|
4623
|
+
const hits = resp.hits || [];
|
|
4624
|
+
if (hits.length === 0) {
|
|
4625
|
+
panel.innerHTML = '<div style="color:var(--text-dim);font-size:12px">No matches.</div>';
|
|
4626
|
+
return;
|
|
4627
|
+
}
|
|
4628
|
+
panel.innerHTML = `<div style="font-size:12px;color:var(--text-dim);margin-bottom:8px">${hits.length} match${hits.length === 1 ? '' : 'es'} (click to open thread)</div>` +
|
|
4629
|
+
hits.map(h => `
|
|
4630
|
+
<div onclick="tlObsLoadThread('${h.message.threadId.replace(/'/g, "\\'")}')"
|
|
4631
|
+
style="padding:6px 8px;border-bottom:1px solid var(--border);cursor:pointer;font-size:12px">
|
|
4632
|
+
<div style="display:flex;justify-content:space-between">
|
|
4633
|
+
<span style="font-weight:600">${h.message.direction === 'in' ? '←' : '→'} ${escapeHtml(h.message.remoteAgentName)}</span>
|
|
4634
|
+
<span style="font-size:11px;color:var(--text-dim)">${escapeHtml(fmtRelTime(h.message.timestamp))}</span>
|
|
4635
|
+
</div>
|
|
4636
|
+
<div style="margin-top:2px;line-height:1.4">${tlObsRenderSnippet(h.snippet)}</div>
|
|
4637
|
+
</div>
|
|
4638
|
+
`).join('');
|
|
4639
|
+
} catch (err) {
|
|
4640
|
+
panel.innerHTML = `<div style="color:var(--red);font-size:12px">Error: ${escapeHtml(err.message || String(err))}</div>`;
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
|
|
4644
|
+
function tlObsRenderSnippet(s) {
|
|
4645
|
+
// Server returns matches wrapped in «...» — render as <mark>
|
|
4646
|
+
return escapeHtml(s).replace(/«/g, '<mark style="background:#fef08a;color:#000">').replace(/»/g, '</mark>');
|
|
4647
|
+
}
|
|
4648
|
+
|
|
4306
4649
|
async function loadFileTree() {
|
|
4307
4650
|
fileTreeLoaded = true;
|
|
4308
4651
|
const list = document.getElementById('fileTreeList');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAmDH,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yFAAyF;IACzF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBrE;AAkzCD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAkqC1E;AA0mBD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAuBlF"}
|
package/dist/commands/init.js
CHANGED
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
import fs from 'node:fs';
|
|
30
30
|
import os from 'node:os';
|
|
31
31
|
import path from 'node:path';
|
|
32
|
+
import { fileURLToPath } from 'node:url';
|
|
33
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
32
34
|
import pc from 'picocolors';
|
|
33
35
|
import { randomUUID } from 'node:crypto';
|
|
34
36
|
import { execFileSync, execSync } from 'node:child_process';
|
|
@@ -2534,7 +2536,7 @@ function installBuildSkill(skillsDir) {
|
|
|
2534
2536
|
if (fs.existsSync(skillFile) || fs.existsSync(path.join(buildDir, 'skill.md')))
|
|
2535
2537
|
return;
|
|
2536
2538
|
// Try to copy from bundled .claude/skills/build/ first
|
|
2537
|
-
const modDir =
|
|
2539
|
+
const modDir = __dirname;
|
|
2538
2540
|
const bundledSkill = path.join(modDir, '..', '..', '.claude', 'skills', 'build', 'SKILL.md');
|
|
2539
2541
|
if (fs.existsSync(bundledSkill)) {
|
|
2540
2542
|
fs.mkdirSync(buildDir, { recursive: true });
|
|
@@ -2573,7 +2575,7 @@ function installAutonomousSkill(skillsDir) {
|
|
|
2573
2575
|
const hooksDir = path.join(autonomousDir, 'hooks');
|
|
2574
2576
|
const scriptsDir = path.join(autonomousDir, 'scripts');
|
|
2575
2577
|
// Copy from instar's bundled skill files if they exist
|
|
2576
|
-
const modDir =
|
|
2578
|
+
const modDir = __dirname;
|
|
2577
2579
|
const bundledDir = path.join(path.dirname(path.dirname(modDir)), '.claude', 'skills', 'autonomous');
|
|
2578
2580
|
if (fs.existsSync(bundledDir)) {
|
|
2579
2581
|
// Copy from bundled source
|
|
@@ -3304,7 +3306,7 @@ function refreshScripts(projectDir, stateDir) {
|
|
|
3304
3306
|
* PostUpdateMigrator.getTelegramReplyScript() uses the same loading pattern.
|
|
3305
3307
|
*/
|
|
3306
3308
|
function loadRelayTemplate(filename, port) {
|
|
3307
|
-
const modDir =
|
|
3309
|
+
const modDir = __dirname;
|
|
3308
3310
|
const candidates = [
|
|
3309
3311
|
// dev: src/commands → ../templates/scripts
|
|
3310
3312
|
path.resolve(modDir, '..', 'templates', 'scripts', filename),
|
|
@@ -4010,7 +4012,7 @@ function installSerendipityCapture(projectDir) {
|
|
|
4010
4012
|
// Resolve template from package directory
|
|
4011
4013
|
// In dev: src/commands/ → ../../src/templates/scripts/serendipity-capture.sh
|
|
4012
4014
|
// In dist: dist/commands/ → ../templates/scripts/serendipity-capture.sh
|
|
4013
|
-
const modDir =
|
|
4015
|
+
const modDir = __dirname;
|
|
4014
4016
|
const candidates = [
|
|
4015
4017
|
path.resolve(modDir, '..', 'templates', 'scripts', 'serendipity-capture.sh'),
|
|
4016
4018
|
path.resolve(modDir, '..', '..', 'src', 'templates', 'scripts', 'serendipity-capture.sh'),
|