switchroom 0.14.86 → 0.14.88
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/dist/cli/switchroom.js
CHANGED
|
@@ -29710,7 +29710,7 @@ import {
|
|
|
29710
29710
|
constants as fsConstants4,
|
|
29711
29711
|
existsSync as existsSync52,
|
|
29712
29712
|
realpathSync as realpathSync4,
|
|
29713
|
-
statSync as
|
|
29713
|
+
statSync as statSync22
|
|
29714
29714
|
} from "node:fs";
|
|
29715
29715
|
import { userInfo, homedir as homedir25 } from "node:os";
|
|
29716
29716
|
import { join as join46 } from "node:path";
|
|
@@ -29728,7 +29728,7 @@ function defaultStatVault(path4) {
|
|
|
29728
29728
|
let uid = -1;
|
|
29729
29729
|
let mode = 0;
|
|
29730
29730
|
try {
|
|
29731
|
-
const s =
|
|
29731
|
+
const s = statSync22(real);
|
|
29732
29732
|
uid = s.uid;
|
|
29733
29733
|
mode = s.mode & 511;
|
|
29734
29734
|
} catch {
|
|
@@ -31226,7 +31226,7 @@ var init_doctor_agent_smoke = __esm(() => {
|
|
|
31226
31226
|
|
|
31227
31227
|
// src/cli/doctor-vault-broker-durability.ts
|
|
31228
31228
|
import { execFileSync as execFileSync18 } from "node:child_process";
|
|
31229
|
-
import { existsSync as existsSync54, statSync as
|
|
31229
|
+
import { existsSync as existsSync54, statSync as statSync23 } from "node:fs";
|
|
31230
31230
|
import { homedir as homedir33 } from "node:os";
|
|
31231
31231
|
import { join as join55 } from "node:path";
|
|
31232
31232
|
function probeBindMountInode(hostPath, brokerContainerPath, opts) {
|
|
@@ -31253,7 +31253,7 @@ function defaultStatHost(p) {
|
|
|
31253
31253
|
if (!existsSync54(p))
|
|
31254
31254
|
return null;
|
|
31255
31255
|
try {
|
|
31256
|
-
const s =
|
|
31256
|
+
const s = statSync23(p, { bigint: true });
|
|
31257
31257
|
return { ino: s.ino, size: Number(s.size) };
|
|
31258
31258
|
} catch {
|
|
31259
31259
|
return null;
|
|
@@ -31463,7 +31463,7 @@ function probeAutoUnlockBlob(home2) {
|
|
|
31463
31463
|
fix: "Run `switchroom vault broker enable-auto-unlock` to seal the blob with the current passphrase + machine-id"
|
|
31464
31464
|
};
|
|
31465
31465
|
}
|
|
31466
|
-
const sz =
|
|
31466
|
+
const sz = statSync23(blobPath).size;
|
|
31467
31467
|
if (sz === 0) {
|
|
31468
31468
|
return {
|
|
31469
31469
|
name: "vault-broker: auto-unlock blob",
|
|
@@ -31563,7 +31563,7 @@ import {
|
|
|
31563
31563
|
mkdirSync as mkdirSync30,
|
|
31564
31564
|
readFileSync as readFileSync49,
|
|
31565
31565
|
readdirSync as readdirSync20,
|
|
31566
|
-
statSync as
|
|
31566
|
+
statSync as statSync24
|
|
31567
31567
|
} from "node:fs";
|
|
31568
31568
|
import { dirname as dirname12, join as join56, resolve as resolve32 } from "node:path";
|
|
31569
31569
|
import { createPublicKey, createPrivateKey } from "node:crypto";
|
|
@@ -31576,7 +31576,7 @@ function findInNvm(bin) {
|
|
|
31576
31576
|
for (const v of versions) {
|
|
31577
31577
|
const candidate = join56(nvmRoot, v, "bin", bin);
|
|
31578
31578
|
try {
|
|
31579
|
-
const s =
|
|
31579
|
+
const s = statSync24(candidate);
|
|
31580
31580
|
if (s.isFile() || s.isSymbolicLink()) {
|
|
31581
31581
|
return candidate;
|
|
31582
31582
|
}
|
|
@@ -49404,7 +49404,7 @@ __export(exports_server2, {
|
|
|
49404
49404
|
TOOLS: () => TOOLS2
|
|
49405
49405
|
});
|
|
49406
49406
|
import { randomBytes as randomBytes15 } from "node:crypto";
|
|
49407
|
-
import { existsSync as existsSync83, readFileSync as
|
|
49407
|
+
import { existsSync as existsSync83, readFileSync as readFileSync69 } from "node:fs";
|
|
49408
49408
|
function selfSocketPath() {
|
|
49409
49409
|
return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
|
|
49410
49410
|
}
|
|
@@ -49582,7 +49582,7 @@ function getLastUpdateApplyStatus() {
|
|
|
49582
49582
|
}
|
|
49583
49583
|
let raw;
|
|
49584
49584
|
try {
|
|
49585
|
-
raw =
|
|
49585
|
+
raw = readFileSync69(path8, "utf-8");
|
|
49586
49586
|
} catch (err2) {
|
|
49587
49587
|
return errorText2(`get_status: failed to read audit log at ${path8}: ${err2.message}`);
|
|
49588
49588
|
}
|
|
@@ -49815,8 +49815,8 @@ var {
|
|
|
49815
49815
|
} = import__.default;
|
|
49816
49816
|
|
|
49817
49817
|
// src/build-info.ts
|
|
49818
|
-
var VERSION = "0.14.
|
|
49819
|
-
var COMMIT_SHA = "
|
|
49818
|
+
var VERSION = "0.14.88";
|
|
49819
|
+
var COMMIT_SHA = "b3c61552";
|
|
49820
49820
|
|
|
49821
49821
|
// src/cli/agent.ts
|
|
49822
49822
|
init_source();
|
|
@@ -50583,6 +50583,36 @@ Example response shapes:
|
|
|
50583
50583
|
\`docker/Dockerfile.agent\` and rebuild the agent image."
|
|
50584
50584
|
- "I tried to clone into \`/workspace\` \u2014 that path doesn't exist in my
|
|
50585
50585
|
sandbox. Cloning into \`$HOME/workspace\` instead."`;
|
|
50586
|
+
var DELIVERY_GUIDANCE = `## Delivering a file to the user
|
|
50587
|
+
|
|
50588
|
+
You run in a container. A local path like \`/state/agent/...\` or
|
|
50589
|
+
\`/tmp/...\` means **nothing** to the user \u2014 they are not on your box and
|
|
50590
|
+
cannot open it. When you produce a file the user should have, **deliver
|
|
50591
|
+
it**, don't print its path.
|
|
50592
|
+
|
|
50593
|
+
### Send it in Telegram (default for most files)
|
|
50594
|
+
The \`reply\` tool attaches files: pass \`files: ["/abs/path"]\` (images
|
|
50595
|
+
send as photos, everything else as documents; 50 MB max each). This is
|
|
50596
|
+
the right channel for almost anything \u2014 a report, a CSV, a chart, a
|
|
50597
|
+
generated doc \u2014 the user gets it straight in the chat. Prefer this.
|
|
50598
|
+
|
|
50599
|
+
### Put it in their Drive (for files they'll keep or edit, or > 50 MB)
|
|
50600
|
+
Run \`switchroom deliver-file <path>\`. It uploads the file into the user's
|
|
50601
|
+
\`Switchroom/<your-agent-name>\` folder on their connected drive (creating
|
|
50602
|
+
the folder if needed) and prints a share link. Reply with that link \u2014 not
|
|
50603
|
+
a path. This is the reliable way: switchroom owns the destination and the
|
|
50604
|
+
upload, so you don't guess folder names or hit a per-file approval. (If you
|
|
50605
|
+
prefer the raw \`gdrive\` / \`ms-365\` MCP tools, still target that same
|
|
50606
|
+
\`Switchroom/<your-agent-name>\` folder \u2014 never scatter files loose in the
|
|
50607
|
+
user's drive.)
|
|
50608
|
+
|
|
50609
|
+
### If you can't deliver
|
|
50610
|
+
No Drive connected and the file is too big for Telegram? Say so plainly
|
|
50611
|
+
and offer the fix ("connect a Drive from the dashboard and I'll put it
|
|
50612
|
+
there"). Don't fall back to handing over a local path that leads nowhere.
|
|
50613
|
+
|
|
50614
|
+
The rule: the user must be able to **reach** what you made. A path on your
|
|
50615
|
+
container is not delivery.`;
|
|
50586
50616
|
var TELEGRAM_GUIDANCE = `## Talking to a human on Telegram
|
|
50587
50617
|
|
|
50588
50618
|
There is a real person on the other end. Every turn should feel like
|
|
@@ -50765,6 +50795,8 @@ function renderFleetInvariants() {
|
|
|
50765
50795
|
"",
|
|
50766
50796
|
SANDBOX_GUIDANCE,
|
|
50767
50797
|
"",
|
|
50798
|
+
DELIVERY_GUIDANCE,
|
|
50799
|
+
"",
|
|
50768
50800
|
TELEGRAM_GUIDANCE,
|
|
50769
50801
|
"",
|
|
50770
50802
|
MEMORY_GUIDANCE,
|
|
@@ -58626,6 +58658,231 @@ async function readHiddenLine2(prompt) {
|
|
|
58626
58658
|
});
|
|
58627
58659
|
}
|
|
58628
58660
|
|
|
58661
|
+
// src/cli/auth-schedule.ts
|
|
58662
|
+
init_source();
|
|
58663
|
+
init_broker_call();
|
|
58664
|
+
init_helpers();
|
|
58665
|
+
var WEEKLY_WALL_PCT = 99.5;
|
|
58666
|
+
function resolveWindow(account, probe) {
|
|
58667
|
+
const entry = probe?.results.find((r) => r.label === account.label);
|
|
58668
|
+
if (entry && entry.result.ok) {
|
|
58669
|
+
const d = entry.result.data;
|
|
58670
|
+
return {
|
|
58671
|
+
fiveHourPct: d.fiveHourUtilizationPct,
|
|
58672
|
+
fiveHourResetAt: d.fiveHourResetAt,
|
|
58673
|
+
weeklyPct: d.sevenDayUtilizationPct,
|
|
58674
|
+
weeklyResetAt: d.sevenDayResetAt,
|
|
58675
|
+
source: "live"
|
|
58676
|
+
};
|
|
58677
|
+
}
|
|
58678
|
+
const lq = account.last_quota;
|
|
58679
|
+
if (lq) {
|
|
58680
|
+
return {
|
|
58681
|
+
fiveHourPct: lq.fiveHourUtilizationPct,
|
|
58682
|
+
fiveHourResetAt: lq.fiveHourResetAt ? new Date(lq.fiveHourResetAt) : null,
|
|
58683
|
+
weeklyPct: lq.sevenDayUtilizationPct,
|
|
58684
|
+
weeklyResetAt: lq.sevenDayResetAt ? new Date(lq.sevenDayResetAt) : null,
|
|
58685
|
+
source: "cached"
|
|
58686
|
+
};
|
|
58687
|
+
}
|
|
58688
|
+
return {
|
|
58689
|
+
fiveHourPct: null,
|
|
58690
|
+
fiveHourResetAt: null,
|
|
58691
|
+
weeklyPct: null,
|
|
58692
|
+
weeklyResetAt: null,
|
|
58693
|
+
source: "none"
|
|
58694
|
+
};
|
|
58695
|
+
}
|
|
58696
|
+
function classifyState(args) {
|
|
58697
|
+
const { exhausted, exhaustedUntil, window: window2, now } = args;
|
|
58698
|
+
const hasWindowData = window2.fiveHourPct !== null || window2.weeklyPct !== null || window2.fiveHourResetAt !== null || window2.weeklyResetAt !== null;
|
|
58699
|
+
if (window2.weeklyPct !== null && window2.weeklyPct >= WEEKLY_WALL_PCT && window2.weeklyResetAt !== null && window2.weeklyResetAt.getTime() > now.getTime()) {
|
|
58700
|
+
return "weekly-walled";
|
|
58701
|
+
}
|
|
58702
|
+
if (!exhausted) {
|
|
58703
|
+
return hasWindowData || exhaustedUntil !== null ? "healthy" : "unprobed";
|
|
58704
|
+
}
|
|
58705
|
+
const until = exhaustedUntil?.getTime();
|
|
58706
|
+
if (until === undefined)
|
|
58707
|
+
return "walled";
|
|
58708
|
+
const remaining = until - now.getTime();
|
|
58709
|
+
if (remaining <= 0)
|
|
58710
|
+
return "healthy";
|
|
58711
|
+
const TOL_MS = 15 * 60 * 1000;
|
|
58712
|
+
const near = (d) => d !== null && Math.abs(d.getTime() - until) <= TOL_MS;
|
|
58713
|
+
if (near(window2.weeklyResetAt))
|
|
58714
|
+
return "weekly-walled";
|
|
58715
|
+
if (near(window2.fiveHourResetAt))
|
|
58716
|
+
return "5h-walled";
|
|
58717
|
+
if (remaining < 6 * 3600000)
|
|
58718
|
+
return "5h-walled";
|
|
58719
|
+
if (remaining >= 20 * 3600000)
|
|
58720
|
+
return "weekly-walled";
|
|
58721
|
+
return "walled";
|
|
58722
|
+
}
|
|
58723
|
+
function buildScheduleRows(state, probe, now) {
|
|
58724
|
+
const rows = state.accounts.map((a) => {
|
|
58725
|
+
const window2 = resolveWindow(a, probe);
|
|
58726
|
+
const exhaustedUntil = typeof a.exhausted_until === "number" ? new Date(a.exhausted_until) : null;
|
|
58727
|
+
const exhausted = a.exhausted && (exhaustedUntil?.getTime() ?? 0) > now.getTime();
|
|
58728
|
+
const rank = state.fallback_order.indexOf(a.label);
|
|
58729
|
+
return {
|
|
58730
|
+
label: a.label,
|
|
58731
|
+
isActive: a.label === state.active,
|
|
58732
|
+
fallbackRank: rank === -1 ? null : rank + 1,
|
|
58733
|
+
window: window2,
|
|
58734
|
+
exhausted,
|
|
58735
|
+
exhaustedUntil,
|
|
58736
|
+
state: classifyState({ exhausted, exhaustedUntil, window: window2, now })
|
|
58737
|
+
};
|
|
58738
|
+
});
|
|
58739
|
+
const key = (r) => r.isActive ? -1 : r.fallbackRank ?? 9999;
|
|
58740
|
+
return rows.sort((a, b) => key(a) - key(b) || a.label.localeCompare(b.label));
|
|
58741
|
+
}
|
|
58742
|
+
var EM_DASH = "\u2014";
|
|
58743
|
+
function formatDuration(ms) {
|
|
58744
|
+
if (ms <= 0)
|
|
58745
|
+
return "now";
|
|
58746
|
+
const d = Math.floor(ms / 86400000);
|
|
58747
|
+
const h = Math.floor(ms % 86400000 / 3600000);
|
|
58748
|
+
const m = Math.floor(ms % 3600000 / 60000);
|
|
58749
|
+
if (d > 0)
|
|
58750
|
+
return `${d}d ${h}h`;
|
|
58751
|
+
if (h > 0)
|
|
58752
|
+
return `${h}h ${m}m`;
|
|
58753
|
+
return `${m}m`;
|
|
58754
|
+
}
|
|
58755
|
+
function tzOpts(tz) {
|
|
58756
|
+
return tz ? { timeZone: tz } : {};
|
|
58757
|
+
}
|
|
58758
|
+
function formatResetDay(d, tz) {
|
|
58759
|
+
const opts = tzOpts(tz);
|
|
58760
|
+
const dow = d.toLocaleDateString("en-US", { weekday: "short", ...opts });
|
|
58761
|
+
const hm = d.toLocaleTimeString("en-GB", {
|
|
58762
|
+
hour: "2-digit",
|
|
58763
|
+
minute: "2-digit",
|
|
58764
|
+
hour12: false,
|
|
58765
|
+
...opts
|
|
58766
|
+
});
|
|
58767
|
+
return `${dow} ${hm}`;
|
|
58768
|
+
}
|
|
58769
|
+
function formatFiveHourCell(w, now) {
|
|
58770
|
+
if (w.fiveHourPct === null)
|
|
58771
|
+
return EM_DASH;
|
|
58772
|
+
const reset = w.fiveHourResetAt ? ` \u00b7 ${formatDuration(w.fiveHourResetAt.getTime() - now.getTime())}` : "";
|
|
58773
|
+
return `${Math.round(w.fiveHourPct)}%${reset}`;
|
|
58774
|
+
}
|
|
58775
|
+
function formatWeeklyCell(w, now, tz) {
|
|
58776
|
+
if (w.weeklyPct === null && w.weeklyResetAt === null)
|
|
58777
|
+
return EM_DASH;
|
|
58778
|
+
const pct = w.weeklyPct === null ? EM_DASH : `${Math.round(w.weeklyPct)}%`;
|
|
58779
|
+
if (!w.weeklyResetAt)
|
|
58780
|
+
return pct;
|
|
58781
|
+
const rel = formatDuration(w.weeklyResetAt.getTime() - now.getTime());
|
|
58782
|
+
return `${pct} \u00b7 ${formatResetDay(w.weeklyResetAt, tz)} (${rel})`;
|
|
58783
|
+
}
|
|
58784
|
+
function poolLabel(row) {
|
|
58785
|
+
if (row.isActive)
|
|
58786
|
+
return row.fallbackRank ? `active #${row.fallbackRank}` : "active";
|
|
58787
|
+
if (row.fallbackRank)
|
|
58788
|
+
return `#${row.fallbackRank}`;
|
|
58789
|
+
return "excluded";
|
|
58790
|
+
}
|
|
58791
|
+
function formatStateCell(row, now) {
|
|
58792
|
+
const horizon = row.state === "weekly-walled" ? row.window.weeklyResetAt ?? row.exhaustedUntil : row.state === "5h-walled" ? row.window.fiveHourResetAt ?? row.exhaustedUntil : row.exhaustedUntil;
|
|
58793
|
+
const rel = horizon ? ` \u00b7 ${formatDuration(horizon.getTime() - now.getTime())}` : "";
|
|
58794
|
+
switch (row.state) {
|
|
58795
|
+
case "healthy":
|
|
58796
|
+
return "healthy";
|
|
58797
|
+
case "unprobed":
|
|
58798
|
+
return "no recent probe";
|
|
58799
|
+
case "5h-walled":
|
|
58800
|
+
return `5h-walled${rel}`;
|
|
58801
|
+
case "weekly-walled":
|
|
58802
|
+
return `weekly-walled${rel}`;
|
|
58803
|
+
case "walled":
|
|
58804
|
+
return `walled${rel}`;
|
|
58805
|
+
}
|
|
58806
|
+
}
|
|
58807
|
+
var W = { label: 30, pool: 11, five: 15, weekly: 26 };
|
|
58808
|
+
function pad3(s, n) {
|
|
58809
|
+
if (s.length > n)
|
|
58810
|
+
return s.length > 1 ? s.slice(0, n - 1) + "\u2026" : s;
|
|
58811
|
+
return s.padEnd(n);
|
|
58812
|
+
}
|
|
58813
|
+
function glyphFor(row, color) {
|
|
58814
|
+
const g = row.isActive ? "\u25cf" : row.exhausted ? "!" : row.state === "unprobed" ? "\u00b7" : "\u2713";
|
|
58815
|
+
if (!color)
|
|
58816
|
+
return g;
|
|
58817
|
+
return row.isActive ? source_default.green(g) : row.exhausted ? source_default.red(g) : source_default.gray(g);
|
|
58818
|
+
}
|
|
58819
|
+
function colorState(text, state, color) {
|
|
58820
|
+
if (!color)
|
|
58821
|
+
return text;
|
|
58822
|
+
switch (state) {
|
|
58823
|
+
case "healthy":
|
|
58824
|
+
return source_default.green(text);
|
|
58825
|
+
case "weekly-walled":
|
|
58826
|
+
return source_default.red(text);
|
|
58827
|
+
case "5h-walled":
|
|
58828
|
+
return source_default.yellow(text);
|
|
58829
|
+
default:
|
|
58830
|
+
return source_default.gray(text);
|
|
58831
|
+
}
|
|
58832
|
+
}
|
|
58833
|
+
function formatScheduleRows(rows, now, opts = {}) {
|
|
58834
|
+
const color = opts.color ?? true;
|
|
58835
|
+
const line = (glyph, label, p, five, weekly, state) => ` ${glyph} ${pad3(label, W.label)} ${pad3(p, W.pool)} ${pad3(five, W.five)} ${pad3(weekly, W.weekly)} ${state}`;
|
|
58836
|
+
const header = line(" ", "ACCOUNT", "POOL", "5H WINDOW", "WEEKLY WINDOW", "STATE");
|
|
58837
|
+
const out = [color ? source_default.bold(header) : header];
|
|
58838
|
+
for (const row of rows) {
|
|
58839
|
+
out.push(line(glyphFor(row, color), row.label, poolLabel(row), formatFiveHourCell(row.window, now), formatWeeklyCell(row.window, now, opts.tz), colorState(formatStateCell(row, now), row.state, color)));
|
|
58840
|
+
}
|
|
58841
|
+
return out;
|
|
58842
|
+
}
|
|
58843
|
+
function formatFooter(rows, opts, now, tz) {
|
|
58844
|
+
const zone = tz ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
58845
|
+
const at = formatResetDay(now, tz);
|
|
58846
|
+
const src = opts.probedLive ? `probed live \u00b7 ${at} ${zone}` : opts.liveRequested ? `live probe unavailable \u2014 showing cached snapshot \u00b7 times in ${zone}` : `cached snapshot (run without --cached for a live probe) \u00b7 times in ${zone}`;
|
|
58847
|
+
const anyUnprobed = rows.some((r) => r.window.source === "none");
|
|
58848
|
+
const lines = [src];
|
|
58849
|
+
if (!opts.probedLive && anyUnprobed) {
|
|
58850
|
+
lines.push(opts.liveRequested ? "some accounts have no quota data \u2014 the broker may not have served a probe" : "some accounts have no cached probe yet \u2014 run without --cached to populate");
|
|
58851
|
+
}
|
|
58852
|
+
return lines;
|
|
58853
|
+
}
|
|
58854
|
+
function registerAuthScheduleSubcommands(_program, authParent) {
|
|
58855
|
+
authParent.command("schedule").description("Per-account quota schedule \u2014 5h vs WEEKLY window, % used, and reset day (live probe by default)").option("--cached", "Use the broker's cached snapshot; skip the live probe").option("--json", "Output JSON").action(withConfigError(async (opts) => {
|
|
58856
|
+
const live = !opts.cached;
|
|
58857
|
+
const { state, probe } = await brokerCall(async (client) => {
|
|
58858
|
+
const s = await client.listState();
|
|
58859
|
+
let p;
|
|
58860
|
+
if (live) {
|
|
58861
|
+
const labels = s.accounts.map((a) => a.label);
|
|
58862
|
+
p = labels.length > 0 ? await client.probeQuota(labels).catch(() => {
|
|
58863
|
+
return;
|
|
58864
|
+
}) : undefined;
|
|
58865
|
+
}
|
|
58866
|
+
return { state: s, probe: p };
|
|
58867
|
+
});
|
|
58868
|
+
if (opts.json) {
|
|
58869
|
+
console.log(JSON.stringify({ ...state, probe: probe ?? null }, null, 2));
|
|
58870
|
+
return;
|
|
58871
|
+
}
|
|
58872
|
+
const now = new Date;
|
|
58873
|
+
const rows = buildScheduleRows(state, probe, now);
|
|
58874
|
+
const probedLive = live && probe !== undefined;
|
|
58875
|
+
console.log();
|
|
58876
|
+
for (const l of formatScheduleRows(rows, now))
|
|
58877
|
+
console.log(l);
|
|
58878
|
+
console.log();
|
|
58879
|
+
for (const l of formatFooter(rows, { liveRequested: live, probedLive }, now)) {
|
|
58880
|
+
console.log(source_default.gray(" " + l));
|
|
58881
|
+
}
|
|
58882
|
+
console.log();
|
|
58883
|
+
}));
|
|
58884
|
+
}
|
|
58885
|
+
|
|
58629
58886
|
// src/cli/auth.ts
|
|
58630
58887
|
init_auth_active_yaml();
|
|
58631
58888
|
init_atomic();
|
|
@@ -58910,6 +59167,7 @@ function registerAuthCommand(program3) {
|
|
|
58910
59167
|
const auth = program3.command("auth").description("Manage OAuth authentication via switchroom-auth-broker (RFC H)");
|
|
58911
59168
|
registerAuthGoogleSubcommands(program3, auth);
|
|
58912
59169
|
registerAuthMicrosoftSubcommands(program3, auth);
|
|
59170
|
+
registerAuthScheduleSubcommands(program3, auth);
|
|
58913
59171
|
auth.command("heal <agent>").description("[boot self-test] emit structural auth-state diagnosis as JSON").option("--json", "Emit JSON (the only supported output)").option("--config-dir <dir>", "Override the .claude config dir to inspect (default: <agentsDir>/<agent>/.claude)").action(async (agent, opts) => {
|
|
58914
59172
|
let configDir = opts.configDir;
|
|
58915
59173
|
if (configDir === undefined) {
|
|
@@ -66888,7 +67146,7 @@ init_lifecycle();
|
|
|
66888
67146
|
init_manager();
|
|
66889
67147
|
init_hindsight();
|
|
66890
67148
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
66891
|
-
import { existsSync as existsSync45, readFileSync as readFileSync41 } from "node:fs";
|
|
67149
|
+
import { existsSync as existsSync45, readFileSync as readFileSync41, statSync as statSync21 } from "node:fs";
|
|
66892
67150
|
import { resolve as resolve27 } from "node:path";
|
|
66893
67151
|
init_audit_reader();
|
|
66894
67152
|
|
|
@@ -71913,9 +72171,18 @@ function listSubagents(db, opts = {}) {
|
|
|
71913
72171
|
}
|
|
71914
72172
|
|
|
71915
72173
|
// src/web/api.ts
|
|
72174
|
+
function agentBridgeAlive(agentsDir, name, maxAgeMs = 30000, now = Date.now()) {
|
|
72175
|
+
try {
|
|
72176
|
+
const f = resolve27(agentsDir, name, "telegram", ".bridge-alive");
|
|
72177
|
+
return now - statSync21(f).mtimeMs <= maxAgeMs;
|
|
72178
|
+
} catch {
|
|
72179
|
+
return false;
|
|
72180
|
+
}
|
|
72181
|
+
}
|
|
71916
72182
|
function handleGetAgents(config) {
|
|
71917
72183
|
const statuses = getAllAgentStatuses(config);
|
|
71918
72184
|
const authStatuses = getAllAuthStatuses(config);
|
|
72185
|
+
const agentsDir = resolveAgentsDir(config);
|
|
71919
72186
|
const agents = [];
|
|
71920
72187
|
for (const [name, agentConfig] of Object.entries(config.agents)) {
|
|
71921
72188
|
const status = statuses[name];
|
|
@@ -71923,9 +72190,10 @@ function handleGetAgents(config) {
|
|
|
71923
72190
|
const collection = getCollectionForAgent(name, config);
|
|
71924
72191
|
const resolved = resolveAgentConfig(config.defaults, config.profiles, agentConfig);
|
|
71925
72192
|
const primaryAccount = resolved.auth?.override ?? config.auth?.active;
|
|
72193
|
+
const active = status?.active === "active" ? "active" : agentBridgeAlive(agentsDir, name) ? "active" : status?.active ?? "unknown";
|
|
71926
72194
|
agents.push({
|
|
71927
72195
|
name,
|
|
71928
|
-
active
|
|
72196
|
+
active,
|
|
71929
72197
|
uptime: status?.uptime ?? null,
|
|
71930
72198
|
memory: status?.memory ?? null,
|
|
71931
72199
|
extends: agentConfig.extends ?? "default",
|
|
@@ -72183,7 +72451,7 @@ function inspectEnv(container, keys) {
|
|
|
72183
72451
|
} catch {}
|
|
72184
72452
|
return out;
|
|
72185
72453
|
}
|
|
72186
|
-
async function handleGetSystemHealth(home2) {
|
|
72454
|
+
async function handleGetSystemHealth(config, home2) {
|
|
72187
72455
|
const broker = { reachable: false };
|
|
72188
72456
|
try {
|
|
72189
72457
|
await withAuthBrokerClient(async (client2) => {
|
|
@@ -72204,23 +72472,25 @@ async function handleGetSystemHealth(home2) {
|
|
|
72204
72472
|
broker.error = err instanceof Error ? err.message : String(err);
|
|
72205
72473
|
}
|
|
72206
72474
|
}
|
|
72475
|
+
const memoryUrl = config?.memory?.config?.url ?? "http://127.0.0.1:18888/mcp/";
|
|
72476
|
+
let running = false;
|
|
72477
|
+
try {
|
|
72478
|
+
running = (await probeHindsight(memoryUrl)).ok;
|
|
72479
|
+
} catch {
|
|
72480
|
+
running = false;
|
|
72481
|
+
}
|
|
72207
72482
|
const containerStatus = getHindsightStatus();
|
|
72208
|
-
const
|
|
72209
|
-
const env2 = running ? inspectEnv("switchroom-hindsight", [
|
|
72483
|
+
const env2 = inspectEnv("switchroom-hindsight", [
|
|
72210
72484
|
"HINDSIGHT_API_LLM_MODEL",
|
|
72211
72485
|
"HINDSIGHT_API_LLM_PROVIDER",
|
|
72212
72486
|
"HINDSIGHT_API_MCP_STATELESS"
|
|
72213
|
-
])
|
|
72214
|
-
HINDSIGHT_API_LLM_MODEL: null,
|
|
72215
|
-
HINDSIGHT_API_LLM_PROVIDER: null,
|
|
72216
|
-
HINDSIGHT_API_MCP_STATELESS: null
|
|
72217
|
-
};
|
|
72487
|
+
]);
|
|
72218
72488
|
const statelessRaw = env2.HINDSIGHT_API_MCP_STATELESS;
|
|
72219
72489
|
const hindsight = {
|
|
72220
72490
|
containerStatus,
|
|
72221
72491
|
running,
|
|
72222
72492
|
model: env2.HINDSIGHT_API_LLM_MODEL,
|
|
72223
|
-
provider: env2.HINDSIGHT_API_LLM_PROVIDER,
|
|
72493
|
+
provider: env2.HINDSIGHT_API_LLM_PROVIDER ?? (config?.memory?.config?.provider ?? null),
|
|
72224
72494
|
mcpStateless: statelessRaw == null ? null : statelessRaw.toLowerCase() === "true"
|
|
72225
72495
|
};
|
|
72226
72496
|
const hostd = {
|
|
@@ -73331,7 +73601,7 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
|
|
|
73331
73601
|
return jsonResponse(result.subagents);
|
|
73332
73602
|
}
|
|
73333
73603
|
case "getSystemHealth":
|
|
73334
|
-
return (async () => jsonResponse(await handleGetSystemHealth()))();
|
|
73604
|
+
return (async () => jsonResponse(await handleGetSystemHealth(config)))();
|
|
73335
73605
|
case "getGoogleAccounts":
|
|
73336
73606
|
return (async () => jsonResponse(await handleGetGoogleAccounts(freshConfig())))();
|
|
73337
73607
|
case "getMicrosoftAccounts":
|
|
@@ -74467,7 +74737,7 @@ init_doctor();
|
|
|
74467
74737
|
init_source();
|
|
74468
74738
|
init_loader();
|
|
74469
74739
|
init_lifecycle();
|
|
74470
|
-
import { cpSync as cpSync2, existsSync as existsSync56, mkdirSync as mkdirSync31, readFileSync as readFileSync50, realpathSync as realpathSync5, rmSync as rmSync12, statSync as
|
|
74740
|
+
import { cpSync as cpSync2, existsSync as existsSync56, mkdirSync as mkdirSync31, readFileSync as readFileSync50, realpathSync as realpathSync5, rmSync as rmSync12, statSync as statSync25 } from "node:fs";
|
|
74471
74741
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
74472
74742
|
import { join as join57, dirname as dirname13, resolve as resolve33 } from "node:path";
|
|
74473
74743
|
import { homedir as homedir34 } from "node:os";
|
|
@@ -74738,7 +75008,7 @@ function defaultStatusProbe(composePath) {
|
|
|
74738
75008
|
} catch {}
|
|
74739
75009
|
if (scriptPath) {
|
|
74740
75010
|
try {
|
|
74741
|
-
cliBuiltAt = new Date(
|
|
75011
|
+
cliBuiltAt = new Date(statSync25(scriptPath).mtimeMs).toISOString();
|
|
74742
75012
|
} catch {}
|
|
74743
75013
|
let dir = dirname13(scriptPath);
|
|
74744
75014
|
for (let i = 0;i < 8; i++) {
|
|
@@ -75248,7 +75518,7 @@ import {
|
|
|
75248
75518
|
readdirSync as readdirSync21,
|
|
75249
75519
|
readFileSync as readFileSync52,
|
|
75250
75520
|
renameSync as renameSync12,
|
|
75251
|
-
statSync as
|
|
75521
|
+
statSync as statSync26,
|
|
75252
75522
|
unlinkSync as unlinkSync11,
|
|
75253
75523
|
writeFileSync as writeFileSync27,
|
|
75254
75524
|
writeSync as writeSync7
|
|
@@ -75822,7 +76092,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
75822
76092
|
continue;
|
|
75823
76093
|
const tmpPath = join59(stateDir, entry);
|
|
75824
76094
|
try {
|
|
75825
|
-
const stat =
|
|
76095
|
+
const stat = statSync26(tmpPath);
|
|
75826
76096
|
if (stat.mtimeMs < cutoff) {
|
|
75827
76097
|
unlinkSync11(tmpPath);
|
|
75828
76098
|
}
|
|
@@ -77387,7 +77657,7 @@ function registerSoulCommand(program3) {
|
|
|
77387
77657
|
// src/cli/debug.ts
|
|
77388
77658
|
init_helpers();
|
|
77389
77659
|
init_loader();
|
|
77390
|
-
import { existsSync as existsSync64, readFileSync as readFileSync56, readdirSync as readdirSync22, statSync as
|
|
77660
|
+
import { existsSync as existsSync64, readFileSync as readFileSync56, readdirSync as readdirSync22, statSync as statSync27 } from "node:fs";
|
|
77391
77661
|
import { resolve as resolve40, join as join64 } from "node:path";
|
|
77392
77662
|
import { createHash as createHash13 } from "node:crypto";
|
|
77393
77663
|
init_merge();
|
|
@@ -77426,7 +77696,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
|
77426
77696
|
const transcriptPath = join64(projectPath, "transcript.jsonl");
|
|
77427
77697
|
if (!existsSync64(transcriptPath))
|
|
77428
77698
|
continue;
|
|
77429
|
-
const stat3 =
|
|
77699
|
+
const stat3 = statSync27(transcriptPath);
|
|
77430
77700
|
if (!latest || stat3.mtimeMs > latest.mtime) {
|
|
77431
77701
|
latest = { path: transcriptPath, mtime: stat3.mtimeMs };
|
|
77432
77702
|
}
|
|
@@ -78764,6 +79034,340 @@ function registerNotionMcpLauncherCommand(program3) {
|
|
|
78764
79034
|
});
|
|
78765
79035
|
}
|
|
78766
79036
|
|
|
79037
|
+
// src/cli/deliver-file.ts
|
|
79038
|
+
init_client2();
|
|
79039
|
+
import { readFileSync as readFileSync58, statSync as statSync28 } from "node:fs";
|
|
79040
|
+
import { basename as basename7 } from "node:path";
|
|
79041
|
+
|
|
79042
|
+
// src/delivery/onedrive.ts
|
|
79043
|
+
import { basename as basename5 } from "node:path";
|
|
79044
|
+
var GRAPH = "https://graph.microsoft.com/v1.0";
|
|
79045
|
+
var ONEDRIVE_INLINE_MAX_BYTES = 4 * 1024 * 1024;
|
|
79046
|
+
function authHeaders(token) {
|
|
79047
|
+
return { Authorization: `Bearer ${token}`, Accept: "application/json" };
|
|
79048
|
+
}
|
|
79049
|
+
async function readBody(resp) {
|
|
79050
|
+
try {
|
|
79051
|
+
const t = await resp.text();
|
|
79052
|
+
return t.length > 300 ? `${t.slice(0, 300)}\u2026` : t;
|
|
79053
|
+
} catch {
|
|
79054
|
+
return "";
|
|
79055
|
+
}
|
|
79056
|
+
}
|
|
79057
|
+
async function ensureFolder(deps, parentPath, name) {
|
|
79058
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79059
|
+
const childPath = `${parentPath}/${name}`;
|
|
79060
|
+
const getUrl = `${GRAPH}/me/drive/root:${encodeURI(childPath)}`;
|
|
79061
|
+
const got = await f(getUrl, { headers: authHeaders(deps.accessToken) });
|
|
79062
|
+
if (got.ok) {
|
|
79063
|
+
return await got.json();
|
|
79064
|
+
}
|
|
79065
|
+
if (got.status !== 404) {
|
|
79066
|
+
throw new Error(`OneDrive folder lookup failed: HTTP ${got.status} \u2014 ${await readBody(got)}`);
|
|
79067
|
+
}
|
|
79068
|
+
const createUrl = parentPath === "" ? `${GRAPH}/me/drive/root/children` : `${GRAPH}/me/drive/root:${encodeURI(parentPath)}:/children`;
|
|
79069
|
+
const created = await f(createUrl, {
|
|
79070
|
+
method: "POST",
|
|
79071
|
+
headers: { ...authHeaders(deps.accessToken), "Content-Type": "application/json" },
|
|
79072
|
+
body: JSON.stringify({
|
|
79073
|
+
name,
|
|
79074
|
+
folder: {},
|
|
79075
|
+
"@microsoft.graph.conflictBehavior": "fail"
|
|
79076
|
+
})
|
|
79077
|
+
});
|
|
79078
|
+
if (created.ok) {
|
|
79079
|
+
return await created.json();
|
|
79080
|
+
}
|
|
79081
|
+
if (created.status === 409) {
|
|
79082
|
+
const reget = await f(getUrl, { headers: authHeaders(deps.accessToken) });
|
|
79083
|
+
if (reget.ok)
|
|
79084
|
+
return await reget.json();
|
|
79085
|
+
}
|
|
79086
|
+
throw new Error(`OneDrive folder create failed: HTTP ${created.status} \u2014 ${await readBody(created)}`);
|
|
79087
|
+
}
|
|
79088
|
+
async function ensureSwitchroomFolder(deps, agentName) {
|
|
79089
|
+
await ensureFolder(deps, "", "Switchroom");
|
|
79090
|
+
return ensureFolder(deps, "/Switchroom", agentName);
|
|
79091
|
+
}
|
|
79092
|
+
async function uploadFile(deps, folderId, filename, bytes) {
|
|
79093
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79094
|
+
if (bytes.byteLength <= ONEDRIVE_INLINE_MAX_BYTES) {
|
|
79095
|
+
const url = `${GRAPH}/me/drive/items/${folderId}:/${encodeURIComponent(filename)}:/content`;
|
|
79096
|
+
const resp = await f(url, {
|
|
79097
|
+
method: "PUT",
|
|
79098
|
+
headers: { ...authHeaders(deps.accessToken), "Content-Type": "application/octet-stream" },
|
|
79099
|
+
body: bytes
|
|
79100
|
+
});
|
|
79101
|
+
if (!resp.ok) {
|
|
79102
|
+
throw new Error(`OneDrive upload failed: HTTP ${resp.status} \u2014 ${await readBody(resp)}`);
|
|
79103
|
+
}
|
|
79104
|
+
return await resp.json();
|
|
79105
|
+
}
|
|
79106
|
+
return uploadLargeFile(deps, folderId, filename, bytes);
|
|
79107
|
+
}
|
|
79108
|
+
async function uploadLargeFile(deps, folderId, filename, bytes) {
|
|
79109
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79110
|
+
const sessUrl = `${GRAPH}/me/drive/items/${folderId}:/${encodeURIComponent(filename)}:/createUploadSession`;
|
|
79111
|
+
const sess = await f(sessUrl, {
|
|
79112
|
+
method: "POST",
|
|
79113
|
+
headers: { ...authHeaders(deps.accessToken), "Content-Type": "application/json" },
|
|
79114
|
+
body: JSON.stringify({ item: { "@microsoft.graph.conflictBehavior": "replace" } })
|
|
79115
|
+
});
|
|
79116
|
+
if (!sess.ok) {
|
|
79117
|
+
throw new Error(`OneDrive upload-session failed: HTTP ${sess.status} \u2014 ${await readBody(sess)}`);
|
|
79118
|
+
}
|
|
79119
|
+
const { uploadUrl } = await sess.json();
|
|
79120
|
+
const CHUNK = 5 * 1024 * 1024;
|
|
79121
|
+
const total = bytes.byteLength;
|
|
79122
|
+
let lastItem = null;
|
|
79123
|
+
for (let start = 0;start < total; start += CHUNK) {
|
|
79124
|
+
const end = Math.min(start + CHUNK, total);
|
|
79125
|
+
const chunk2 = bytes.subarray(start, end);
|
|
79126
|
+
const put = await f(uploadUrl, {
|
|
79127
|
+
method: "PUT",
|
|
79128
|
+
headers: {
|
|
79129
|
+
"Content-Length": String(chunk2.byteLength),
|
|
79130
|
+
"Content-Range": `bytes ${start}-${end - 1}/${total}`
|
|
79131
|
+
},
|
|
79132
|
+
body: chunk2
|
|
79133
|
+
});
|
|
79134
|
+
if (put.status === 200 || put.status === 201) {
|
|
79135
|
+
lastItem = await put.json();
|
|
79136
|
+
} else if (put.status !== 202) {
|
|
79137
|
+
throw new Error(`OneDrive chunk upload failed: HTTP ${put.status} \u2014 ${await readBody(put)}`);
|
|
79138
|
+
}
|
|
79139
|
+
}
|
|
79140
|
+
if (!lastItem)
|
|
79141
|
+
throw new Error("OneDrive upload session completed without a final item");
|
|
79142
|
+
return lastItem;
|
|
79143
|
+
}
|
|
79144
|
+
async function createShareLink(deps, item, scopes = ["anonymous", "organization"]) {
|
|
79145
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79146
|
+
const url = `${GRAPH}/me/drive/items/${item.id}/createLink`;
|
|
79147
|
+
for (const scope of scopes) {
|
|
79148
|
+
const resp = await f(url, {
|
|
79149
|
+
method: "POST",
|
|
79150
|
+
headers: { ...authHeaders(deps.accessToken), "Content-Type": "application/json" },
|
|
79151
|
+
body: JSON.stringify({ type: "view", scope })
|
|
79152
|
+
});
|
|
79153
|
+
if (resp.ok) {
|
|
79154
|
+
const body = await resp.json();
|
|
79155
|
+
if (body.link?.webUrl)
|
|
79156
|
+
return body.link.webUrl;
|
|
79157
|
+
}
|
|
79158
|
+
}
|
|
79159
|
+
if (item.webUrl)
|
|
79160
|
+
return item.webUrl;
|
|
79161
|
+
throw new Error("OneDrive: could not create a share link and the item has no webUrl");
|
|
79162
|
+
}
|
|
79163
|
+
async function deliverToOneDrive(args) {
|
|
79164
|
+
const deps = { accessToken: args.accessToken, fetchImpl: args.fetchImpl };
|
|
79165
|
+
const folder = await ensureSwitchroomFolder(deps, args.agentName);
|
|
79166
|
+
const filename = basename5(args.localPath);
|
|
79167
|
+
const item = await uploadFile(deps, folder.id, filename, args.bytes);
|
|
79168
|
+
const link = await createShareLink(deps, item, args.linkScopes);
|
|
79169
|
+
return { itemId: item.id, link, folderPath: `Switchroom/${args.agentName}` };
|
|
79170
|
+
}
|
|
79171
|
+
|
|
79172
|
+
// src/delivery/gdrive.ts
|
|
79173
|
+
import { basename as basename6 } from "node:path";
|
|
79174
|
+
var DRIVE = "https://www.googleapis.com/drive/v3";
|
|
79175
|
+
var UPLOAD = "https://www.googleapis.com/upload/drive/v3";
|
|
79176
|
+
var FOLDER_MIME = "application/vnd.google-apps.folder";
|
|
79177
|
+
function authHeaders2(token) {
|
|
79178
|
+
return { Authorization: `Bearer ${token}`, Accept: "application/json" };
|
|
79179
|
+
}
|
|
79180
|
+
async function readBody2(resp) {
|
|
79181
|
+
try {
|
|
79182
|
+
const t = await resp.text();
|
|
79183
|
+
return t.length > 300 ? `${t.slice(0, 300)}\u2026` : t;
|
|
79184
|
+
} catch {
|
|
79185
|
+
return "";
|
|
79186
|
+
}
|
|
79187
|
+
}
|
|
79188
|
+
async function ensureFolder2(deps, name, parentId) {
|
|
79189
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79190
|
+
const safeName = name.replace(/'/g, "\\'");
|
|
79191
|
+
const q = `name='${safeName}' and mimeType='${FOLDER_MIME}' and '${parentId}' in parents and trashed=false`;
|
|
79192
|
+
const listUrl = `${DRIVE}/files?q=${encodeURIComponent(q)}&fields=files(id,name)&spaces=drive`;
|
|
79193
|
+
const list2 = await f(listUrl, { headers: authHeaders2(deps.accessToken) });
|
|
79194
|
+
if (!list2.ok) {
|
|
79195
|
+
throw new Error(`Drive folder lookup failed: HTTP ${list2.status} \u2014 ${await readBody2(list2)}`);
|
|
79196
|
+
}
|
|
79197
|
+
const found = await list2.json();
|
|
79198
|
+
if (found.files && found.files.length > 0)
|
|
79199
|
+
return found.files[0];
|
|
79200
|
+
const created = await f(`${DRIVE}/files?fields=id,name`, {
|
|
79201
|
+
method: "POST",
|
|
79202
|
+
headers: { ...authHeaders2(deps.accessToken), "Content-Type": "application/json" },
|
|
79203
|
+
body: JSON.stringify({ name, mimeType: FOLDER_MIME, parents: [parentId] })
|
|
79204
|
+
});
|
|
79205
|
+
if (!created.ok) {
|
|
79206
|
+
throw new Error(`Drive folder create failed: HTTP ${created.status} \u2014 ${await readBody2(created)}`);
|
|
79207
|
+
}
|
|
79208
|
+
return await created.json();
|
|
79209
|
+
}
|
|
79210
|
+
async function ensureSwitchroomFolder2(deps, agentName) {
|
|
79211
|
+
const top = await ensureFolder2(deps, "Switchroom", "root");
|
|
79212
|
+
return ensureFolder2(deps, agentName, top.id);
|
|
79213
|
+
}
|
|
79214
|
+
async function uploadFile2(deps, parentId, filename, bytes, mimeType = "application/octet-stream") {
|
|
79215
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79216
|
+
const boundary = "switchroom-deliver-boundary";
|
|
79217
|
+
const metadata = JSON.stringify({ name: filename, parents: [parentId] });
|
|
79218
|
+
const enc = new TextEncoder;
|
|
79219
|
+
const head = enc.encode(`--${boundary}\r
|
|
79220
|
+
Content-Type: application/json; charset=UTF-8\r
|
|
79221
|
+
\r
|
|
79222
|
+
${metadata}\r
|
|
79223
|
+
` + `--${boundary}\r
|
|
79224
|
+
Content-Type: ${mimeType}\r
|
|
79225
|
+
\r
|
|
79226
|
+
`);
|
|
79227
|
+
const tail = enc.encode(`\r
|
|
79228
|
+
--${boundary}--`);
|
|
79229
|
+
const body = new Uint8Array(head.length + bytes.length + tail.length);
|
|
79230
|
+
body.set(head, 0);
|
|
79231
|
+
body.set(bytes, head.length);
|
|
79232
|
+
body.set(tail, head.length + bytes.length);
|
|
79233
|
+
const resp = await f(`${UPLOAD}/files?uploadType=multipart&fields=id,name,webViewLink`, {
|
|
79234
|
+
method: "POST",
|
|
79235
|
+
headers: {
|
|
79236
|
+
Authorization: `Bearer ${deps.accessToken}`,
|
|
79237
|
+
"Content-Type": `multipart/related; boundary=${boundary}`
|
|
79238
|
+
},
|
|
79239
|
+
body
|
|
79240
|
+
});
|
|
79241
|
+
if (!resp.ok) {
|
|
79242
|
+
throw new Error(`Drive upload failed: HTTP ${resp.status} \u2014 ${await readBody2(resp)}`);
|
|
79243
|
+
}
|
|
79244
|
+
return await resp.json();
|
|
79245
|
+
}
|
|
79246
|
+
async function createShareLink2(deps, file, scopes = ["anyone"]) {
|
|
79247
|
+
const f = deps.fetchImpl ?? fetch;
|
|
79248
|
+
for (const type of scopes) {
|
|
79249
|
+
const resp = await f(`${DRIVE}/files/${file.id}/permissions`, {
|
|
79250
|
+
method: "POST",
|
|
79251
|
+
headers: { ...authHeaders2(deps.accessToken), "Content-Type": "application/json" },
|
|
79252
|
+
body: JSON.stringify(type === "domain" ? { role: "reader", type: "domain" } : { role: "reader", type: "anyone" })
|
|
79253
|
+
});
|
|
79254
|
+
if (resp.ok)
|
|
79255
|
+
break;
|
|
79256
|
+
}
|
|
79257
|
+
if (file.webViewLink)
|
|
79258
|
+
return file.webViewLink;
|
|
79259
|
+
const meta = await f(`${DRIVE}/files/${file.id}?fields=webViewLink`, {
|
|
79260
|
+
headers: authHeaders2(deps.accessToken)
|
|
79261
|
+
});
|
|
79262
|
+
if (meta.ok) {
|
|
79263
|
+
const j = await meta.json();
|
|
79264
|
+
if (j.webViewLink)
|
|
79265
|
+
return j.webViewLink;
|
|
79266
|
+
}
|
|
79267
|
+
throw new Error("Drive: could not resolve a webViewLink for the uploaded file");
|
|
79268
|
+
}
|
|
79269
|
+
async function deliverToGoogleDrive(args) {
|
|
79270
|
+
const deps = { accessToken: args.accessToken, fetchImpl: args.fetchImpl };
|
|
79271
|
+
const folder = await ensureSwitchroomFolder2(deps, args.agentName);
|
|
79272
|
+
const filename = basename6(args.localPath);
|
|
79273
|
+
const file = await uploadFile2(deps, folder.id, filename, args.bytes);
|
|
79274
|
+
const link = await createShareLink2(deps, file, args.linkScopes);
|
|
79275
|
+
return { itemId: file.id, link, folderPath: `Switchroom/${args.agentName}` };
|
|
79276
|
+
}
|
|
79277
|
+
|
|
79278
|
+
// src/cli/deliver-file.ts
|
|
79279
|
+
function resolveGoogleLinkScopes(env2 = process.env) {
|
|
79280
|
+
const raw = (env2.SWITCHROOM_DELIVER_LINK_SCOPE ?? "").trim().toLowerCase();
|
|
79281
|
+
if (raw === "organization")
|
|
79282
|
+
return ["domain"];
|
|
79283
|
+
return ["anyone"];
|
|
79284
|
+
}
|
|
79285
|
+
function resolveLinkScopes(env2 = process.env) {
|
|
79286
|
+
const raw = (env2.SWITCHROOM_DELIVER_LINK_SCOPE ?? "").trim().toLowerCase();
|
|
79287
|
+
if (raw === "organization")
|
|
79288
|
+
return ["organization"];
|
|
79289
|
+
if (raw === "anonymous")
|
|
79290
|
+
return ["anonymous"];
|
|
79291
|
+
return ["anonymous", "organization"];
|
|
79292
|
+
}
|
|
79293
|
+
function safeAgentName(name) {
|
|
79294
|
+
const n = (name ?? "").trim();
|
|
79295
|
+
return /^[a-z0-9][a-z0-9_-]{0,50}$/.test(n) ? n : "agent";
|
|
79296
|
+
}
|
|
79297
|
+
async function brokerToken(provider) {
|
|
79298
|
+
const client2 = new AuthBrokerClient;
|
|
79299
|
+
try {
|
|
79300
|
+
const data = await client2.getCredentials(provider);
|
|
79301
|
+
const creds = data.credentials;
|
|
79302
|
+
const token = provider === "microsoft" ? creds?.microsoftOauth?.accessToken : creds?.googleOauth?.accessToken;
|
|
79303
|
+
return token ?? null;
|
|
79304
|
+
} catch {
|
|
79305
|
+
return null;
|
|
79306
|
+
} finally {
|
|
79307
|
+
await client2.close().catch(() => {});
|
|
79308
|
+
}
|
|
79309
|
+
}
|
|
79310
|
+
async function defaultResolveProvider() {
|
|
79311
|
+
const ms = await brokerToken("microsoft");
|
|
79312
|
+
if (ms) {
|
|
79313
|
+
return {
|
|
79314
|
+
name: "OneDrive",
|
|
79315
|
+
deliver: (a) => deliverToOneDrive({ ...a, accessToken: ms, linkScopes: resolveLinkScopes() })
|
|
79316
|
+
};
|
|
79317
|
+
}
|
|
79318
|
+
const g = await brokerToken("google");
|
|
79319
|
+
if (g) {
|
|
79320
|
+
return {
|
|
79321
|
+
name: "Google Drive",
|
|
79322
|
+
deliver: (a) => deliverToGoogleDrive({ ...a, accessToken: g, linkScopes: resolveGoogleLinkScopes() })
|
|
79323
|
+
};
|
|
79324
|
+
}
|
|
79325
|
+
return null;
|
|
79326
|
+
}
|
|
79327
|
+
async function runDeliverFile(localPath, deps = {}) {
|
|
79328
|
+
const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
|
|
79329
|
+
const sizeOf = deps.fileSize ?? ((p) => statSync28(p).size);
|
|
79330
|
+
const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync58(p)));
|
|
79331
|
+
const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
|
|
79332
|
+
let size;
|
|
79333
|
+
try {
|
|
79334
|
+
size = sizeOf(localPath);
|
|
79335
|
+
} catch {
|
|
79336
|
+
return { ok: false, error: `file not found: ${localPath}` };
|
|
79337
|
+
}
|
|
79338
|
+
if (size === 0) {
|
|
79339
|
+
return { ok: false, error: `file is empty: ${localPath}` };
|
|
79340
|
+
}
|
|
79341
|
+
const provider = await resolveProvider();
|
|
79342
|
+
if (!provider) {
|
|
79343
|
+
return {
|
|
79344
|
+
ok: false,
|
|
79345
|
+
error: `no connected drive for delivery. Connect a Microsoft or Google ` + `account from the dashboard, or send the file directly with the ` + `reply tool (files: ["${localPath}"]) for files under 50MB.`
|
|
79346
|
+
};
|
|
79347
|
+
}
|
|
79348
|
+
try {
|
|
79349
|
+
const bytes = read(localPath);
|
|
79350
|
+
const out = await provider.deliver({ agentName, localPath, bytes });
|
|
79351
|
+
return { ok: true, provider: provider.name, link: out.link, folderPath: out.folderPath, filename: basename7(localPath) };
|
|
79352
|
+
} catch (err) {
|
|
79353
|
+
return { ok: false, provider: provider.name, error: `upload failed: ${err.message}` };
|
|
79354
|
+
}
|
|
79355
|
+
}
|
|
79356
|
+
function registerDeliverFileCommand(program3) {
|
|
79357
|
+
program3.command("deliver-file").description("Deliver a file you produced to the user: upload it to their Switchroom/<agent>/ folder on the connected drive and print a shareable link. Reply with that link \u2014 never a local container path.").argument("<path>", "absolute local path of the file to deliver").action(async (path7) => {
|
|
79358
|
+
const res = await runDeliverFile(path7);
|
|
79359
|
+
if (res.ok) {
|
|
79360
|
+
process.stdout.write(`Delivered ${res.filename} to the user's ${res.provider} \u2192 ${res.folderPath}/
|
|
79361
|
+
` + `Share link (reply with this): ${res.link}
|
|
79362
|
+
`);
|
|
79363
|
+
return;
|
|
79364
|
+
}
|
|
79365
|
+
process.stderr.write(`deliver-file: ${res.error}
|
|
79366
|
+
`);
|
|
79367
|
+
process.exitCode = 1;
|
|
79368
|
+
});
|
|
79369
|
+
}
|
|
79370
|
+
|
|
78767
79371
|
// src/cli/notion.ts
|
|
78768
79372
|
init_loader();
|
|
78769
79373
|
|
|
@@ -79013,7 +79617,7 @@ async function fetchToken(vaultKey) {
|
|
|
79013
79617
|
|
|
79014
79618
|
// src/cli/apply.ts
|
|
79015
79619
|
init_source();
|
|
79016
|
-
import { accessSync as accessSync3, chownSync as chownSync4, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync73, mkdirSync as mkdirSync41, readFileSync as
|
|
79620
|
+
import { accessSync as accessSync3, chownSync as chownSync4, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync73, mkdirSync as mkdirSync41, readFileSync as readFileSync60, readdirSync as readdirSync26, renameSync as renameSync14, writeFileSync as writeFileSync36 } from "node:fs";
|
|
79017
79621
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
79018
79622
|
import { spawnSync as childSpawnSync } from "node:child_process";
|
|
79019
79623
|
import readline from "node:readline";
|
|
@@ -79410,7 +80014,7 @@ init_loader();
|
|
|
79410
80014
|
init_loader();
|
|
79411
80015
|
|
|
79412
80016
|
// src/cli/update-prompt-hook.ts
|
|
79413
|
-
import { existsSync as existsSync70, readFileSync as
|
|
80017
|
+
import { existsSync as existsSync70, readFileSync as readFileSync59, writeFileSync as writeFileSync35, chmodSync as chmodSync10, mkdirSync as mkdirSync40 } from "node:fs";
|
|
79414
80018
|
import { join as join69 } from "node:path";
|
|
79415
80019
|
var HOOK_FILENAME = "update-card-on-prompt.sh";
|
|
79416
80020
|
function updatePromptHookScript() {
|
|
@@ -79482,7 +80086,7 @@ function installUpdatePromptHook(agentDir) {
|
|
|
79482
80086
|
const scriptPath = join69(hooksDir, HOOK_FILENAME);
|
|
79483
80087
|
const desired = updatePromptHookScript();
|
|
79484
80088
|
let installed = false;
|
|
79485
|
-
const existing = existsSync70(scriptPath) ?
|
|
80089
|
+
const existing = existsSync70(scriptPath) ? readFileSync59(scriptPath, "utf-8") : "";
|
|
79486
80090
|
if (existing !== desired) {
|
|
79487
80091
|
writeFileSync35(scriptPath, desired, { mode: 493 });
|
|
79488
80092
|
chmodSync10(scriptPath, 493);
|
|
@@ -79496,7 +80100,7 @@ function installUpdatePromptHook(agentDir) {
|
|
|
79496
80100
|
if (!existsSync70(settingsPath)) {
|
|
79497
80101
|
return { scriptPath, settingsPath, installed };
|
|
79498
80102
|
}
|
|
79499
|
-
const raw =
|
|
80103
|
+
const raw = readFileSync59(settingsPath, "utf-8");
|
|
79500
80104
|
let parsed;
|
|
79501
80105
|
try {
|
|
79502
80106
|
parsed = JSON.parse(raw);
|
|
@@ -79616,7 +80220,7 @@ import {
|
|
|
79616
80220
|
lstatSync as lstatSync7,
|
|
79617
80221
|
readdirSync as readdirSync25,
|
|
79618
80222
|
realpathSync as realpathSync6,
|
|
79619
|
-
statSync as
|
|
80223
|
+
statSync as statSync29
|
|
79620
80224
|
} from "node:fs";
|
|
79621
80225
|
import { join as join71 } from "node:path";
|
|
79622
80226
|
function resolveOperatorUid() {
|
|
@@ -79656,7 +80260,7 @@ function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
|
|
|
79656
80260
|
});
|
|
79657
80261
|
const isDir = deps.isDir ?? ((p) => {
|
|
79658
80262
|
try {
|
|
79659
|
-
return
|
|
80263
|
+
return statSync29(p).isDirectory();
|
|
79660
80264
|
} catch {
|
|
79661
80265
|
return false;
|
|
79662
80266
|
}
|
|
@@ -79790,7 +80394,7 @@ async function ensureHostMountSources(config) {
|
|
|
79790
80394
|
await mkdir(fleetDir, { recursive: true });
|
|
79791
80395
|
const invariantsPath = join72(fleetDir, "switchroom-invariants.md");
|
|
79792
80396
|
const invariantsCanonical = renderFleetInvariants();
|
|
79793
|
-
const invariantsCurrent = existsSync73(invariantsPath) ?
|
|
80397
|
+
const invariantsCurrent = existsSync73(invariantsPath) ? readFileSync60(invariantsPath, "utf-8") : null;
|
|
79794
80398
|
if (invariantsCurrent !== invariantsCanonical) {
|
|
79795
80399
|
writeFileSync36(invariantsPath, invariantsCanonical, { mode: 420 });
|
|
79796
80400
|
}
|
|
@@ -80327,7 +80931,7 @@ function runRedactStdin() {
|
|
|
80327
80931
|
}
|
|
80328
80932
|
|
|
80329
80933
|
// src/cli/status-ask.ts
|
|
80330
|
-
import { readFileSync as
|
|
80934
|
+
import { readFileSync as readFileSync61, existsSync as existsSync74, readdirSync as readdirSync27 } from "node:fs";
|
|
80331
80935
|
import { join as join73 } from "node:path";
|
|
80332
80936
|
import { homedir as homedir42 } from "node:os";
|
|
80333
80937
|
|
|
@@ -80603,7 +81207,7 @@ function runReport(opts) {
|
|
|
80603
81207
|
for (const src of sources) {
|
|
80604
81208
|
let content;
|
|
80605
81209
|
try {
|
|
80606
|
-
content =
|
|
81210
|
+
content = readFileSync61(src.path, "utf-8");
|
|
80607
81211
|
} catch (err) {
|
|
80608
81212
|
process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
|
|
80609
81213
|
`);
|
|
@@ -80704,7 +81308,7 @@ import {
|
|
|
80704
81308
|
existsSync as existsSync75,
|
|
80705
81309
|
mkdirSync as mkdirSync42,
|
|
80706
81310
|
appendFileSync as appendFileSync4,
|
|
80707
|
-
readFileSync as
|
|
81311
|
+
readFileSync as readFileSync62
|
|
80708
81312
|
} from "node:fs";
|
|
80709
81313
|
var AUDIT_ROOT = join74(homedir43(), ".switchroom", "audit");
|
|
80710
81314
|
function auditPathFor(agent) {
|
|
@@ -80799,7 +81403,7 @@ function readAuditTail(agent, limit, opts = {}) {
|
|
|
80799
81403
|
return [];
|
|
80800
81404
|
let raw;
|
|
80801
81405
|
try {
|
|
80802
|
-
raw =
|
|
81406
|
+
raw = readFileSync62(path8, "utf-8");
|
|
80803
81407
|
} catch {
|
|
80804
81408
|
return [];
|
|
80805
81409
|
}
|
|
@@ -80960,9 +81564,9 @@ import {
|
|
|
80960
81564
|
mkdirSync as mkdirSync43,
|
|
80961
81565
|
openSync as openSync13,
|
|
80962
81566
|
readdirSync as readdirSync28,
|
|
80963
|
-
readFileSync as
|
|
81567
|
+
readFileSync as readFileSync63,
|
|
80964
81568
|
renameSync as renameSync15,
|
|
80965
|
-
statSync as
|
|
81569
|
+
statSync as statSync30,
|
|
80966
81570
|
unlinkSync as unlinkSync14,
|
|
80967
81571
|
writeSync as writeSync8
|
|
80968
81572
|
} from "node:fs";
|
|
@@ -81006,7 +81610,7 @@ function withAgentLock(paths, fn) {
|
|
|
81006
81610
|
if (e.code !== "EEXIST")
|
|
81007
81611
|
throw err;
|
|
81008
81612
|
try {
|
|
81009
|
-
const age = Date.now() -
|
|
81613
|
+
const age = Date.now() - statSync30(paths.lockPath).mtimeMs;
|
|
81010
81614
|
if (age > 30000) {
|
|
81011
81615
|
unlinkSync14(paths.lockPath);
|
|
81012
81616
|
continue;
|
|
@@ -81084,7 +81688,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
|
|
|
81084
81688
|
continue;
|
|
81085
81689
|
const full = join75(paths.skillsDir, name);
|
|
81086
81690
|
try {
|
|
81087
|
-
const raw =
|
|
81691
|
+
const raw = readFileSync63(full, "utf-8");
|
|
81088
81692
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
81089
81693
|
out.push({ slug, path: full, raw });
|
|
81090
81694
|
} catch {}
|
|
@@ -81111,7 +81715,7 @@ function listOverlayEntries(agent, opts = {}) {
|
|
|
81111
81715
|
continue;
|
|
81112
81716
|
const full = join75(paths.scheduleDir, name);
|
|
81113
81717
|
try {
|
|
81114
|
-
const raw =
|
|
81718
|
+
const raw = readFileSync63(full, "utf-8");
|
|
81115
81719
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
81116
81720
|
out.push({ slug, path: full, raw });
|
|
81117
81721
|
} catch {}
|
|
@@ -81259,7 +81863,7 @@ import {
|
|
|
81259
81863
|
mkdirSync as mkdirSync44,
|
|
81260
81864
|
openSync as openSync14,
|
|
81261
81865
|
readdirSync as readdirSync29,
|
|
81262
|
-
readFileSync as
|
|
81866
|
+
readFileSync as readFileSync64,
|
|
81263
81867
|
renameSync as renameSync16,
|
|
81264
81868
|
unlinkSync as unlinkSync15,
|
|
81265
81869
|
writeFileSync as writeFileSync37,
|
|
@@ -81323,7 +81927,7 @@ function listPendingScheduleEntries(agent, opts = {}) {
|
|
|
81323
81927
|
if (!existsSync77(yamlPath))
|
|
81324
81928
|
continue;
|
|
81325
81929
|
try {
|
|
81326
|
-
const meta = JSON.parse(
|
|
81930
|
+
const meta = JSON.parse(readFileSync64(metaPath, "utf-8"));
|
|
81327
81931
|
if (meta?.v !== 1 || typeof meta.stage_id !== "string")
|
|
81328
81932
|
continue;
|
|
81329
81933
|
out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
|
|
@@ -81362,7 +81966,7 @@ function denyPendingScheduleEntry(opts) {
|
|
|
81362
81966
|
|
|
81363
81967
|
// src/cli/agent-config-write.ts
|
|
81364
81968
|
init_protocol3();
|
|
81365
|
-
import { existsSync as existsSync78, readFileSync as
|
|
81969
|
+
import { existsSync as existsSync78, readFileSync as readFileSync65 } from "node:fs";
|
|
81366
81970
|
var MAX_ENTRIES_PER_AGENT = 20;
|
|
81367
81971
|
var MIN_CRON_INTERVAL_MIN = 5;
|
|
81368
81972
|
function extractCronSmallestGapMin(expr) {
|
|
@@ -81649,7 +82253,7 @@ function scheduleRemove(opts) {
|
|
|
81649
82253
|
let priorContent = null;
|
|
81650
82254
|
try {
|
|
81651
82255
|
if (existsSync78(match.path))
|
|
81652
|
-
priorContent =
|
|
82256
|
+
priorContent = readFileSync65(match.path, "utf-8");
|
|
81653
82257
|
} catch {}
|
|
81654
82258
|
deleteOverlayEntry(agent, match.slug, { root: opts.root });
|
|
81655
82259
|
const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
|
|
@@ -82089,12 +82693,12 @@ import {
|
|
|
82089
82693
|
mkdirSync as mkdirSync45,
|
|
82090
82694
|
mkdtempSync as mkdtempSync5,
|
|
82091
82695
|
openSync as openSync15,
|
|
82092
|
-
readFileSync as
|
|
82696
|
+
readFileSync as readFileSync66,
|
|
82093
82697
|
readdirSync as readdirSync30,
|
|
82094
82698
|
realpathSync as realpathSync7,
|
|
82095
82699
|
renameSync as renameSync17,
|
|
82096
82700
|
rmSync as rmSync16,
|
|
82097
|
-
statSync as
|
|
82701
|
+
statSync as statSync31,
|
|
82098
82702
|
writeFileSync as writeFileSync38
|
|
82099
82703
|
} from "node:fs";
|
|
82100
82704
|
import { tmpdir as tmpdir5, homedir as homedir44 } from "node:os";
|
|
@@ -82324,7 +82928,7 @@ function isTarballPath(p) {
|
|
|
82324
82928
|
}
|
|
82325
82929
|
function loadFromDir(dir) {
|
|
82326
82930
|
const abs = realpathSync7(dir);
|
|
82327
|
-
if (!
|
|
82931
|
+
if (!statSync31(abs).isDirectory()) {
|
|
82328
82932
|
fail2(`--from path is not a directory: ${dir}`);
|
|
82329
82933
|
}
|
|
82330
82934
|
const files = {};
|
|
@@ -82341,7 +82945,7 @@ function loadFromDir(dir) {
|
|
|
82341
82945
|
continue;
|
|
82342
82946
|
}
|
|
82343
82947
|
if (ent.isFile()) {
|
|
82344
|
-
const buf =
|
|
82948
|
+
const buf = readFileSync66(full);
|
|
82345
82949
|
files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
|
|
82346
82950
|
}
|
|
82347
82951
|
}
|
|
@@ -82390,7 +82994,7 @@ function loadFromTarball(tarPath) {
|
|
|
82390
82994
|
}
|
|
82391
82995
|
}
|
|
82392
82996
|
function loadSingleFile(filePath) {
|
|
82393
|
-
const content =
|
|
82997
|
+
const content = readFileSync66(filePath, "utf-8");
|
|
82394
82998
|
return { "SKILL.md": content };
|
|
82395
82999
|
}
|
|
82396
83000
|
function loadFromStdin() {
|
|
@@ -82481,7 +83085,7 @@ function diffSummary(currentDir, files) {
|
|
|
82481
83085
|
if (ent.isDirectory()) {
|
|
82482
83086
|
walk2(full);
|
|
82483
83087
|
} else if (ent.isFile()) {
|
|
82484
|
-
currentFiles[rel.replace(/\\/g, "/")] =
|
|
83088
|
+
currentFiles[rel.replace(/\\/g, "/")] = readFileSync66(full, "utf-8");
|
|
82485
83089
|
}
|
|
82486
83090
|
}
|
|
82487
83091
|
};
|
|
@@ -82584,7 +83188,7 @@ function registerSkillCommand(program3) {
|
|
|
82584
83188
|
if (!existsSync80(fromPath)) {
|
|
82585
83189
|
fail2(`--from path does not exist: ${opts.from}`);
|
|
82586
83190
|
}
|
|
82587
|
-
const st =
|
|
83191
|
+
const st = statSync31(fromPath);
|
|
82588
83192
|
if (st.isDirectory()) {
|
|
82589
83193
|
files = loadFromDir(fromPath);
|
|
82590
83194
|
} else if (isTarballPath(fromPath)) {
|
|
@@ -82641,11 +83245,11 @@ import {
|
|
|
82641
83245
|
mkdirSync as mkdirSync46,
|
|
82642
83246
|
mkdtempSync as mkdtempSync6,
|
|
82643
83247
|
openSync as openSync16,
|
|
82644
|
-
readFileSync as
|
|
83248
|
+
readFileSync as readFileSync67,
|
|
82645
83249
|
readdirSync as readdirSync31,
|
|
82646
83250
|
renameSync as renameSync18,
|
|
82647
83251
|
rmSync as rmSync17,
|
|
82648
|
-
statSync as
|
|
83252
|
+
statSync as statSync32,
|
|
82649
83253
|
utimesSync,
|
|
82650
83254
|
writeFileSync as writeFileSync39
|
|
82651
83255
|
} from "node:fs";
|
|
@@ -82723,7 +83327,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
82723
83327
|
if (ent.isDirectory())
|
|
82724
83328
|
walk2(s, d);
|
|
82725
83329
|
else if (ent.isFile()) {
|
|
82726
|
-
writeFileSync39(d,
|
|
83330
|
+
writeFileSync39(d, readFileSync67(s));
|
|
82727
83331
|
}
|
|
82728
83332
|
}
|
|
82729
83333
|
};
|
|
@@ -82786,7 +83390,7 @@ function readStdinSync2() {
|
|
|
82786
83390
|
}
|
|
82787
83391
|
function loadFromDir2(dir) {
|
|
82788
83392
|
const abs = resolve47(dir);
|
|
82789
|
-
if (!
|
|
83393
|
+
if (!statSync32(abs).isDirectory()) {
|
|
82790
83394
|
fail3(`--from path is not a directory: ${dir}`);
|
|
82791
83395
|
}
|
|
82792
83396
|
const files = {};
|
|
@@ -82802,7 +83406,7 @@ function loadFromDir2(dir) {
|
|
|
82802
83406
|
}
|
|
82803
83407
|
if (ent.isFile()) {
|
|
82804
83408
|
const rel = relative3(abs, full).replace(/\\/g, "/");
|
|
82805
|
-
files[rel] =
|
|
83409
|
+
files[rel] = readFileSync67(full, "utf-8");
|
|
82806
83410
|
}
|
|
82807
83411
|
}
|
|
82808
83412
|
};
|
|
@@ -82872,7 +83476,7 @@ function sweepTrash(agentsRoot, agent) {
|
|
|
82872
83476
|
continue;
|
|
82873
83477
|
const entPath = join79(trash, ent.name);
|
|
82874
83478
|
try {
|
|
82875
|
-
const st =
|
|
83479
|
+
const st = statSync32(entPath);
|
|
82876
83480
|
if (now - st.mtimeMs > TRASH_TTL_MS) {
|
|
82877
83481
|
rmSync17(entPath, { recursive: true, force: true });
|
|
82878
83482
|
}
|
|
@@ -82983,12 +83587,12 @@ function loadFiles(opts) {
|
|
|
82983
83587
|
if (!existsSync81(p)) {
|
|
82984
83588
|
fail3(`--from path does not exist: ${opts.from}`);
|
|
82985
83589
|
}
|
|
82986
|
-
const st =
|
|
83590
|
+
const st = statSync32(p);
|
|
82987
83591
|
if (st.isDirectory()) {
|
|
82988
83592
|
return loadFromDir2(p);
|
|
82989
83593
|
}
|
|
82990
83594
|
if (p.endsWith(".md")) {
|
|
82991
|
-
return { "SKILL.md":
|
|
83595
|
+
return { "SKILL.md": readFileSync67(p, "utf-8") };
|
|
82992
83596
|
}
|
|
82993
83597
|
fail3(`--from must be a directory or a .md file. Got: ${opts.from}`);
|
|
82994
83598
|
}
|
|
@@ -83077,7 +83681,7 @@ function readSourceFiles(dir) {
|
|
|
83077
83681
|
fail3(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
|
|
83078
83682
|
}
|
|
83079
83683
|
} catch {}
|
|
83080
|
-
files[rel] =
|
|
83684
|
+
files[rel] = readFileSync67(full, "utf-8");
|
|
83081
83685
|
}
|
|
83082
83686
|
}
|
|
83083
83687
|
};
|
|
@@ -83204,7 +83808,7 @@ function listPersonalAction(opts) {
|
|
|
83204
83808
|
if (e.isFile()) {
|
|
83205
83809
|
fileCount += 1;
|
|
83206
83810
|
try {
|
|
83207
|
-
totalBytes +=
|
|
83811
|
+
totalBytes += statSync32(join79(sub, e.name)).size;
|
|
83208
83812
|
} catch {}
|
|
83209
83813
|
} else if (e.isDirectory()) {
|
|
83210
83814
|
walk2(join79(sub, e.name));
|
|
@@ -83246,7 +83850,7 @@ function registerSkillPersonalCommands(program3) {
|
|
|
83246
83850
|
// src/cli/skill-search.ts
|
|
83247
83851
|
init_helpers();
|
|
83248
83852
|
var import_yaml23 = __toESM(require_dist(), 1);
|
|
83249
|
-
import { existsSync as existsSync82, readdirSync as readdirSync32, readFileSync as
|
|
83853
|
+
import { existsSync as existsSync82, readdirSync as readdirSync32, readFileSync as readFileSync68, statSync as statSync33 } from "node:fs";
|
|
83250
83854
|
import { homedir as homedir46 } from "node:os";
|
|
83251
83855
|
import { join as join80, resolve as resolve48 } from "node:path";
|
|
83252
83856
|
var PERSONAL_PREFIX2 = "personal-";
|
|
@@ -83267,7 +83871,7 @@ function readSkillFrontmatter(skillDir) {
|
|
|
83267
83871
|
return null;
|
|
83268
83872
|
let content;
|
|
83269
83873
|
try {
|
|
83270
|
-
content =
|
|
83874
|
+
content = readFileSync68(mdPath, "utf-8");
|
|
83271
83875
|
} catch {
|
|
83272
83876
|
return null;
|
|
83273
83877
|
}
|
|
@@ -83297,7 +83901,7 @@ function readSkillFrontmatter(skillDir) {
|
|
|
83297
83901
|
function statSkillMd(skillDir) {
|
|
83298
83902
|
const mdPath = join80(skillDir, "SKILL.md");
|
|
83299
83903
|
try {
|
|
83300
|
-
const st =
|
|
83904
|
+
const st = statSync33(mdPath);
|
|
83301
83905
|
return { size: st.size, mtime: st.mtime.toISOString() };
|
|
83302
83906
|
} catch {
|
|
83303
83907
|
return null;
|
|
@@ -83321,7 +83925,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
|
83321
83925
|
continue;
|
|
83322
83926
|
const dirPath = join80(skillsDir, ent);
|
|
83323
83927
|
try {
|
|
83324
|
-
if (!
|
|
83928
|
+
if (!statSync33(dirPath).isDirectory())
|
|
83325
83929
|
continue;
|
|
83326
83930
|
} catch {
|
|
83327
83931
|
continue;
|
|
@@ -83361,7 +83965,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
|
|
|
83361
83965
|
continue;
|
|
83362
83966
|
const dirPath = join80(sharedRoot, ent);
|
|
83363
83967
|
try {
|
|
83364
|
-
if (!
|
|
83968
|
+
if (!statSync33(dirPath).isDirectory())
|
|
83365
83969
|
continue;
|
|
83366
83970
|
} catch {
|
|
83367
83971
|
continue;
|
|
@@ -83397,7 +84001,7 @@ function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
|
|
|
83397
84001
|
continue;
|
|
83398
84002
|
const dirPath = join80(bundledRoot, ent);
|
|
83399
84003
|
try {
|
|
83400
|
-
if (!
|
|
84004
|
+
if (!statSync33(dirPath).isDirectory())
|
|
83401
84005
|
continue;
|
|
83402
84006
|
} catch {
|
|
83403
84007
|
continue;
|
|
@@ -83539,7 +84143,7 @@ function registerHostdMcpCommand(program3) {
|
|
|
83539
84143
|
// src/cli/hostd.ts
|
|
83540
84144
|
init_source();
|
|
83541
84145
|
init_helpers();
|
|
83542
|
-
import { existsSync as existsSync84, mkdirSync as mkdirSync47, readdirSync as readdirSync33, readFileSync as
|
|
84146
|
+
import { existsSync as existsSync84, mkdirSync as mkdirSync47, readdirSync as readdirSync33, readFileSync as readFileSync70, writeFileSync as writeFileSync40, statSync as statSync34, copyFileSync as copyFileSync12 } from "node:fs";
|
|
83543
84147
|
import { homedir as homedir47 } from "node:os";
|
|
83544
84148
|
import { join as join81 } from "node:path";
|
|
83545
84149
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
@@ -83747,7 +84351,7 @@ function doStatus() {
|
|
|
83747
84351
|
continue;
|
|
83748
84352
|
const sockPath = join81(dir, name, "sock");
|
|
83749
84353
|
if (existsSync84(sockPath)) {
|
|
83750
|
-
const st =
|
|
84354
|
+
const st = statSync34(sockPath);
|
|
83751
84355
|
if ((st.mode & 61440) === 49152) {
|
|
83752
84356
|
entries.push(`${name} \u2192 ${sockPath}`);
|
|
83753
84357
|
}
|
|
@@ -83794,7 +84398,7 @@ function registerHostdCommand(program3) {
|
|
|
83794
84398
|
The log is created when hostd handles its first privileged-verb request.`));
|
|
83795
84399
|
return;
|
|
83796
84400
|
}
|
|
83797
|
-
const raw =
|
|
84401
|
+
const raw = readFileSync70(logPath, "utf-8");
|
|
83798
84402
|
const limit = Math.max(1, parseInt(opts.tail ?? "50", 10) || 50);
|
|
83799
84403
|
const filters = {
|
|
83800
84404
|
agent: opts.agent,
|
|
@@ -84084,6 +84688,7 @@ registerDriveCommand(program3);
|
|
|
84084
84688
|
registerDriveMcpLauncherCommand(program3);
|
|
84085
84689
|
registerM365McpLauncherCommand(program3);
|
|
84086
84690
|
registerNotionMcpLauncherCommand(program3);
|
|
84691
|
+
registerDeliverFileCommand(program3);
|
|
84087
84692
|
registerNotionCommand(program3);
|
|
84088
84693
|
registerApplyCommand(program3);
|
|
84089
84694
|
registerSecretDetectCommand(program3);
|
package/package.json
CHANGED
|
@@ -52889,10 +52889,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
52889
52889
|
}
|
|
52890
52890
|
|
|
52891
52891
|
// ../src/build-info.ts
|
|
52892
|
-
var VERSION = "0.14.
|
|
52893
|
-
var COMMIT_SHA = "
|
|
52894
|
-
var COMMIT_DATE = "2026-06-
|
|
52895
|
-
var LATEST_PR =
|
|
52892
|
+
var VERSION = "0.14.88";
|
|
52893
|
+
var COMMIT_SHA = "b3c61552";
|
|
52894
|
+
var COMMIT_DATE = "2026-06-07T16:17:55Z";
|
|
52895
|
+
var LATEST_PR = 2229;
|
|
52896
52896
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
52897
52897
|
|
|
52898
52898
|
// gateway/boot-version.ts
|