@ssm123ssm/vault 0.1.17 → 0.1.18
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/package.json +1 -1
- package/preview-agent.js +212 -26
package/package.json
CHANGED
package/preview-agent.js
CHANGED
|
@@ -235,36 +235,206 @@ async function selectDirectoryViaServer() {
|
|
|
235
235
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
236
236
|
<title>Preview Agent - Select Folder</title>
|
|
237
237
|
<style>
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
238
|
+
:root {
|
|
239
|
+
--bg: #0b0f14;
|
|
240
|
+
--bg-2: #0f1624;
|
|
241
|
+
--panel: #141c2b;
|
|
242
|
+
--panel-2: #0f1522;
|
|
243
|
+
--text: #e9edf2;
|
|
244
|
+
--muted: #94a3b8;
|
|
245
|
+
--accent: #ff7a18;
|
|
246
|
+
--accent-2: #ffb347;
|
|
247
|
+
--border: rgba(255,255,255,0.08);
|
|
248
|
+
}
|
|
249
|
+
* { box-sizing: border-box; }
|
|
250
|
+
body {
|
|
251
|
+
margin: 0;
|
|
252
|
+
color: var(--text);
|
|
253
|
+
font-family: "Space Grotesk", "Avenir Next", "Segoe UI", sans-serif;
|
|
254
|
+
background:
|
|
255
|
+
radial-gradient(1100px 600px at 15% -10%, rgba(255, 179, 71, 0.16), transparent 60%),
|
|
256
|
+
radial-gradient(900px 500px at 90% 0%, rgba(255, 122, 24, 0.18), transparent 55%),
|
|
257
|
+
linear-gradient(180deg, var(--bg), var(--bg-2));
|
|
258
|
+
}
|
|
259
|
+
.wrap { max-width: 900px; margin: 0 auto; padding: 28px 24px 40px; }
|
|
260
|
+
header { display:flex; align-items:center; justify-content:space-between; gap:16px; margin-bottom: 18px; }
|
|
261
|
+
h2 { margin: 0; font-size: 22px; letter-spacing: 0.3px; }
|
|
262
|
+
.subtitle { color: var(--muted); font-size: 13px; }
|
|
263
|
+
.panel {
|
|
264
|
+
background: linear-gradient(160deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01));
|
|
265
|
+
border: 1px solid var(--border);
|
|
266
|
+
border-radius: 18px;
|
|
267
|
+
padding: 16px;
|
|
268
|
+
box-shadow: 0 20px 50px rgba(0,0,0,0.35);
|
|
269
|
+
}
|
|
270
|
+
.toolbar { display:flex; flex-wrap:wrap; gap:10px; align-items:center; }
|
|
271
|
+
.pathline {
|
|
272
|
+
margin-top: 10px;
|
|
273
|
+
display:flex;
|
|
274
|
+
align-items:center;
|
|
275
|
+
gap:10px;
|
|
276
|
+
padding: 10px 12px;
|
|
277
|
+
border-radius: 12px;
|
|
278
|
+
background: var(--panel-2);
|
|
279
|
+
border: 1px solid var(--border);
|
|
280
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
|
281
|
+
font-size: 12px;
|
|
282
|
+
color: #d6dee8;
|
|
283
|
+
overflow-x: auto;
|
|
284
|
+
}
|
|
285
|
+
.breadcrumbs { display:flex; flex-wrap:wrap; gap:6px; margin-top: 10px; }
|
|
286
|
+
.crumb {
|
|
287
|
+
border: 1px solid transparent;
|
|
288
|
+
background: rgba(255,255,255,0.05);
|
|
289
|
+
color: #e2e8f0;
|
|
290
|
+
padding: 6px 10px;
|
|
291
|
+
border-radius: 999px;
|
|
292
|
+
cursor: pointer;
|
|
293
|
+
font-size: 12px;
|
|
294
|
+
}
|
|
295
|
+
.crumb:hover { border-color: rgba(255,255,255,0.2); }
|
|
296
|
+
.list { margin-top:14px; display:grid; gap:10px; }
|
|
297
|
+
.entry {
|
|
298
|
+
display:flex;
|
|
299
|
+
align-items:center;
|
|
300
|
+
justify-content:space-between;
|
|
301
|
+
width: 100%;
|
|
302
|
+
background: var(--panel);
|
|
303
|
+
color: var(--text);
|
|
304
|
+
border: 1px solid var(--border);
|
|
305
|
+
border-radius: 14px;
|
|
306
|
+
padding: 12px 14px;
|
|
307
|
+
cursor: pointer;
|
|
308
|
+
text-align: left;
|
|
309
|
+
}
|
|
310
|
+
.entry:hover { border-color: rgba(255, 122, 24, 0.6); }
|
|
311
|
+
.entry span { font-size: 14px; }
|
|
312
|
+
.entry small { color: var(--muted); }
|
|
313
|
+
.muted { color: var(--muted); font-size: 12px; }
|
|
314
|
+
.actions { display:flex; gap:10px; flex-wrap:wrap; margin-top: 16px; }
|
|
315
|
+
button {
|
|
316
|
+
background: rgba(255,255,255,0.06);
|
|
317
|
+
color: var(--text);
|
|
318
|
+
border: 1px solid var(--border);
|
|
319
|
+
border-radius: 12px;
|
|
320
|
+
padding: 10px 14px;
|
|
321
|
+
cursor: pointer;
|
|
322
|
+
font-size: 13px;
|
|
323
|
+
transition: border-color 0.2s ease, transform 0.2s ease;
|
|
324
|
+
}
|
|
325
|
+
button:hover { border-color: rgba(255, 122, 24, 0.7); transform: translateY(-1px); }
|
|
326
|
+
button:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
|
|
327
|
+
.primary {
|
|
328
|
+
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
|
329
|
+
color: #1b1209;
|
|
330
|
+
font-weight: 600;
|
|
331
|
+
border: none;
|
|
332
|
+
}
|
|
333
|
+
.ghost { background: transparent; }
|
|
334
|
+
input[type="text"] {
|
|
335
|
+
background: rgba(10, 14, 20, 0.6);
|
|
336
|
+
border: 1px solid var(--border);
|
|
337
|
+
border-radius: 12px;
|
|
338
|
+
padding: 10px 12px;
|
|
339
|
+
color: var(--text);
|
|
340
|
+
font-size: 13px;
|
|
341
|
+
min-width: 220px;
|
|
342
|
+
}
|
|
343
|
+
.footer { margin-top: 14px; font-size: 12px; color: var(--muted); }
|
|
247
344
|
</style>
|
|
248
345
|
</head>
|
|
249
346
|
<body>
|
|
250
347
|
<div class="wrap">
|
|
251
|
-
<
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
<
|
|
255
|
-
|
|
348
|
+
<header>
|
|
349
|
+
<div>
|
|
350
|
+
<h2>Choose a folder</h2>
|
|
351
|
+
<div class="subtitle">Pick the folder that should be linked to this project.</div>
|
|
352
|
+
</div>
|
|
353
|
+
<div class="muted" id="status">Waiting for selection…</div>
|
|
354
|
+
</header>
|
|
355
|
+
<div class="panel">
|
|
356
|
+
<div class="toolbar">
|
|
357
|
+
<button id="upBtn" class="ghost">Up one level</button>
|
|
358
|
+
<input id="filter" type="text" placeholder="Filter folders…" />
|
|
256
359
|
</div>
|
|
257
|
-
<div class="
|
|
360
|
+
<div class="pathline" id="path"></div>
|
|
361
|
+
<div class="breadcrumbs" id="breadcrumbs"></div>
|
|
258
362
|
<div class="list" id="list"></div>
|
|
363
|
+
<div class="actions">
|
|
364
|
+
<button id="confirmBtn" class="primary">Confirm selection</button>
|
|
365
|
+
<button id="closeBtn" class="ghost">Close window</button>
|
|
366
|
+
</div>
|
|
259
367
|
</div>
|
|
260
|
-
<
|
|
368
|
+
<div class="footer">Leave this window open until selection is confirmed. Closing it early will cancel the assignment.</div>
|
|
261
369
|
</div>
|
|
262
370
|
<script>
|
|
263
371
|
let currentPath = "";
|
|
372
|
+
let allEntries = [];
|
|
264
373
|
const pathEl = document.getElementById("path");
|
|
265
374
|
const listEl = document.getElementById("list");
|
|
266
375
|
const upBtn = document.getElementById("upBtn");
|
|
267
|
-
const
|
|
376
|
+
const confirmBtn = document.getElementById("confirmBtn");
|
|
377
|
+
const closeBtn = document.getElementById("closeBtn");
|
|
378
|
+
const statusEl = document.getElementById("status");
|
|
379
|
+
const filterEl = document.getElementById("filter");
|
|
380
|
+
const crumbsEl = document.getElementById("breadcrumbs");
|
|
381
|
+
|
|
382
|
+
function splitPathSegments(input) {
|
|
383
|
+
const hasBackslash = input.includes("\\\\") && !input.includes("/");
|
|
384
|
+
const sep = hasBackslash ? "\\\\" : "/";
|
|
385
|
+
const parts = input.split(sep).filter(Boolean);
|
|
386
|
+
const prefix = !hasBackslash && input.startsWith("/") ? "/" : "";
|
|
387
|
+
return { parts, sep, prefix };
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function renderBreadcrumbs(pathValue) {
|
|
391
|
+
crumbsEl.innerHTML = "";
|
|
392
|
+
const { parts, sep, prefix } = splitPathSegments(pathValue);
|
|
393
|
+
if (!parts.length) return;
|
|
394
|
+
let acc = prefix || "";
|
|
395
|
+
parts.forEach((part, index) => {
|
|
396
|
+
if (!acc) {
|
|
397
|
+
acc = part;
|
|
398
|
+
} else if (acc === "/" || acc.endsWith(sep)) {
|
|
399
|
+
acc = acc + part;
|
|
400
|
+
} else {
|
|
401
|
+
acc = acc + sep + part;
|
|
402
|
+
}
|
|
403
|
+
const btn = document.createElement("button");
|
|
404
|
+
btn.className = "crumb";
|
|
405
|
+
btn.textContent = part;
|
|
406
|
+
btn.onclick = () => load(acc);
|
|
407
|
+
crumbsEl.appendChild(btn);
|
|
408
|
+
if (index < parts.length - 1) {
|
|
409
|
+
const dot = document.createElement("span");
|
|
410
|
+
dot.className = "muted";
|
|
411
|
+
dot.textContent = "›";
|
|
412
|
+
crumbsEl.appendChild(dot);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function renderList() {
|
|
418
|
+
const term = (filterEl.value || "").trim().toLowerCase();
|
|
419
|
+
listEl.innerHTML = "";
|
|
420
|
+
const entries = allEntries.filter((entry) =>
|
|
421
|
+
entry.name.toLowerCase().includes(term)
|
|
422
|
+
);
|
|
423
|
+
if (!entries.length) {
|
|
424
|
+
const empty = document.createElement("div");
|
|
425
|
+
empty.className = "muted";
|
|
426
|
+
empty.textContent = "No folders match this filter.";
|
|
427
|
+
listEl.appendChild(empty);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
entries.forEach((entry) => {
|
|
431
|
+
const btn = document.createElement("button");
|
|
432
|
+
btn.className = "entry";
|
|
433
|
+
btn.innerHTML = "<span>" + entry.name + "/</span><small>Open</small>";
|
|
434
|
+
btn.onclick = () => load(entry.path);
|
|
435
|
+
listEl.appendChild(btn);
|
|
436
|
+
});
|
|
437
|
+
}
|
|
268
438
|
|
|
269
439
|
async function load(path) {
|
|
270
440
|
const res = await fetch("/api/list?path=" + encodeURIComponent(path || ""));
|
|
@@ -272,25 +442,33 @@ async function selectDirectoryViaServer() {
|
|
|
272
442
|
if (!res.ok) return;
|
|
273
443
|
currentPath = data.path;
|
|
274
444
|
pathEl.textContent = currentPath;
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
btn.textContent = entry.name + "/";
|
|
279
|
-
btn.onclick = () => load(entry.path);
|
|
280
|
-
listEl.appendChild(btn);
|
|
281
|
-
});
|
|
445
|
+
allEntries = data.entries || [];
|
|
446
|
+
renderList();
|
|
447
|
+
renderBreadcrumbs(currentPath);
|
|
282
448
|
upBtn.onclick = () => load(data.parent);
|
|
449
|
+
confirmBtn.disabled = !currentPath;
|
|
283
450
|
}
|
|
284
451
|
|
|
285
|
-
|
|
452
|
+
confirmBtn.onclick = async () => {
|
|
453
|
+
if (!currentPath) return;
|
|
454
|
+
statusEl.textContent = "Confirming selection…";
|
|
286
455
|
await fetch("/api/select", {
|
|
287
456
|
method: "POST",
|
|
288
457
|
headers: { "Content-Type": "application/json" },
|
|
289
458
|
body: JSON.stringify({ path: currentPath }),
|
|
290
459
|
});
|
|
291
|
-
|
|
460
|
+
confirmBtn.textContent = "Confirmed";
|
|
461
|
+
statusEl.textContent = "Selection confirmed. You can close this window.";
|
|
462
|
+
setTimeout(() => window.close(), 150);
|
|
292
463
|
};
|
|
293
464
|
|
|
465
|
+
closeBtn.onclick = () => {
|
|
466
|
+
window.close();
|
|
467
|
+
statusEl.textContent = "You can close this window now.";
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
filterEl.addEventListener("input", () => renderList());
|
|
471
|
+
|
|
294
472
|
load("");
|
|
295
473
|
</script>
|
|
296
474
|
</body>
|
|
@@ -786,6 +964,14 @@ function runDaemon() {
|
|
|
786
964
|
const sourceDir = daemonMode || uiMode
|
|
787
965
|
? await selectDirectoryViaServer()
|
|
788
966
|
: await selectDirectory(process.cwd());
|
|
967
|
+
const selectionMode = daemonMode
|
|
968
|
+
? "daemon"
|
|
969
|
+
: uiMode
|
|
970
|
+
? "ui"
|
|
971
|
+
: "interactive";
|
|
972
|
+
console.log(
|
|
973
|
+
`[${agentLabel}] Selected folder (${selectionMode}): ${sourceDir}`
|
|
974
|
+
);
|
|
789
975
|
config.projects = config.projects || {};
|
|
790
976
|
config.projects[command.projectId] = {
|
|
791
977
|
source: sourceDir,
|