switchroom 0.15.11 → 0.15.13
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/agent-scheduler/index.js +16 -0
- package/dist/auth-broker/index.js +16 -0
- package/dist/cli/notion-write-pretool.mjs +16 -0
- package/dist/cli/switchroom.js +356 -186
- package/dist/host-control/main.js +16 -0
- package/dist/vault/approvals/kernel-server.js +16 -0
- package/dist/vault/broker/server.js +16 -0
- package/package.json +1 -1
- package/profiles/_shared/agent-self-service.md.hbs +37 -0
- package/telegram-plugin/bridge/bridge.ts +55 -0
- package/telegram-plugin/dist/bridge/bridge.js +53 -0
- package/telegram-plugin/dist/gateway/gateway.js +628 -50
- package/telegram-plugin/dist/server.js +53 -0
- package/telegram-plugin/gateway/gateway.ts +130 -5
- package/telegram-plugin/gateway/linear-activity.ts +305 -0
- package/telegram-plugin/gateway/model-command.ts +13 -5
- package/telegram-plugin/scoped-approval.ts +253 -0
- package/telegram-plugin/tests/gateway-request-secret.test.ts +1 -1
- package/telegram-plugin/tests/linear-agent-activity.test.ts +124 -0
- package/telegram-plugin/tests/linear-create-issue.test.ts +211 -0
- package/telegram-plugin/tests/model-command.test.ts +40 -0
- package/telegram-plugin/tests/permission-verdict-resume-guard.test.ts +13 -0
- package/telegram-plugin/tests/scoped-approval.test.ts +254 -0
package/dist/cli/switchroom.js
CHANGED
|
@@ -13711,6 +13711,12 @@ var init_schema = __esm(() => {
|
|
|
13711
13711
|
}).optional().describe("Per-source rate limit for the webhook ingest path (#714). " + "Off by default \u2014 when this key is absent the handler skips " + "rate-limit checks entirely. Opt in by setting `rpm` to an " + "integer requests-per-minute (token bucket per (agent, source); " + "burst equal to rpm). When enabled, exceeding the limit returns " + "429 with Retry-After header; first throttle event per " + "(agent, source) per 60s window is written to " + "<agent>/telegram/issues.jsonl. " + "Cascades from defaults.channels.telegram.webhook_rate_limit."),
|
|
13712
13712
|
webhook_via_gateway: exports_external.boolean().optional().describe("Route verified webhook events to the agent's in-container gateway " + "over a peercred-gated UDS (<agent>/telegram/webhook.sock) instead " + "of having the host-side web receiver write the agent dir directly. " + "Required under the Docker runtime: the receiver runs as the host " + "operator UID and cannot write the per-agent-UID-owned agent dir " + "(EACCES 500) nor connect the gateway socket. When true the gateway " + "(running as the agent UID) becomes the sole writer of " + "webhook-events.jsonl + dedup/cooldown state and also fires " + "webhook_dispatch. Off by default for back-compat with host-runtime " + "installs. See docs/rfcs/webhook-via-gateway-socket.md."),
|
|
13713
13713
|
webhook_require_edge: exports_external.boolean().optional().describe("Cloudflare-only edge lock: require the X-Switchroom-Edge header " + "(injected by a Cloudflare Transform Rule on hooks.switchroom.ai) to " + "match the operator's edge secret at ~/.switchroom/webhook-edge-secret " + "before any HMAC verification; reject 403 otherwise. Proves the " + "request entered through our Cloudflare edge \u2014 the per-agent HMAC " + "alone can't (it proves body provenance, not network path). Stacks " + "on the GitHub-IP WAF + per-agent HMAC. Fail-closed: when required " + "but the secret file is missing/empty every request is rejected. Off " + "by default. See docs/rfcs/webhook-cloudflare-edge-lock.md."),
|
|
13714
|
+
linear_agent: exports_external.object({
|
|
13715
|
+
enabled: exports_external.boolean(),
|
|
13716
|
+
token: exports_external.string().describe("vault:<key> reference to the Linear OAuth app token (actor=app). " + "Resolved at runtime via the vault broker (canonically " + "vault:linear/<agent>/token). Never an inline literal."),
|
|
13717
|
+
workspace_id: exports_external.string().optional().describe("Optional Linear workspace (organization) id this agent is " + "installed into. Informational \u2014 used for setup hints and " + "multi-workspace disambiguation; the token already scopes the " + "app to its workspace."),
|
|
13718
|
+
default_team_id: exports_external.string().optional().describe("Optional Linear team id new captured issues file into when the " + "agent doesn't pass an explicit team_id. Unnecessary for a " + "single-team workspace (auto-resolved); set it only when the " + "workspace has multiple teams. Manage via " + "`switchroom linear-agent set-team <agent> <team>`.")
|
|
13719
|
+
}).optional().describe("Linear first-class agent integration (#2298). When enabled, the " + "agent appears in a Linear workspace as an app actor (own name/" + "avatar, @-mentionable, delegate-assignable). Linear AgentSessionEvent " + "webhooks (mention / delegation) wake the agent instantly via the " + "same gateway inject path as webhook_dispatch, tagged " + 'meta.source="linear" with the agent_session_id, and the agent ' + "responds with structured AgentActivity (thought/message/complete/" + "error) via the linear_agent_activity MCP tool. Builds the " + "session-lifecycle layer on top of the plain webhook_sources:[linear] " + "+ webhook_dispatch support (#2272). The OAuth app token is stored in " + "the vault and referenced here as vault:linear/<agent>/token; run " + "`switchroom linear-agent setup <agent>` to provision it. Off by " + "default \u2014 opt in per agent. Cascades from " + "defaults.channels.telegram.linear_agent."),
|
|
13714
13720
|
chat_id: exports_external.string().regex(/^-\d+$/, 'supergroup chat_id must be a negative integer as a string (e.g. "-1001234567890")').optional().describe("Per-agent supergroup ID \u2014 overrides fleet `telegram.forum_chat_id`. " + "When set, requires `default_topic_id`. Negative integer as string. " + "Forbidden when `dm_only: true`. See docs/rfcs/supergroup-mode.md."),
|
|
13715
13721
|
default_topic_id: exports_external.number().int().positive().optional().describe("Forum topic ID this agent's automated outbounds default to when " + "no more-specific alias resolves. Defaults to General (topic 1) when " + "`chat_id` is set and this is omitted \u2014 set it only to pin a different " + "fallback topic. " + "Telegram's General topic is `id=1` at MTProto but sends omit the " + "field \u2014 the outbound wrapper strips `message_thread_id === 1` " + "on send. Forbidden when `dm_only: true`."),
|
|
13716
13722
|
topic_aliases: exports_external.record(exports_external.string(), exports_external.number().int().positive()).optional().describe("Operator-friendly names for forum topic IDs (e.g. " + "`{ general: 1, planning: 17, cron: 23, admin: 31, alerts: 41 }`). " + "Referenced from per-cron `topic:` fields and the outbound router " + "for autonomous events (boot \u2192 alerts, hostd \u2192 admin, etc.). " + "Cascades per-key through defaults \u2192 profile \u2192 agent.")
|
|
@@ -14635,6 +14641,16 @@ function mergeAgentConfig(defaultsIn, agentIn) {
|
|
|
14635
14641
|
}
|
|
14636
14642
|
merged.reaction_dispatch = combined;
|
|
14637
14643
|
}
|
|
14644
|
+
const linearEnabled = merged.channels?.telegram?.linear_agent?.enabled === true;
|
|
14645
|
+
if (linearEnabled) {
|
|
14646
|
+
const rd = merged.reaction_dispatch;
|
|
14647
|
+
if (!rd || rd.emojis === undefined) {
|
|
14648
|
+
merged.reaction_dispatch = {
|
|
14649
|
+
enabled: rd?.enabled ?? true,
|
|
14650
|
+
emojis: ["\uD83D\uDC68\u200d\uD83D\uDCBB", "\uD83D\uDCCC"]
|
|
14651
|
+
};
|
|
14652
|
+
}
|
|
14653
|
+
}
|
|
14638
14654
|
if (defaults.resources || merged.resources) {
|
|
14639
14655
|
const d = defaults.resources ?? {};
|
|
14640
14656
|
const a = merged.resources ?? {};
|
|
@@ -29166,7 +29182,7 @@ var init_thinking_effort_risk = __esm(() => {
|
|
|
29166
29182
|
// src/manifest.ts
|
|
29167
29183
|
import {
|
|
29168
29184
|
existsSync as existsSync52,
|
|
29169
|
-
readFileSync as
|
|
29185
|
+
readFileSync as readFileSync48,
|
|
29170
29186
|
readdirSync as readdirSync19
|
|
29171
29187
|
} from "node:fs";
|
|
29172
29188
|
import { dirname as dirname12, join as join47 } from "node:path";
|
|
@@ -29188,7 +29204,7 @@ function loadManifest(manifestPath) {
|
|
|
29188
29204
|
}
|
|
29189
29205
|
let raw;
|
|
29190
29206
|
try {
|
|
29191
|
-
raw =
|
|
29207
|
+
raw = readFileSync48(path4, "utf-8");
|
|
29192
29208
|
} catch (err) {
|
|
29193
29209
|
throw new Error(`Failed to read manifest at ${path4}: ${err.message}`);
|
|
29194
29210
|
}
|
|
@@ -29253,7 +29269,7 @@ function probePlaywrightMcpVersion() {
|
|
|
29253
29269
|
const pkgPath = join47(npxCache, entry, "node_modules/@playwright/mcp/package.json");
|
|
29254
29270
|
if (existsSync52(pkgPath)) {
|
|
29255
29271
|
try {
|
|
29256
|
-
const pkg = JSON.parse(
|
|
29272
|
+
const pkg = JSON.parse(readFileSync48(pkgPath, "utf-8"));
|
|
29257
29273
|
if (pkg.version)
|
|
29258
29274
|
return pkg.version;
|
|
29259
29275
|
} catch {}
|
|
@@ -29488,7 +29504,7 @@ var init_doctor_memory = __esm(() => {
|
|
|
29488
29504
|
});
|
|
29489
29505
|
|
|
29490
29506
|
// src/cli/doctor-docker.ts
|
|
29491
|
-
import { readFileSync as
|
|
29507
|
+
import { readFileSync as readFileSync49 } from "node:fs";
|
|
29492
29508
|
function imageTagOf(ref) {
|
|
29493
29509
|
if (!ref)
|
|
29494
29510
|
return "<absent>";
|
|
@@ -29503,7 +29519,7 @@ function isDockerMode(opts) {
|
|
|
29503
29519
|
return true;
|
|
29504
29520
|
if (opts?.composePath) {
|
|
29505
29521
|
try {
|
|
29506
|
-
|
|
29522
|
+
readFileSync49(opts.composePath, "utf8");
|
|
29507
29523
|
return true;
|
|
29508
29524
|
} catch {}
|
|
29509
29525
|
}
|
|
@@ -29692,7 +29708,7 @@ var init_doctor_docker = __esm(() => {
|
|
|
29692
29708
|
});
|
|
29693
29709
|
|
|
29694
29710
|
// src/cli/doctor-auth-broker.ts
|
|
29695
|
-
import { existsSync as existsSync53, readFileSync as
|
|
29711
|
+
import { existsSync as existsSync53, readFileSync as readFileSync50 } from "node:fs";
|
|
29696
29712
|
import { createHash as createHash10 } from "node:crypto";
|
|
29697
29713
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
29698
29714
|
import { homedir as homedir26 } from "node:os";
|
|
@@ -29806,7 +29822,7 @@ function checkAuthBrokerDrift(deps = {}) {
|
|
|
29806
29822
|
}
|
|
29807
29823
|
let index;
|
|
29808
29824
|
try {
|
|
29809
|
-
index = JSON.parse(
|
|
29825
|
+
index = JSON.parse(readFileSync50(indexPath, "utf-8"));
|
|
29810
29826
|
} catch (err) {
|
|
29811
29827
|
return {
|
|
29812
29828
|
name: "auth-broker: drift",
|
|
@@ -29826,7 +29842,7 @@ function checkAuthBrokerDrift(deps = {}) {
|
|
|
29826
29842
|
}
|
|
29827
29843
|
let got;
|
|
29828
29844
|
try {
|
|
29829
|
-
got = sha256Hex(
|
|
29845
|
+
got = sha256Hex(readFileSync50(credsPath, "utf-8"));
|
|
29830
29846
|
} catch (err) {
|
|
29831
29847
|
divergent.push(`${label} (read failed: ${err.message})`);
|
|
29832
29848
|
continue;
|
|
@@ -29867,7 +29883,7 @@ function checkAuthBrokerThresholdViolations(deps = {}) {
|
|
|
29867
29883
|
}
|
|
29868
29884
|
let violations;
|
|
29869
29885
|
try {
|
|
29870
|
-
violations = JSON.parse(
|
|
29886
|
+
violations = JSON.parse(readFileSync50(path4, "utf-8"));
|
|
29871
29887
|
} catch (err) {
|
|
29872
29888
|
return {
|
|
29873
29889
|
name: "auth-broker: threshold violations",
|
|
@@ -31903,7 +31919,7 @@ import {
|
|
|
31903
31919
|
existsSync as existsSync57,
|
|
31904
31920
|
lstatSync as lstatSync6,
|
|
31905
31921
|
mkdirSync as mkdirSync31,
|
|
31906
|
-
readFileSync as
|
|
31922
|
+
readFileSync as readFileSync51,
|
|
31907
31923
|
readdirSync as readdirSync21,
|
|
31908
31924
|
statSync as statSync25
|
|
31909
31925
|
} from "node:fs";
|
|
@@ -32663,7 +32679,7 @@ function classifyReadError(err) {
|
|
|
32663
32679
|
}
|
|
32664
32680
|
function tryReadHostFile(path4) {
|
|
32665
32681
|
try {
|
|
32666
|
-
return { kind: "ok", content:
|
|
32682
|
+
return { kind: "ok", content: readFileSync51(path4, "utf-8") };
|
|
32667
32683
|
} catch (err) {
|
|
32668
32684
|
const kind = classifyReadError(err);
|
|
32669
32685
|
const error = err?.message ?? String(err);
|
|
@@ -32679,7 +32695,7 @@ function parseEnvFile(path4) {
|
|
|
32679
32695
|
return {};
|
|
32680
32696
|
let content;
|
|
32681
32697
|
try {
|
|
32682
|
-
content =
|
|
32698
|
+
content = readFileSync51(path4, "utf-8");
|
|
32683
32699
|
} catch {
|
|
32684
32700
|
return {};
|
|
32685
32701
|
}
|
|
@@ -32796,7 +32812,7 @@ function checkStartShStale(agentName, startShPath) {
|
|
|
32796
32812
|
}
|
|
32797
32813
|
let content;
|
|
32798
32814
|
try {
|
|
32799
|
-
content =
|
|
32815
|
+
content = readFileSync51(startShPath, "utf-8");
|
|
32800
32816
|
} catch (err) {
|
|
32801
32817
|
return {
|
|
32802
32818
|
name: label,
|
|
@@ -32909,7 +32925,7 @@ function isSwitchroomCheckout(dir) {
|
|
|
32909
32925
|
const pkgPath = join59(dir, "package.json");
|
|
32910
32926
|
if (!existsSync57(pkgPath))
|
|
32911
32927
|
return false;
|
|
32912
|
-
const pkg = JSON.parse(
|
|
32928
|
+
const pkg = JSON.parse(readFileSync51(pkgPath, "utf-8"));
|
|
32913
32929
|
return pkg.name === "switchroom";
|
|
32914
32930
|
} catch {
|
|
32915
32931
|
return false;
|
|
@@ -33030,7 +33046,7 @@ function checkAgents(config, configPath) {
|
|
|
33030
33046
|
});
|
|
33031
33047
|
} else {
|
|
33032
33048
|
try {
|
|
33033
|
-
const mcp = JSON.parse(
|
|
33049
|
+
const mcp = JSON.parse(readFileSync51(mcpJsonPath, "utf-8"));
|
|
33034
33050
|
const hasSwitchroomTelegram = !!mcp.mcpServers?.["switchroom-telegram"];
|
|
33035
33051
|
const memoryEnabled = isHindsightEnabled(config);
|
|
33036
33052
|
const hasHindsight = !!mcp.mcpServers?.hindsight;
|
|
@@ -33525,11 +33541,11 @@ function runDockerSection(config) {
|
|
|
33525
33541
|
let composeYaml;
|
|
33526
33542
|
let dockerfileAgent;
|
|
33527
33543
|
try {
|
|
33528
|
-
composeYaml =
|
|
33544
|
+
composeYaml = readFileSync51(composePath, "utf8");
|
|
33529
33545
|
} catch {}
|
|
33530
33546
|
const dockerfilePath = resolve32(process.env.HOME ?? "", ".switchroom", "docker", "Dockerfile.agent");
|
|
33531
33547
|
try {
|
|
33532
|
-
dockerfileAgent =
|
|
33548
|
+
dockerfileAgent = readFileSync51(dockerfilePath, "utf8");
|
|
33533
33549
|
} catch {}
|
|
33534
33550
|
return runDockerChecks({
|
|
33535
33551
|
config,
|
|
@@ -49836,7 +49852,7 @@ __export(exports_server2, {
|
|
|
49836
49852
|
TOOLS: () => TOOLS2
|
|
49837
49853
|
});
|
|
49838
49854
|
import { randomBytes as randomBytes15 } from "node:crypto";
|
|
49839
|
-
import { existsSync as existsSync83, readFileSync as
|
|
49855
|
+
import { existsSync as existsSync83, readFileSync as readFileSync70 } from "node:fs";
|
|
49840
49856
|
function selfSocketPath() {
|
|
49841
49857
|
return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
|
|
49842
49858
|
}
|
|
@@ -50014,7 +50030,7 @@ function getLastUpdateApplyStatus() {
|
|
|
50014
50030
|
}
|
|
50015
50031
|
let raw;
|
|
50016
50032
|
try {
|
|
50017
|
-
raw =
|
|
50033
|
+
raw = readFileSync70(path8, "utf-8");
|
|
50018
50034
|
} catch (err2) {
|
|
50019
50035
|
return errorText2(`get_status: failed to read audit log at ${path8}: ${err2.message}`);
|
|
50020
50036
|
}
|
|
@@ -50247,8 +50263,8 @@ var {
|
|
|
50247
50263
|
} = import__.default;
|
|
50248
50264
|
|
|
50249
50265
|
// src/build-info.ts
|
|
50250
|
-
var VERSION = "0.15.
|
|
50251
|
-
var COMMIT_SHA = "
|
|
50266
|
+
var VERSION = "0.15.13";
|
|
50267
|
+
var COMMIT_SHA = "36ba2682";
|
|
50252
50268
|
|
|
50253
50269
|
// src/cli/agent.ts
|
|
50254
50270
|
init_source();
|
|
@@ -51714,6 +51730,11 @@ function webkiteDenyForAgent(agentConfig) {
|
|
|
51714
51730
|
}
|
|
51715
51731
|
var SWITCHROOM_DEFAULT_MAIN_MODEL = "claude-sonnet-4-6";
|
|
51716
51732
|
var SWITCHROOM_DEFAULT_THINKING_EFFORT = "low";
|
|
51733
|
+
function resolveMainModel(model) {
|
|
51734
|
+
if (model === undefined || model === "default")
|
|
51735
|
+
return SWITCHROOM_DEFAULT_MAIN_MODEL;
|
|
51736
|
+
return model;
|
|
51737
|
+
}
|
|
51717
51738
|
function dedupe2(items) {
|
|
51718
51739
|
const seen = new Set;
|
|
51719
51740
|
const out = [];
|
|
@@ -51983,6 +52004,10 @@ function channelsToEnv(agent) {
|
|
|
51983
52004
|
if (tg.clear_status_on_completion !== undefined) {
|
|
51984
52005
|
out.SWITCHROOM_TG_CLEAR_STATUS_ON_COMPLETION = tg.clear_status_on_completion ? "1" : "0";
|
|
51985
52006
|
}
|
|
52007
|
+
const linearDefaultTeam = tg?.linear_agent?.default_team_id;
|
|
52008
|
+
if (linearDefaultTeam) {
|
|
52009
|
+
out.SWITCHROOM_LINEAR_DEFAULT_TEAM_ID = linearDefaultTeam;
|
|
52010
|
+
}
|
|
51986
52011
|
return out;
|
|
51987
52012
|
}
|
|
51988
52013
|
function buildRepoEnvVars(_agentName, agentDir, agent) {
|
|
@@ -52322,6 +52347,7 @@ function buildWorkspaceContext(args) {
|
|
|
52322
52347
|
useSwitchroomPlugin: usesSwitchroomTelegramPlugin(agentConfig),
|
|
52323
52348
|
useHotReloadStable: agentConfig.channels?.telegram?.hotReloadStable === true,
|
|
52324
52349
|
telegramEnabledFlag: agentConfig.channels?.telegram?.enabled === false ? "false" : "true",
|
|
52350
|
+
linearAgentEnabled: agentConfig.channels?.telegram?.linear_agent?.enabled === true,
|
|
52325
52351
|
securityPluginDir: DOCKER_SECURITY_PLUGIN_PATH,
|
|
52326
52352
|
hindsightEnabled: hindsightAutoRecallEnabled,
|
|
52327
52353
|
hindsightBankIdQ: shellSingleQuote(hindsightBankId),
|
|
@@ -52333,7 +52359,7 @@ function buildWorkspaceContext(args) {
|
|
|
52333
52359
|
hindsightTopicFilterMode,
|
|
52334
52360
|
switchroomConfigPathQ: switchroomConfigPath ? shellSingleQuote(resolve11(switchroomConfigPath)) : undefined,
|
|
52335
52361
|
hostHomeQ: process.env.HOME ? shellSingleQuote(process.env.HOME) : undefined,
|
|
52336
|
-
modelQ: shellSingleQuote(agentConfig.model
|
|
52362
|
+
modelQ: shellSingleQuote(resolveMainModel(agentConfig.model)),
|
|
52337
52363
|
...buildCronSessionContext(agentConfig),
|
|
52338
52364
|
thinkingEffort: agentConfig.thinking_effort ?? SWITCHROOM_DEFAULT_THINKING_EFFORT,
|
|
52339
52365
|
permissionMode: agentConfig.permission_mode,
|
|
@@ -52633,7 +52659,7 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
52633
52659
|
useSwitchroomPlugin: usesSwitchroomTelegramPlugin(agentConfig),
|
|
52634
52660
|
configPath: switchroomConfigPath
|
|
52635
52661
|
});
|
|
52636
|
-
settings.model = agentConfig.model
|
|
52662
|
+
settings.model = resolveMainModel(agentConfig.model);
|
|
52637
52663
|
const mergedSettings = agentConfig.settings_raw ? deepMergeJson(settings, agentConfig.settings_raw) : settings;
|
|
52638
52664
|
if (agentConfig.settings_raw && Object.keys(agentConfig.settings_raw).length > 0) {
|
|
52639
52665
|
mergedSettings._switchroomManagedRawKeys = Object.keys(agentConfig.settings_raw);
|
|
@@ -53424,7 +53450,7 @@ function reconcileAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchr
|
|
|
53424
53450
|
hindsightTopicAliasesJsonQ: hindsightTopicAliasesJson ? shellSingleQuote(hindsightTopicAliasesJson) : undefined,
|
|
53425
53451
|
hindsightTopicFilterMode,
|
|
53426
53452
|
hostHomeQ: process.env.HOME ? shellSingleQuote(process.env.HOME) : undefined,
|
|
53427
|
-
modelQ: shellSingleQuote(agentConfig.model
|
|
53453
|
+
modelQ: shellSingleQuote(resolveMainModel(agentConfig.model)),
|
|
53428
53454
|
...buildCronSessionContext(agentConfig),
|
|
53429
53455
|
thinkingEffort: agentConfig.thinking_effort ?? SWITCHROOM_DEFAULT_THINKING_EFFORT,
|
|
53430
53456
|
permissionMode: agentConfig.permission_mode,
|
|
@@ -53509,7 +53535,8 @@ function reconcileAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchr
|
|
|
53509
53535
|
schedule: agentConfig.schedule,
|
|
53510
53536
|
useSwitchroomPlugin: usesSwitchroomTelegramPlugin(agentConfig),
|
|
53511
53537
|
admin: agentConfig.admin === true || agentConfig.root === true,
|
|
53512
|
-
root: agentConfig.root === true
|
|
53538
|
+
root: agentConfig.root === true,
|
|
53539
|
+
linearAgentEnabled: agentConfig.channels?.telegram?.linear_agent?.enabled === true
|
|
53513
53540
|
};
|
|
53514
53541
|
let rendered = renderTemplate(claudeMdSrc, claudeContext);
|
|
53515
53542
|
const vaultProtocol = renderVaultProtocolFragment(claudeContext);
|
|
@@ -53675,7 +53702,7 @@ ${body}
|
|
|
53675
53702
|
}
|
|
53676
53703
|
}
|
|
53677
53704
|
}
|
|
53678
|
-
settings.model = agentConfig.model
|
|
53705
|
+
settings.model = resolveMainModel(agentConfig.model);
|
|
53679
53706
|
const mergedSettings = agentConfig.settings_raw ? deepMergeJson(settings, agentConfig.settings_raw) : settings;
|
|
53680
53707
|
if (agentConfig.settings_raw && Object.keys(agentConfig.settings_raw).length > 0) {
|
|
53681
53708
|
mergedSettings[META_KEY] = Object.keys(agentConfig.settings_raw);
|
|
@@ -67029,6 +67056,31 @@ import { createInterface as createInterface4 } from "node:readline";
|
|
|
67029
67056
|
|
|
67030
67057
|
// src/cli/telegram-yaml.ts
|
|
67031
67058
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
67059
|
+
function setLinearAgent(yamlText, agentName, opts) {
|
|
67060
|
+
const doc = import_yaml11.parseDocument(yamlText);
|
|
67061
|
+
ensureAgent(doc, agentName);
|
|
67062
|
+
const block = { enabled: true, token: opts.token };
|
|
67063
|
+
if (opts.workspaceId)
|
|
67064
|
+
block.workspace_id = opts.workspaceId;
|
|
67065
|
+
doc.setIn(["agents", agentName, "channels", "telegram", "linear_agent"], block);
|
|
67066
|
+
doc.setIn(["agents", agentName, "channels", "telegram", "webhook_via_gateway"], true);
|
|
67067
|
+
return String(doc);
|
|
67068
|
+
}
|
|
67069
|
+
function setLinearDefaultTeam(yamlText, agentName, teamId) {
|
|
67070
|
+
const doc = import_yaml11.parseDocument(yamlText);
|
|
67071
|
+
ensureAgent(doc, agentName);
|
|
67072
|
+
if (!doc.hasIn(["agents", agentName, "channels", "telegram", "linear_agent"])) {
|
|
67073
|
+
throw new Error(`agent '${agentName}' has no linear_agent block. Run 'switchroom linear-agent setup --agent ${agentName} --token <token>' first.`);
|
|
67074
|
+
}
|
|
67075
|
+
const path4 = ["agents", agentName, "channels", "telegram", "linear_agent", "default_team_id"];
|
|
67076
|
+
if (teamId === null) {
|
|
67077
|
+
if (doc.hasIn(path4))
|
|
67078
|
+
doc.deleteIn(path4);
|
|
67079
|
+
} else {
|
|
67080
|
+
doc.setIn(path4, teamId);
|
|
67081
|
+
}
|
|
67082
|
+
return String(doc);
|
|
67083
|
+
}
|
|
67032
67084
|
function setTelegramFeature(yamlText, agentName, feature, value) {
|
|
67033
67085
|
const doc = import_yaml11.parseDocument(yamlText);
|
|
67034
67086
|
ensureAgent(doc, agentName);
|
|
@@ -67587,6 +67639,123 @@ function promptHidden2(prompt) {
|
|
|
67587
67639
|
});
|
|
67588
67640
|
}
|
|
67589
67641
|
|
|
67642
|
+
// src/cli/linear-agent.ts
|
|
67643
|
+
init_source();
|
|
67644
|
+
init_helpers();
|
|
67645
|
+
import { readFileSync as readFileSync39, writeFileSync as writeFileSync22 } from "node:fs";
|
|
67646
|
+
function registerLinearAgentCommand(program3) {
|
|
67647
|
+
const linear = program3.command("linear-agent").description("Install an agent into a Linear workspace as a first-class app actor (#2298) \u2014 @-mentionable, delegate-assignable, agent sessions wake it instantly.");
|
|
67648
|
+
linear.command("setup").description("Provision <agent> as a Linear agent. Vault-stores the Linear OAuth app token (actor=app) under 'linear/<agent>/token' and enables the linear_agent block in switchroom.yaml. The OAuth browser authorize step is printed as instructions (it can't run headless); pass the already-obtained --token.").requiredOption("--agent <name>", "Agent name (must exist in switchroom.yaml)").requiredOption("--token <token>", "The Linear OAuth app token (actor=app), obtained out-of-band via the browser authorize step. Stored in the vault, never in switchroom.yaml.").option("--client-id <id>", "Linear OAuth app client id (for the printed authorize-URL hint).").option("--client-secret <secret>", "Linear OAuth app client secret (informational \u2014 not stored by this verb).").option("--redirect-uri <uri>", "OAuth redirect URI registered on the Linear app (for the authorize-URL hint).").option("--workspace-id <id>", "Optional Linear workspace (organization) id to record in config.").option("--webhook-base <url>", "Base URL of the switchroom web server (e.g. https://hooks.switchroom.ai). Used to print the webhook URL to register in Linear. Defaults to a placeholder.").option("--dry-run", "Print the YAML diff + instructions without writing or vaulting anything").action(withConfigError(async (opts) => {
|
|
67649
|
+
if (!/^[a-z][a-z0-9_-]{0,63}$/.test(opts.agent)) {
|
|
67650
|
+
fail2(`--agent must be a lowercase agent slug (got '${opts.agent}').`);
|
|
67651
|
+
}
|
|
67652
|
+
if (!opts.token || opts.token.trim().length === 0) {
|
|
67653
|
+
fail2("--token must be a non-empty Linear app token.");
|
|
67654
|
+
}
|
|
67655
|
+
const vaultKey = `linear/${opts.agent}/token`;
|
|
67656
|
+
if (!opts.dryRun) {
|
|
67657
|
+
await vaultPut(program3, vaultKey, opts.token);
|
|
67658
|
+
} else {
|
|
67659
|
+
console.log(source_default.gray(`[dry-run] would store the Linear token in the vault as '${vaultKey}'`));
|
|
67660
|
+
}
|
|
67661
|
+
const path4 = getConfigPath(program3);
|
|
67662
|
+
const before = readFileSync39(path4, "utf-8");
|
|
67663
|
+
let after;
|
|
67664
|
+
try {
|
|
67665
|
+
after = setLinearAgent(before, opts.agent, {
|
|
67666
|
+
token: `vault:${vaultKey}`,
|
|
67667
|
+
...opts.workspaceId ? { workspaceId: opts.workspaceId } : {}
|
|
67668
|
+
});
|
|
67669
|
+
} catch (err) {
|
|
67670
|
+
fail2(err.message);
|
|
67671
|
+
}
|
|
67672
|
+
if (opts.dryRun) {
|
|
67673
|
+
console.log(source_default.bold(`[dry-run] would edit ${path4}`));
|
|
67674
|
+
console.log(makeUnifiedDiff2(before, after));
|
|
67675
|
+
} else {
|
|
67676
|
+
writeFileSync22(path4, after, "utf-8");
|
|
67677
|
+
console.log(source_default.green(`\u2713 Enabled linear-agent for agent '${opts.agent}'`));
|
|
67678
|
+
console.log(source_default.gray(` Vault key: ${vaultKey}`));
|
|
67679
|
+
console.log(source_default.gray(` Run 'switchroom agent restart ${opts.agent}' to pick up the change.`));
|
|
67680
|
+
}
|
|
67681
|
+
printLinearInstructions(opts, vaultKey);
|
|
67682
|
+
}));
|
|
67683
|
+
linear.command("set-team").description("Set (or clear) the default Linear team captured issues file into for <agent>. Only needed when the workspace has multiple teams \u2014 a single-team workspace auto-resolves. Pass --clear to remove the default.").requiredOption("--agent <name>", "Agent name (must have a linear_agent block)").option("--team <id>", "Linear team id new captured issues default to.").option("--clear", "Remove the configured default team (revert to auto-resolve).").action(withConfigError(async (opts) => {
|
|
67684
|
+
if (!/^[a-z][a-z0-9_-]{0,63}$/.test(opts.agent)) {
|
|
67685
|
+
fail2(`--agent must be a lowercase agent slug (got '${opts.agent}').`);
|
|
67686
|
+
}
|
|
67687
|
+
if (!opts.clear && (!opts.team || opts.team.trim().length === 0)) {
|
|
67688
|
+
fail2("pass either --team <id> or --clear.");
|
|
67689
|
+
}
|
|
67690
|
+
const path4 = getConfigPath(program3);
|
|
67691
|
+
const before = readFileSync39(path4, "utf-8");
|
|
67692
|
+
let after;
|
|
67693
|
+
try {
|
|
67694
|
+
after = setLinearDefaultTeam(before, opts.agent, opts.clear ? null : opts.team.trim());
|
|
67695
|
+
} catch (err) {
|
|
67696
|
+
fail2(err.message);
|
|
67697
|
+
}
|
|
67698
|
+
writeFileSync22(path4, after, "utf-8");
|
|
67699
|
+
if (opts.clear) {
|
|
67700
|
+
console.log(source_default.green(`\u2713 Cleared default Linear team for '${opts.agent}' (auto-resolve).`));
|
|
67701
|
+
} else {
|
|
67702
|
+
console.log(source_default.green(`\u2713 Default Linear team for '${opts.agent}' set to ${opts.team.trim()}.`));
|
|
67703
|
+
}
|
|
67704
|
+
console.log(source_default.gray(` Run 'switchroom agent restart ${opts.agent}' to pick up the change.`));
|
|
67705
|
+
}));
|
|
67706
|
+
}
|
|
67707
|
+
function printLinearInstructions(opts, vaultKey) {
|
|
67708
|
+
const base = opts.webhookBase ?? "https://<your-switchroom-web-host>";
|
|
67709
|
+
const webhookUrl = `${base.replace(/\/$/, "")}/webhook/${opts.agent}/linear`;
|
|
67710
|
+
console.log("");
|
|
67711
|
+
console.log(source_default.bold("Next steps in Linear (browser, one-time per agent):"));
|
|
67712
|
+
console.log(source_default.gray(" 1. Create / open your Linear OAuth app with actor=app and scopes"));
|
|
67713
|
+
console.log(source_default.gray(" app:mentionable + app:assignable (https://linear.app/developers/agents)."));
|
|
67714
|
+
if (opts.clientId) {
|
|
67715
|
+
const redirect = opts.redirectUri ?? `${base.replace(/\/$/, "")}/oauth/callback`;
|
|
67716
|
+
const authorizeUrl = `https://linear.app/oauth/authorize?` + `client_id=${encodeURIComponent(opts.clientId)}` + `&redirect_uri=${encodeURIComponent(redirect)}` + `&response_type=code` + `&scope=${encodeURIComponent("read,write,app:assignable,app:mentionable")}` + `&actor=app`;
|
|
67717
|
+
console.log(source_default.gray(" 2. Authorize the app as an actor (open in a browser):"));
|
|
67718
|
+
console.log(source_default.cyan(` ${authorizeUrl}`));
|
|
67719
|
+
console.log(source_default.gray(" The redirect delivers the app token you pass to this verb via --token."));
|
|
67720
|
+
} else {
|
|
67721
|
+
console.log(source_default.gray(" 2. Authorize the app (actor=app) in a browser; capture the app token and"));
|
|
67722
|
+
console.log(source_default.gray(" re-run this verb with --token (and optionally --client-id to print the"));
|
|
67723
|
+
console.log(source_default.gray(" authorize URL)."));
|
|
67724
|
+
}
|
|
67725
|
+
console.log(source_default.gray(" 3. Register this webhook URL on the app (AgentSessionEvent + Issue/Comment):"));
|
|
67726
|
+
console.log(source_default.cyan(` ${webhookUrl}`));
|
|
67727
|
+
console.log(source_default.gray(" Use Linear's signing secret as the webhook secret \u2014 store it in the vault " + `under webhook/${opts.agent}/linear (e.g. 'switchroom telegram enable webhook ` + `--agent ${opts.agent} --source linear --secret <signing-secret>').`));
|
|
67728
|
+
console.log("");
|
|
67729
|
+
console.log(source_default.gray(` Token is read at runtime from vault:${vaultKey} (actor=app).`));
|
|
67730
|
+
}
|
|
67731
|
+
function makeUnifiedDiff2(before, after) {
|
|
67732
|
+
const a = before.split(`
|
|
67733
|
+
`);
|
|
67734
|
+
const b = after.split(`
|
|
67735
|
+
`);
|
|
67736
|
+
const out = [];
|
|
67737
|
+
let i = 0, j = 0;
|
|
67738
|
+
while (i < a.length || j < b.length) {
|
|
67739
|
+
if (i < a.length && j < b.length && a[i] === b[j]) {
|
|
67740
|
+
out.push(` ${a[i]}`);
|
|
67741
|
+
i++;
|
|
67742
|
+
j++;
|
|
67743
|
+
} else if (j < b.length && (i >= a.length || a[i] !== b[j])) {
|
|
67744
|
+
out.push(source_default.green(`+ ${b[j]}`));
|
|
67745
|
+
j++;
|
|
67746
|
+
} else {
|
|
67747
|
+
out.push(source_default.red(`- ${a[i]}`));
|
|
67748
|
+
i++;
|
|
67749
|
+
}
|
|
67750
|
+
}
|
|
67751
|
+
return out.join(`
|
|
67752
|
+
`);
|
|
67753
|
+
}
|
|
67754
|
+
function fail2(msg) {
|
|
67755
|
+
console.error(source_default.red(`Error: ${msg}`));
|
|
67756
|
+
process.exit(1);
|
|
67757
|
+
}
|
|
67758
|
+
|
|
67590
67759
|
// src/cli/memory.ts
|
|
67591
67760
|
init_source();
|
|
67592
67761
|
init_hindsight();
|
|
@@ -67856,7 +68025,7 @@ async function ensureHindsightConsumer(configPath, account, uid = HINDSIGHT_DEFA
|
|
|
67856
68025
|
// src/cli/memory.ts
|
|
67857
68026
|
init_loader();
|
|
67858
68027
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
67859
|
-
import { existsSync as existsSync44, readFileSync as
|
|
68028
|
+
import { existsSync as existsSync44, readFileSync as readFileSync40, writeFileSync as writeFileSync23 } from "node:fs";
|
|
67860
68029
|
import { join as join39 } from "node:path";
|
|
67861
68030
|
function readRecallLog(agentDir, limit) {
|
|
67862
68031
|
const path4 = join39(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
|
|
@@ -67864,7 +68033,7 @@ function readRecallLog(agentDir, limit) {
|
|
|
67864
68033
|
return [];
|
|
67865
68034
|
let raw;
|
|
67866
68035
|
try {
|
|
67867
|
-
raw =
|
|
68036
|
+
raw = readFileSync40(path4, "utf-8");
|
|
67868
68037
|
} catch {
|
|
67869
68038
|
return [];
|
|
67870
68039
|
}
|
|
@@ -68059,7 +68228,7 @@ Cross-agent reflection plan
|
|
|
68059
68228
|
const configPath = getConfigPath(program3);
|
|
68060
68229
|
try {
|
|
68061
68230
|
if (existsSync44(configPath)) {
|
|
68062
|
-
const raw =
|
|
68231
|
+
const raw = readFileSync40(configPath, "utf-8");
|
|
68063
68232
|
const doc = import_yaml12.default.parseDocument(raw);
|
|
68064
68233
|
if (!doc.has("memory")) {
|
|
68065
68234
|
doc.set("memory", { backend: "hindsight", shared_collection: "shared", config: { provider, url } });
|
|
@@ -68075,7 +68244,7 @@ Cross-agent reflection plan
|
|
|
68075
68244
|
}
|
|
68076
68245
|
}
|
|
68077
68246
|
}
|
|
68078
|
-
|
|
68247
|
+
writeFileSync23(configPath, doc.toString(), "utf-8");
|
|
68079
68248
|
console.log(source_default.gray(` Updated ${configPath} with memory.config.url = ${url}`));
|
|
68080
68249
|
console.log(source_default.gray(" Run `switchroom agent reconcile all --restart` to apply this to existing agents."));
|
|
68081
68250
|
}
|
|
@@ -68168,7 +68337,7 @@ init_loader();
|
|
|
68168
68337
|
init_client();
|
|
68169
68338
|
init_lifecycle();
|
|
68170
68339
|
import {
|
|
68171
|
-
readFileSync as
|
|
68340
|
+
readFileSync as readFileSync46,
|
|
68172
68341
|
existsSync as existsSync50,
|
|
68173
68342
|
realpathSync as realpathSync4,
|
|
68174
68343
|
mkdirSync as mkdirSync29,
|
|
@@ -68187,7 +68356,7 @@ init_lifecycle();
|
|
|
68187
68356
|
init_manager();
|
|
68188
68357
|
init_hindsight();
|
|
68189
68358
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
68190
|
-
import { existsSync as existsSync47, readFileSync as
|
|
68359
|
+
import { existsSync as existsSync47, readFileSync as readFileSync43, statSync as statSync22 } from "node:fs";
|
|
68191
68360
|
import { resolve as resolve27 } from "node:path";
|
|
68192
68361
|
init_audit_reader();
|
|
68193
68362
|
|
|
@@ -72695,8 +72864,8 @@ init_paths();
|
|
|
72695
72864
|
import {
|
|
72696
72865
|
existsSync as existsSync45,
|
|
72697
72866
|
mkdirSync as mkdirSync25,
|
|
72698
|
-
readFileSync as
|
|
72699
|
-
writeFileSync as
|
|
72867
|
+
readFileSync as readFileSync41,
|
|
72868
|
+
writeFileSync as writeFileSync24
|
|
72700
72869
|
} from "node:fs";
|
|
72701
72870
|
import { dirname as dirname9 } from "node:path";
|
|
72702
72871
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
@@ -72716,7 +72885,7 @@ function getDistinctId() {
|
|
|
72716
72885
|
const path4 = resolveStatePath("analytics-id");
|
|
72717
72886
|
try {
|
|
72718
72887
|
if (existsSync45(path4)) {
|
|
72719
|
-
const existing =
|
|
72888
|
+
const existing = readFileSync41(path4, "utf-8").trim();
|
|
72720
72889
|
if (existing) {
|
|
72721
72890
|
cachedDistinctId = existing;
|
|
72722
72891
|
return existing;
|
|
@@ -72727,7 +72896,7 @@ function getDistinctId() {
|
|
|
72727
72896
|
cachedDistinctId = id;
|
|
72728
72897
|
try {
|
|
72729
72898
|
mkdirSync25(dirname9(path4), { recursive: true });
|
|
72730
|
-
|
|
72899
|
+
writeFileSync24(path4, id, "utf-8");
|
|
72731
72900
|
} catch {}
|
|
72732
72901
|
return id;
|
|
72733
72902
|
}
|
|
@@ -72852,7 +73021,7 @@ function getAgentWorkspaceAccount(yamlText, provider, agent) {
|
|
|
72852
73021
|
// src/web/config-edit-plan.ts
|
|
72853
73022
|
init_schema();
|
|
72854
73023
|
var import_yaml14 = __toESM(require_dist(), 1);
|
|
72855
|
-
import { readFileSync as
|
|
73024
|
+
import { readFileSync as readFileSync42 } from "node:fs";
|
|
72856
73025
|
|
|
72857
73026
|
class ConfigPlanError extends Error {
|
|
72858
73027
|
}
|
|
@@ -72862,7 +73031,7 @@ function composeTransforms(...transforms) {
|
|
|
72862
73031
|
function planConfigEdit(configPath, transform) {
|
|
72863
73032
|
let before;
|
|
72864
73033
|
try {
|
|
72865
|
-
before =
|
|
73034
|
+
before = readFileSync42(configPath, "utf-8");
|
|
72866
73035
|
} catch (err) {
|
|
72867
73036
|
throw new ConfigPlanError(`could not read config: ${err.message}`);
|
|
72868
73037
|
}
|
|
@@ -72893,7 +73062,7 @@ import {
|
|
|
72893
73062
|
mkdirSync as mkdirSync26,
|
|
72894
73063
|
mkdtempSync as mkdtemp,
|
|
72895
73064
|
rmSync as rmrf,
|
|
72896
|
-
writeFileSync as
|
|
73065
|
+
writeFileSync as writeFileSync25
|
|
72897
73066
|
} from "node:fs";
|
|
72898
73067
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
72899
73068
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
@@ -72908,8 +73077,8 @@ function generateUnifiedDiff(before, after, name = "switchroom.yaml", gitBin = "
|
|
|
72908
73077
|
try {
|
|
72909
73078
|
mkdirSync26(join41(dir, "cur"), { recursive: true });
|
|
72910
73079
|
mkdirSync26(join41(dir, "new"), { recursive: true });
|
|
72911
|
-
|
|
72912
|
-
|
|
73080
|
+
writeFileSync25(join41(dir, "cur", name), before);
|
|
73081
|
+
writeFileSync25(join41(dir, "new", name), after);
|
|
72913
73082
|
const r = spawnSync4(gitBin, ["diff", "--no-index", "--no-color", "--", `cur/${name}`, `new/${name}`], { cwd: dir, encoding: "utf-8", timeout: 1e4 });
|
|
72914
73083
|
if (r.status === 0)
|
|
72915
73084
|
return "";
|
|
@@ -73546,7 +73715,7 @@ async function handleGetSystemHealth(config, home2) {
|
|
|
73546
73715
|
const logPath = defaultAuditLogPath2(home2);
|
|
73547
73716
|
if (existsSync47(logPath)) {
|
|
73548
73717
|
hostd.auditLogPresent = true;
|
|
73549
|
-
const raw =
|
|
73718
|
+
const raw = readFileSync43(logPath, "utf-8");
|
|
73550
73719
|
hostd.recent = readAndFilter(raw, {}, 10);
|
|
73551
73720
|
}
|
|
73552
73721
|
} catch (err) {
|
|
@@ -73906,7 +74075,7 @@ async function handleGetMemoryHealth(config, opts) {
|
|
|
73906
74075
|
}
|
|
73907
74076
|
|
|
73908
74077
|
// src/web/webhook-handler.ts
|
|
73909
|
-
import { appendFileSync as appendFileSync4, existsSync as existsSync49, mkdirSync as mkdirSync28, readFileSync as
|
|
74078
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync49, mkdirSync as mkdirSync28, readFileSync as readFileSync45, writeFileSync as writeFileSync26 } from "fs";
|
|
73910
74079
|
import { join as join45 } from "path";
|
|
73911
74080
|
import { homedir as homedir24 } from "os";
|
|
73912
74081
|
|
|
@@ -74113,7 +74282,7 @@ function forwardToGateway(socketPath, req, opts = {}) {
|
|
|
74113
74282
|
}
|
|
74114
74283
|
|
|
74115
74284
|
// src/web/webhook-edge.ts
|
|
74116
|
-
import { existsSync as existsSync48, readFileSync as
|
|
74285
|
+
import { existsSync as existsSync48, readFileSync as readFileSync44 } from "fs";
|
|
74117
74286
|
import { join as join44 } from "path";
|
|
74118
74287
|
import { homedir as homedir23 } from "os";
|
|
74119
74288
|
import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
@@ -74126,7 +74295,7 @@ function loadEdgeSecret(path4) {
|
|
|
74126
74295
|
try {
|
|
74127
74296
|
if (!existsSync48(p))
|
|
74128
74297
|
return null;
|
|
74129
|
-
const raw =
|
|
74298
|
+
const raw = readFileSync44(p, "utf-8").trim();
|
|
74130
74299
|
return raw.length > 0 ? raw : null;
|
|
74131
74300
|
} catch {
|
|
74132
74301
|
return null;
|
|
@@ -74160,7 +74329,7 @@ function loadDedupFile(path4) {
|
|
|
74160
74329
|
try {
|
|
74161
74330
|
if (!existsSync49(path4))
|
|
74162
74331
|
return {};
|
|
74163
|
-
const raw = JSON.parse(
|
|
74332
|
+
const raw = JSON.parse(readFileSync45(path4, "utf-8"));
|
|
74164
74333
|
return typeof raw.deliveries === "object" && raw.deliveries !== null ? raw.deliveries : {};
|
|
74165
74334
|
} catch {
|
|
74166
74335
|
return {};
|
|
@@ -74174,7 +74343,7 @@ function saveDedupFile(path4, deliveries, now) {
|
|
|
74174
74343
|
}
|
|
74175
74344
|
const sorted = Object.entries(pruned).sort((a, b) => b[1] - a[1]).slice(0, DEDUP_MAX);
|
|
74176
74345
|
const final = Object.fromEntries(sorted);
|
|
74177
|
-
|
|
74346
|
+
writeFileSync26(path4, JSON.stringify({ deliveries: final }), {
|
|
74178
74347
|
mode: 384
|
|
74179
74348
|
});
|
|
74180
74349
|
}
|
|
@@ -74443,7 +74612,7 @@ function resolveWebToken() {
|
|
|
74443
74612
|
const home2 = process.env.HOME ?? homedir25();
|
|
74444
74613
|
const tokenPath = join46(home2, ".switchroom", "web-token");
|
|
74445
74614
|
if (existsSync50(tokenPath)) {
|
|
74446
|
-
const existing =
|
|
74615
|
+
const existing = readFileSync46(tokenPath, "utf8").trim();
|
|
74447
74616
|
if (existing.length > 0)
|
|
74448
74617
|
return existing;
|
|
74449
74618
|
}
|
|
@@ -74460,7 +74629,7 @@ function resolveWebToken() {
|
|
|
74460
74629
|
return token;
|
|
74461
74630
|
} catch (err) {
|
|
74462
74631
|
if (err.code === "EEXIST") {
|
|
74463
|
-
const existing =
|
|
74632
|
+
const existing = readFileSync46(tokenPath, "utf8").trim();
|
|
74464
74633
|
if (existing.length > 0)
|
|
74465
74634
|
return existing;
|
|
74466
74635
|
}
|
|
@@ -74530,7 +74699,7 @@ function loadWebhookSecrets() {
|
|
|
74530
74699
|
if (!existsSync50(path4))
|
|
74531
74700
|
return {};
|
|
74532
74701
|
try {
|
|
74533
|
-
const parsed = JSON.parse(
|
|
74702
|
+
const parsed = JSON.parse(readFileSync46(path4, "utf-8"));
|
|
74534
74703
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
74535
74704
|
} catch (err) {
|
|
74536
74705
|
process.stderr.write(`webhook-ingest: failed to parse ${path4}: ${err.message} \u2014 webhooks will return 401 until fixed
|
|
@@ -74903,7 +75072,7 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
|
|
|
74903
75072
|
}
|
|
74904
75073
|
const ext = extname(realFullPath);
|
|
74905
75074
|
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
74906
|
-
const content =
|
|
75075
|
+
const content = readFileSync46(realFullPath);
|
|
74907
75076
|
return new Response(content, {
|
|
74908
75077
|
headers: { "Content-Type": contentType }
|
|
74909
75078
|
});
|
|
@@ -75037,7 +75206,7 @@ Starting Switchroom dashboard...
|
|
|
75037
75206
|
// src/cli/setup.ts
|
|
75038
75207
|
init_source();
|
|
75039
75208
|
init_loader();
|
|
75040
|
-
import { existsSync as existsSync51, copyFileSync as copyFileSync8, readFileSync as
|
|
75209
|
+
import { existsSync as existsSync51, copyFileSync as copyFileSync8, readFileSync as readFileSync47, writeFileSync as writeFileSync27, mkdirSync as mkdirSync30 } from "node:fs";
|
|
75041
75210
|
import { resolve as resolve29, dirname as dirname11 } from "node:path";
|
|
75042
75211
|
init_vault();
|
|
75043
75212
|
init_manager();
|
|
@@ -75766,10 +75935,10 @@ async function stepAutoUnlock(config, switchroomConfigPath, nonInteractive) {
|
|
|
75766
75935
|
try {
|
|
75767
75936
|
const yamlPath = existsSync51(resolve29(process.cwd(), "switchroom.yaml")) ? resolve29(process.cwd(), "switchroom.yaml") : resolve29(process.cwd(), "switchroom.yml");
|
|
75768
75937
|
if (existsSync51(yamlPath)) {
|
|
75769
|
-
const content =
|
|
75938
|
+
const content = readFileSync47(yamlPath, "utf-8");
|
|
75770
75939
|
const result = insertVaultBrokerApprovalAuth(content, "telegram-id");
|
|
75771
75940
|
if (result.kind === "rewritten") {
|
|
75772
|
-
|
|
75941
|
+
writeFileSync27(yamlPath, result.content, "utf-8");
|
|
75773
75942
|
console.log(source_default.green(` ${STEP_DONE} Set vault.broker.approvalAuth: telegram-id in ${yamlPath}`));
|
|
75774
75943
|
} else if (result.kind === "already-set") {
|
|
75775
75944
|
console.log(source_default.gray(" approvalAuth already set \u2014 leaving it alone."));
|
|
@@ -75801,7 +75970,7 @@ async function stepDangerousMode(config, nonInteractive) {
|
|
|
75801
75970
|
];
|
|
75802
75971
|
for (const configPath of configPaths) {
|
|
75803
75972
|
if (existsSync51(configPath)) {
|
|
75804
|
-
let content =
|
|
75973
|
+
let content = readFileSync47(configPath, "utf-8");
|
|
75805
75974
|
const agentNames = Object.keys(config.agents);
|
|
75806
75975
|
for (const name of agentNames) {
|
|
75807
75976
|
const agentPattern = new RegExp(`(^ ${name}:\\s*\\n)`, "m");
|
|
@@ -75815,7 +75984,7 @@ async function stepDangerousMode(config, nonInteractive) {
|
|
|
75815
75984
|
}
|
|
75816
75985
|
config.agents[name].dangerous_mode = true;
|
|
75817
75986
|
}
|
|
75818
|
-
|
|
75987
|
+
writeFileSync27(configPath, content, "utf-8");
|
|
75819
75988
|
console.log(source_default.green(` ${STEP_DONE} Enabled dangerous_mode for all agents in ${configPath}`));
|
|
75820
75989
|
break;
|
|
75821
75990
|
}
|
|
@@ -75930,7 +76099,7 @@ init_doctor();
|
|
|
75930
76099
|
init_source();
|
|
75931
76100
|
init_loader();
|
|
75932
76101
|
init_lifecycle();
|
|
75933
|
-
import { cpSync as cpSync2, existsSync as existsSync58, mkdirSync as mkdirSync32, readFileSync as
|
|
76102
|
+
import { cpSync as cpSync2, existsSync as existsSync58, mkdirSync as mkdirSync32, readFileSync as readFileSync52, realpathSync as realpathSync6, rmSync as rmSync12, statSync as statSync26 } from "node:fs";
|
|
75934
76103
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
75935
76104
|
import { join as join60, dirname as dirname14, resolve as resolve33 } from "node:path";
|
|
75936
76105
|
import { homedir as homedir36 } from "node:os";
|
|
@@ -75940,7 +76109,7 @@ function runningFromSwitchroomCheckout(scriptPath) {
|
|
|
75940
76109
|
for (let i = 0;i < 12; i++) {
|
|
75941
76110
|
if (existsSync58(join60(dir, ".git"))) {
|
|
75942
76111
|
try {
|
|
75943
|
-
const pkg = JSON.parse(
|
|
76112
|
+
const pkg = JSON.parse(readFileSync52(join60(dir, "package.json"), "utf-8"));
|
|
75944
76113
|
if (pkg.name === "switchroom")
|
|
75945
76114
|
return true;
|
|
75946
76115
|
} catch {}
|
|
@@ -76208,7 +76377,7 @@ function defaultStatusProbe(composePath) {
|
|
|
76208
76377
|
const pkgPath = join60(dir, "package.json");
|
|
76209
76378
|
if (existsSync58(pkgPath)) {
|
|
76210
76379
|
try {
|
|
76211
|
-
const pkg = JSON.parse(
|
|
76380
|
+
const pkg = JSON.parse(readFileSync52(pkgPath, "utf-8"));
|
|
76212
76381
|
if (typeof pkg.version === "string")
|
|
76213
76382
|
cliVersion = pkg.version;
|
|
76214
76383
|
} catch (err) {
|
|
@@ -76424,7 +76593,7 @@ init_source();
|
|
|
76424
76593
|
init_helpers();
|
|
76425
76594
|
init_lifecycle();
|
|
76426
76595
|
import { execSync as execSync4 } from "node:child_process";
|
|
76427
|
-
import { existsSync as existsSync59, readFileSync as
|
|
76596
|
+
import { existsSync as existsSync59, readFileSync as readFileSync53 } from "node:fs";
|
|
76428
76597
|
import { dirname as dirname15, join as join61 } from "node:path";
|
|
76429
76598
|
function getClaudeCodeVersion() {
|
|
76430
76599
|
try {
|
|
@@ -76478,7 +76647,7 @@ function locateSwitchroomInstallDir() {
|
|
|
76478
76647
|
const pkgPath = join61(dir, "package.json");
|
|
76479
76648
|
if (existsSync59(pkgPath)) {
|
|
76480
76649
|
try {
|
|
76481
|
-
const pkg = JSON.parse(
|
|
76650
|
+
const pkg = JSON.parse(readFileSync53(pkgPath, "utf-8"));
|
|
76482
76651
|
if (pkg.name === "switchroom" && existsSync59(join61(dir, ".git"))) {
|
|
76483
76652
|
return dir;
|
|
76484
76653
|
}
|
|
@@ -76709,11 +76878,11 @@ import {
|
|
|
76709
76878
|
mkdirSync as mkdirSync33,
|
|
76710
76879
|
openSync as openSync11,
|
|
76711
76880
|
readdirSync as readdirSync22,
|
|
76712
|
-
readFileSync as
|
|
76881
|
+
readFileSync as readFileSync54,
|
|
76713
76882
|
renameSync as renameSync12,
|
|
76714
76883
|
statSync as statSync27,
|
|
76715
76884
|
unlinkSync as unlinkSync11,
|
|
76716
|
-
writeFileSync as
|
|
76885
|
+
writeFileSync as writeFileSync28,
|
|
76717
76886
|
writeSync as writeSync7
|
|
76718
76887
|
} from "node:fs";
|
|
76719
76888
|
import { join as join62 } from "node:path";
|
|
@@ -77119,7 +77288,7 @@ function readAll(stateDir) {
|
|
|
77119
77288
|
return [];
|
|
77120
77289
|
let raw;
|
|
77121
77290
|
try {
|
|
77122
|
-
raw =
|
|
77291
|
+
raw = readFileSync54(path4, "utf-8");
|
|
77123
77292
|
} catch {
|
|
77124
77293
|
return [];
|
|
77125
77294
|
}
|
|
@@ -77267,7 +77436,7 @@ function writeAll(stateDir, events) {
|
|
|
77267
77436
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
77268
77437
|
`) + `
|
|
77269
77438
|
`;
|
|
77270
|
-
|
|
77439
|
+
writeFileSync28(tmp, body, "utf-8");
|
|
77271
77440
|
renameSync12(tmp, path4);
|
|
77272
77441
|
}
|
|
77273
77442
|
var ORPHAN_TMP_TTL_MS = 60000;
|
|
@@ -77330,7 +77499,7 @@ function withLock(stateDir, fn) {
|
|
|
77330
77499
|
function tryStealStaleLock(lockPath) {
|
|
77331
77500
|
let pidStr;
|
|
77332
77501
|
try {
|
|
77333
|
-
pidStr =
|
|
77502
|
+
pidStr = readFileSync54(lockPath, "utf-8").trim();
|
|
77334
77503
|
} catch {
|
|
77335
77504
|
return true;
|
|
77336
77505
|
}
|
|
@@ -77587,9 +77756,9 @@ import { createHash as createHash11 } from "node:crypto";
|
|
|
77587
77756
|
import {
|
|
77588
77757
|
existsSync as existsSync61,
|
|
77589
77758
|
mkdirSync as mkdirSync34,
|
|
77590
|
-
readFileSync as
|
|
77759
|
+
readFileSync as readFileSync55,
|
|
77591
77760
|
rmSync as rmSync13,
|
|
77592
|
-
writeFileSync as
|
|
77761
|
+
writeFileSync as writeFileSync29
|
|
77593
77762
|
} from "node:fs";
|
|
77594
77763
|
import { dirname as dirname16, join as join63 } from "node:path";
|
|
77595
77764
|
import { homedir as homedir37 } from "node:os";
|
|
@@ -77607,7 +77776,7 @@ function defaultPythonCacheRoot() {
|
|
|
77607
77776
|
return join63(homedir37(), ".switchroom", "deps", "python");
|
|
77608
77777
|
}
|
|
77609
77778
|
function hashFile(path4) {
|
|
77610
|
-
return createHash11("sha256").update(
|
|
77779
|
+
return createHash11("sha256").update(readFileSync55(path4)).digest("hex");
|
|
77611
77780
|
}
|
|
77612
77781
|
function ensurePythonEnv(opts) {
|
|
77613
77782
|
const { skillName, requirementsPath, force = false } = opts;
|
|
@@ -77623,7 +77792,7 @@ function ensurePythonEnv(opts) {
|
|
|
77623
77792
|
const pipBin = join63(binDir, "pip");
|
|
77624
77793
|
const targetHash = hashFile(requirementsPath);
|
|
77625
77794
|
if (!force && existsSync61(stampPath) && existsSync61(pythonBin)) {
|
|
77626
|
-
const existingHash =
|
|
77795
|
+
const existingHash = readFileSync55(stampPath, "utf8").trim();
|
|
77627
77796
|
if (existingHash === targetHash) {
|
|
77628
77797
|
return {
|
|
77629
77798
|
skillName,
|
|
@@ -77657,7 +77826,7 @@ function ensurePythonEnv(opts) {
|
|
|
77657
77826
|
const e = err;
|
|
77658
77827
|
throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
|
|
77659
77828
|
}
|
|
77660
|
-
|
|
77829
|
+
writeFileSync29(stampPath, targetHash + `
|
|
77661
77830
|
`);
|
|
77662
77831
|
return {
|
|
77663
77832
|
skillName,
|
|
@@ -77675,9 +77844,9 @@ import {
|
|
|
77675
77844
|
copyFileSync as copyFileSync9,
|
|
77676
77845
|
existsSync as existsSync62,
|
|
77677
77846
|
mkdirSync as mkdirSync35,
|
|
77678
|
-
readFileSync as
|
|
77847
|
+
readFileSync as readFileSync56,
|
|
77679
77848
|
rmSync as rmSync14,
|
|
77680
|
-
writeFileSync as
|
|
77849
|
+
writeFileSync as writeFileSync30
|
|
77681
77850
|
} from "node:fs";
|
|
77682
77851
|
import { dirname as dirname17, join as join64 } from "node:path";
|
|
77683
77852
|
import { homedir as homedir38 } from "node:os";
|
|
@@ -77710,7 +77879,7 @@ function hashDepInputs(packageJsonPath) {
|
|
|
77710
77879
|
const hasher = createHash12("sha256");
|
|
77711
77880
|
hasher.update(`package.json
|
|
77712
77881
|
`);
|
|
77713
|
-
hasher.update(
|
|
77882
|
+
hasher.update(readFileSync56(packageJsonPath));
|
|
77714
77883
|
for (const lockName of ALL_LOCKFILES) {
|
|
77715
77884
|
const lockPath = join64(sourceDir, lockName);
|
|
77716
77885
|
if (existsSync62(lockPath)) {
|
|
@@ -77719,7 +77888,7 @@ function hashDepInputs(packageJsonPath) {
|
|
|
77719
77888
|
hasher.update(lockName);
|
|
77720
77889
|
hasher.update(`
|
|
77721
77890
|
`);
|
|
77722
|
-
hasher.update(
|
|
77891
|
+
hasher.update(readFileSync56(lockPath));
|
|
77723
77892
|
}
|
|
77724
77893
|
}
|
|
77725
77894
|
return hasher.digest("hex");
|
|
@@ -77738,7 +77907,7 @@ function ensureNodeEnv(opts) {
|
|
|
77738
77907
|
const binDir = join64(nodeModulesDir, ".bin");
|
|
77739
77908
|
const targetHash = hashDepInputs(packageJsonPath);
|
|
77740
77909
|
if (!force && existsSync62(stampPath) && existsSync62(nodeModulesDir)) {
|
|
77741
|
-
const existingHash =
|
|
77910
|
+
const existingHash = readFileSync56(stampPath, "utf8").trim();
|
|
77742
77911
|
if (existingHash === targetHash) {
|
|
77743
77912
|
return {
|
|
77744
77913
|
skillName,
|
|
@@ -77774,7 +77943,7 @@ function ensureNodeEnv(opts) {
|
|
|
77774
77943
|
const e = err;
|
|
77775
77944
|
throw new NodeEnvError(`Failed to install node deps for skill "${skillName}" with ${installer}: ${e.message}`, e.stderr?.toString());
|
|
77776
77945
|
}
|
|
77777
|
-
|
|
77946
|
+
writeFileSync30(stampPath, targetHash + `
|
|
77778
77947
|
`);
|
|
77779
77948
|
return {
|
|
77780
77949
|
skillName,
|
|
@@ -78757,7 +78926,7 @@ function safeParseInt(value, fallback) {
|
|
|
78757
78926
|
init_helpers();
|
|
78758
78927
|
init_loader();
|
|
78759
78928
|
init_merge();
|
|
78760
|
-
import { copyFileSync as copyFileSync10, existsSync as existsSync65, readFileSync as
|
|
78929
|
+
import { copyFileSync as copyFileSync10, existsSync as existsSync65, readFileSync as readFileSync57, writeFileSync as writeFileSync31 } from "node:fs";
|
|
78761
78930
|
import { join as join66, resolve as resolve39 } from "node:path";
|
|
78762
78931
|
init_schema();
|
|
78763
78932
|
function resolveSoulTargetOrExit(program3, agentName) {
|
|
@@ -78803,7 +78972,7 @@ function registerSoulCommand(program3) {
|
|
|
78803
78972
|
console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
|
|
78804
78973
|
process.exit(1);
|
|
78805
78974
|
}
|
|
78806
|
-
process.stdout.write(
|
|
78975
|
+
process.stdout.write(readFileSync57(t.soulPath, "utf-8"));
|
|
78807
78976
|
}));
|
|
78808
78977
|
cmd.command("reset <agent>").description("Re-seed SOUL.md from the agent's current profile " + "(backs the existing file up to SOUL.md.bak first)").option("-y, --yes", "Skip the confirmation prompt").action(withConfigError(async (agentName, opts) => {
|
|
78809
78978
|
const t = resolveSoulTargetOrExit(program3, agentName);
|
|
@@ -78834,7 +79003,7 @@ function registerSoulCommand(program3) {
|
|
|
78834
79003
|
}
|
|
78835
79004
|
copyFileSync10(t.soulPath, backupPath);
|
|
78836
79005
|
}
|
|
78837
|
-
|
|
79006
|
+
writeFileSync31(t.soulPath, content, "utf-8");
|
|
78838
79007
|
if (backupPath) {
|
|
78839
79008
|
console.log(`soul: re-seeded ${agentName}'s SOUL.md from profile ` + `"${t.profileName}".
|
|
78840
79009
|
` + ` Previous version saved to ${backupPath}`);
|
|
@@ -78848,7 +79017,7 @@ function registerSoulCommand(program3) {
|
|
|
78848
79017
|
// src/cli/debug.ts
|
|
78849
79018
|
init_helpers();
|
|
78850
79019
|
init_loader();
|
|
78851
|
-
import { existsSync as existsSync66, readFileSync as
|
|
79020
|
+
import { existsSync as existsSync66, readFileSync as readFileSync58, readdirSync as readdirSync23, statSync as statSync28 } from "node:fs";
|
|
78852
79021
|
import { resolve as resolve40, join as join67 } from "node:path";
|
|
78853
79022
|
import { createHash as createHash13 } from "node:crypto";
|
|
78854
79023
|
init_merge();
|
|
@@ -78864,7 +79033,7 @@ function readMcpServerNames(agentDir) {
|
|
|
78864
79033
|
if (!existsSync66(mcpPath))
|
|
78865
79034
|
return [];
|
|
78866
79035
|
try {
|
|
78867
|
-
const parsed = JSON.parse(
|
|
79036
|
+
const parsed = JSON.parse(readFileSync58(mcpPath, "utf-8"));
|
|
78868
79037
|
return Object.keys(parsed.mcpServers ?? {});
|
|
78869
79038
|
} catch {
|
|
78870
79039
|
return null;
|
|
@@ -78899,7 +79068,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
|
78899
79068
|
}
|
|
78900
79069
|
function extractLatestUserMessage(transcriptPath) {
|
|
78901
79070
|
try {
|
|
78902
|
-
const content =
|
|
79071
|
+
const content = readFileSync58(transcriptPath, "utf-8");
|
|
78903
79072
|
const lines = content.trim().split(`
|
|
78904
79073
|
`).filter(Boolean);
|
|
78905
79074
|
for (let i = lines.length - 1;i >= 0; i--) {
|
|
@@ -79003,7 +79172,7 @@ function registerDebugCommand(program3) {
|
|
|
79003
79172
|
}
|
|
79004
79173
|
console.log(`=== Append System Prompt (per-session) ===
|
|
79005
79174
|
`);
|
|
79006
|
-
const handoffContent = existsSync66(handoffPath) ?
|
|
79175
|
+
const handoffContent = existsSync66(handoffPath) ? readFileSync58(handoffPath, "utf-8") : "";
|
|
79007
79176
|
if (handoffContent.trim().length > 0) {
|
|
79008
79177
|
console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
|
|
79009
79178
|
console.log(handoffContent);
|
|
@@ -79014,7 +79183,7 @@ function registerDebugCommand(program3) {
|
|
|
79014
79183
|
}
|
|
79015
79184
|
console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
|
|
79016
79185
|
`);
|
|
79017
|
-
const claudeMdContent = existsSync66(claudeMdPath) ?
|
|
79186
|
+
const claudeMdContent = existsSync66(claudeMdPath) ? readFileSync58(claudeMdPath, "utf-8") : "";
|
|
79018
79187
|
if (claudeMdContent.trim().length > 0) {
|
|
79019
79188
|
console.log(`(${formatBytes(claudeMdContent.length)})`);
|
|
79020
79189
|
console.log(claudeMdContent);
|
|
@@ -79025,7 +79194,7 @@ function registerDebugCommand(program3) {
|
|
|
79025
79194
|
}
|
|
79026
79195
|
console.log(`=== Persona (SOUL.md) ===
|
|
79027
79196
|
`);
|
|
79028
|
-
const soulMdContent = existsSync66(soulMdPath) ?
|
|
79197
|
+
const soulMdContent = existsSync66(soulMdPath) ? readFileSync58(soulMdPath, "utf-8") : existsSync66(workspaceSoulMdPath) ? readFileSync58(workspaceSoulMdPath, "utf-8") : "";
|
|
79029
79198
|
if (soulMdContent.trim().length > 0) {
|
|
79030
79199
|
console.log(`(${formatBytes(soulMdContent.length)})`);
|
|
79031
79200
|
console.log(soulMdContent);
|
|
@@ -79089,8 +79258,8 @@ function registerDebugCommand(program3) {
|
|
|
79089
79258
|
const fleetDir = join67(agentsDir, "..", "fleet");
|
|
79090
79259
|
const fleetInvPath = join67(fleetDir, "switchroom-invariants.md");
|
|
79091
79260
|
const fleetClaudePath = join67(fleetDir, "CLAUDE.md");
|
|
79092
|
-
const fleetInvBytes = existsSync66(fleetInvPath) ?
|
|
79093
|
-
const fleetClaudeBytes = existsSync66(fleetClaudePath) ?
|
|
79261
|
+
const fleetInvBytes = existsSync66(fleetInvPath) ? readFileSync58(fleetInvPath, "utf-8").length : 0;
|
|
79262
|
+
const fleetClaudeBytes = existsSync66(fleetClaudePath) ? readFileSync58(fleetClaudePath, "utf-8").length : 0;
|
|
79094
79263
|
const fleetBytes = fleetInvBytes + fleetClaudeBytes;
|
|
79095
79264
|
const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
|
|
79096
79265
|
console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
|
|
@@ -79131,8 +79300,8 @@ import { randomBytes as randomBytes13 } from "node:crypto";
|
|
|
79131
79300
|
// src/worktree/registry.ts
|
|
79132
79301
|
import {
|
|
79133
79302
|
mkdirSync as mkdirSync36,
|
|
79134
|
-
writeFileSync as
|
|
79135
|
-
readFileSync as
|
|
79303
|
+
writeFileSync as writeFileSync32,
|
|
79304
|
+
readFileSync as readFileSync59,
|
|
79136
79305
|
readdirSync as readdirSync24,
|
|
79137
79306
|
unlinkSync as unlinkSync12,
|
|
79138
79307
|
existsSync as existsSync67,
|
|
@@ -79153,14 +79322,14 @@ function writeRecord(record2) {
|
|
|
79153
79322
|
ensureDir2();
|
|
79154
79323
|
const target = recordPath(record2.id);
|
|
79155
79324
|
const tmp = `${target}.tmp${process.pid}`;
|
|
79156
|
-
|
|
79325
|
+
writeFileSync32(tmp, JSON.stringify(record2, null, 2) + `
|
|
79157
79326
|
`, { mode: 384 });
|
|
79158
79327
|
renameSync13(tmp, target);
|
|
79159
79328
|
}
|
|
79160
79329
|
function readRecord(id) {
|
|
79161
79330
|
const path7 = recordPath(id);
|
|
79162
79331
|
try {
|
|
79163
|
-
const raw =
|
|
79332
|
+
const raw = readFileSync59(path7, "utf8");
|
|
79164
79333
|
return JSON.parse(raw);
|
|
79165
79334
|
} catch {
|
|
79166
79335
|
return null;
|
|
@@ -79525,7 +79694,7 @@ import {
|
|
|
79525
79694
|
mkdirSync as mkdirSync38,
|
|
79526
79695
|
readdirSync as readdirSync25,
|
|
79527
79696
|
rmSync as rmSync15,
|
|
79528
|
-
writeFileSync as
|
|
79697
|
+
writeFileSync as writeFileSync33
|
|
79529
79698
|
} from "node:fs";
|
|
79530
79699
|
import { join as join70 } from "node:path";
|
|
79531
79700
|
function encodeCredentialsFilename(email) {
|
|
@@ -79727,7 +79896,7 @@ function writeSeedFile(dir, email, seed) {
|
|
|
79727
79896
|
}
|
|
79728
79897
|
const filename = encodeCredentialsFilename(email);
|
|
79729
79898
|
const filePath = join70(dir, filename);
|
|
79730
|
-
|
|
79899
|
+
writeFileSync33(filePath, JSON.stringify(seed), { mode: 384 });
|
|
79731
79900
|
chmodSync9(filePath, 384);
|
|
79732
79901
|
return filePath;
|
|
79733
79902
|
}
|
|
@@ -79885,7 +80054,7 @@ function registerDriveMcpLauncherCommand(program3) {
|
|
|
79885
80054
|
// src/cli/m365-mcp-launcher.ts
|
|
79886
80055
|
init_scaffold_integration();
|
|
79887
80056
|
import { spawn as spawn6 } from "node:child_process";
|
|
79888
|
-
import { writeFileSync as
|
|
80057
|
+
import { writeFileSync as writeFileSync34, mkdirSync as mkdirSync39 } from "node:fs";
|
|
79889
80058
|
import { dirname as dirname18, join as join71 } from "node:path";
|
|
79890
80059
|
var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
|
|
79891
80060
|
var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
|
|
@@ -79912,7 +80081,7 @@ function writeRefreshHeartbeat(agentName, data) {
|
|
|
79912
80081
|
const path7 = heartbeatPath(agentName);
|
|
79913
80082
|
try {
|
|
79914
80083
|
mkdirSync39(dirname18(path7), { recursive: true });
|
|
79915
|
-
|
|
80084
|
+
writeFileSync34(path7, JSON.stringify(data, null, 2), { mode: 420 });
|
|
79916
80085
|
} catch {}
|
|
79917
80086
|
}
|
|
79918
80087
|
function heartbeatPath(agentName) {
|
|
@@ -80103,7 +80272,7 @@ function registerM365McpLauncherCommand(program3) {
|
|
|
80103
80272
|
// src/cli/notion-mcp-launcher.ts
|
|
80104
80273
|
init_scaffold_integration();
|
|
80105
80274
|
import { spawn as spawn7 } from "node:child_process";
|
|
80106
|
-
import { existsSync as existsSync71, mkdirSync as mkdirSync40, writeFileSync as
|
|
80275
|
+
import { existsSync as existsSync71, mkdirSync as mkdirSync40, writeFileSync as writeFileSync35 } from "node:fs";
|
|
80107
80276
|
import { dirname as dirname19 } from "node:path";
|
|
80108
80277
|
var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
|
|
80109
80278
|
var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
|
|
@@ -80117,7 +80286,7 @@ function defaultWriteHeartbeat(path7, contents) {
|
|
|
80117
80286
|
const dir = dirname19(path7);
|
|
80118
80287
|
if (!existsSync71(dir))
|
|
80119
80288
|
mkdirSync40(dir, { recursive: true });
|
|
80120
|
-
|
|
80289
|
+
writeFileSync35(path7, contents);
|
|
80121
80290
|
} catch {}
|
|
80122
80291
|
}
|
|
80123
80292
|
async function runNotionMcpLauncher(opts, runtime) {
|
|
@@ -80227,7 +80396,7 @@ function registerNotionMcpLauncherCommand(program3) {
|
|
|
80227
80396
|
|
|
80228
80397
|
// src/cli/deliver-file.ts
|
|
80229
80398
|
init_client2();
|
|
80230
|
-
import { readFileSync as
|
|
80399
|
+
import { readFileSync as readFileSync60, statSync as statSync29 } from "node:fs";
|
|
80231
80400
|
import { basename as basename8 } from "node:path";
|
|
80232
80401
|
|
|
80233
80402
|
// src/delivery/onedrive.ts
|
|
@@ -80567,7 +80736,7 @@ async function defaultResolveProvider() {
|
|
|
80567
80736
|
async function runDeliverFile(localPath, deps = {}) {
|
|
80568
80737
|
const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
|
|
80569
80738
|
const sizeOf = deps.fileSize ?? ((p) => statSync29(p).size);
|
|
80570
|
-
const read = deps.readFile ?? ((p) => new Uint8Array(
|
|
80739
|
+
const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync60(p)));
|
|
80571
80740
|
const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
|
|
80572
80741
|
let size;
|
|
80573
80742
|
try {
|
|
@@ -80857,7 +81026,7 @@ async function fetchToken(vaultKey) {
|
|
|
80857
81026
|
|
|
80858
81027
|
// src/cli/apply.ts
|
|
80859
81028
|
init_source();
|
|
80860
|
-
import { accessSync as accessSync3, chownSync as chownSync5, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync74, mkdirSync as mkdirSync42, readFileSync as
|
|
81029
|
+
import { accessSync as accessSync3, chownSync as chownSync5, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync74, mkdirSync as mkdirSync42, readFileSync as readFileSync62, readdirSync as readdirSync26, renameSync as renameSync14, writeFileSync as writeFileSync37 } from "node:fs";
|
|
80861
81030
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
80862
81031
|
import { spawnSync as childSpawnSync } from "node:child_process";
|
|
80863
81032
|
import readline from "node:readline";
|
|
@@ -81254,7 +81423,7 @@ init_loader();
|
|
|
81254
81423
|
init_loader();
|
|
81255
81424
|
|
|
81256
81425
|
// src/cli/update-prompt-hook.ts
|
|
81257
|
-
import { existsSync as existsSync72, readFileSync as
|
|
81426
|
+
import { existsSync as existsSync72, readFileSync as readFileSync61, writeFileSync as writeFileSync36, chmodSync as chmodSync10, mkdirSync as mkdirSync41 } from "node:fs";
|
|
81258
81427
|
import { join as join72 } from "node:path";
|
|
81259
81428
|
var HOOK_FILENAME = "update-card-on-prompt.sh";
|
|
81260
81429
|
function updatePromptHookScript() {
|
|
@@ -81326,9 +81495,9 @@ function installUpdatePromptHook(agentDir) {
|
|
|
81326
81495
|
const scriptPath = join72(hooksDir, HOOK_FILENAME);
|
|
81327
81496
|
const desired = updatePromptHookScript();
|
|
81328
81497
|
let installed = false;
|
|
81329
|
-
const existing = existsSync72(scriptPath) ?
|
|
81498
|
+
const existing = existsSync72(scriptPath) ? readFileSync61(scriptPath, "utf-8") : "";
|
|
81330
81499
|
if (existing !== desired) {
|
|
81331
|
-
|
|
81500
|
+
writeFileSync36(scriptPath, desired, { mode: 493 });
|
|
81332
81501
|
chmodSync10(scriptPath, 493);
|
|
81333
81502
|
installed = true;
|
|
81334
81503
|
} else {
|
|
@@ -81340,7 +81509,7 @@ function installUpdatePromptHook(agentDir) {
|
|
|
81340
81509
|
if (!existsSync72(settingsPath)) {
|
|
81341
81510
|
return { scriptPath, settingsPath, installed };
|
|
81342
81511
|
}
|
|
81343
|
-
const raw =
|
|
81512
|
+
const raw = readFileSync61(settingsPath, "utf-8");
|
|
81344
81513
|
let parsed;
|
|
81345
81514
|
try {
|
|
81346
81515
|
parsed = JSON.parse(raw);
|
|
@@ -81373,7 +81542,7 @@ function installUpdatePromptHook(agentDir) {
|
|
|
81373
81542
|
});
|
|
81374
81543
|
hooks.UserPromptSubmit = list2;
|
|
81375
81544
|
parsed.hooks = hooks;
|
|
81376
|
-
|
|
81545
|
+
writeFileSync36(settingsPath, JSON.stringify(parsed, null, 2) + `
|
|
81377
81546
|
`, { mode: 384 });
|
|
81378
81547
|
installed = true;
|
|
81379
81548
|
}
|
|
@@ -81496,24 +81665,24 @@ async function ensureHostMountSources(config) {
|
|
|
81496
81665
|
}
|
|
81497
81666
|
const autoUnlockPath = join74(home2, ".switchroom", "vault-auto-unlock");
|
|
81498
81667
|
if (!existsSync74(autoUnlockPath)) {
|
|
81499
|
-
|
|
81668
|
+
writeFileSync37(autoUnlockPath, "", { mode: 384 });
|
|
81500
81669
|
}
|
|
81501
81670
|
const auditLogPath = join74(home2, ".switchroom", "vault-audit.log");
|
|
81502
81671
|
if (!existsSync74(auditLogPath)) {
|
|
81503
|
-
|
|
81672
|
+
writeFileSync37(auditLogPath, "", { mode: 420 });
|
|
81504
81673
|
}
|
|
81505
81674
|
const grantsDbPath = join74(home2, ".switchroom", "vault-grants.db");
|
|
81506
81675
|
if (!existsSync74(grantsDbPath)) {
|
|
81507
|
-
|
|
81676
|
+
writeFileSync37(grantsDbPath, "", { mode: 384 });
|
|
81508
81677
|
}
|
|
81509
81678
|
const hostdAuditLogPath = join74(home2, ".switchroom", "host-control-audit.log");
|
|
81510
81679
|
if (!existsSync74(hostdAuditLogPath)) {
|
|
81511
|
-
|
|
81680
|
+
writeFileSync37(hostdAuditLogPath, "", { mode: 420 });
|
|
81512
81681
|
}
|
|
81513
81682
|
for (const name of Object.keys(config.agents)) {
|
|
81514
81683
|
const tokenPath = join74(home2, ".switchroom", "agents", name, ".vault-token");
|
|
81515
81684
|
if (!existsSync74(tokenPath)) {
|
|
81516
|
-
|
|
81685
|
+
writeFileSync37(tokenPath, "", { mode: 384 });
|
|
81517
81686
|
}
|
|
81518
81687
|
try {
|
|
81519
81688
|
const uid = allocateAgentUid(name);
|
|
@@ -81524,13 +81693,13 @@ async function ensureHostMountSources(config) {
|
|
|
81524
81693
|
await mkdir2(fleetDir, { recursive: true });
|
|
81525
81694
|
const invariantsPath = join74(fleetDir, "switchroom-invariants.md");
|
|
81526
81695
|
const invariantsCanonical = renderFleetInvariants();
|
|
81527
|
-
const invariantsCurrent = existsSync74(invariantsPath) ?
|
|
81696
|
+
const invariantsCurrent = existsSync74(invariantsPath) ? readFileSync62(invariantsPath, "utf-8") : null;
|
|
81528
81697
|
if (invariantsCurrent !== invariantsCanonical) {
|
|
81529
|
-
|
|
81698
|
+
writeFileSync37(invariantsPath, invariantsCanonical, { mode: 420 });
|
|
81530
81699
|
}
|
|
81531
81700
|
const fleetClaudePath = join74(fleetDir, "CLAUDE.md");
|
|
81532
81701
|
if (!existsSync74(fleetClaudePath)) {
|
|
81533
|
-
|
|
81702
|
+
writeFileSync37(fleetClaudePath, [
|
|
81534
81703
|
"# Switchroom fleet defaults",
|
|
81535
81704
|
"",
|
|
81536
81705
|
"Operator-owned fleet brain. Every agent reads this via",
|
|
@@ -81622,7 +81791,7 @@ function writeInstallTypeCache(homeDir = homedir43()) {
|
|
|
81622
81791
|
detected_at: new Date().toISOString(),
|
|
81623
81792
|
source_paths: ctx.source_paths
|
|
81624
81793
|
};
|
|
81625
|
-
|
|
81794
|
+
writeFileSync37(tmp, JSON.stringify(payload, null, 2), { mode: 420 });
|
|
81626
81795
|
renameSync14(tmp, out);
|
|
81627
81796
|
return out;
|
|
81628
81797
|
}
|
|
@@ -81818,10 +81987,10 @@ Done. Scaffolded ${scaffolded}/${allAgentNames.length} agents.
|
|
|
81818
81987
|
};
|
|
81819
81988
|
}
|
|
81820
81989
|
function formatScaffoldFailureResolution(failures, scaffolded, agentsTotal) {
|
|
81821
|
-
const
|
|
81990
|
+
const fail3 = failures.length;
|
|
81822
81991
|
const lines = [];
|
|
81823
81992
|
lines.push("");
|
|
81824
|
-
lines.push(`ERROR: Scaffolded ${scaffolded}/${agentsTotal} agents. ${
|
|
81993
|
+
lines.push(`ERROR: Scaffolded ${scaffolded}/${agentsTotal} agents. ${fail3} failed.`);
|
|
81825
81994
|
lines.push("");
|
|
81826
81995
|
lines.push("Per-agent state dirs are mode 0700 owned by per-agent UIDs (the v0.7+");
|
|
81827
81996
|
lines.push("docker model). The operator cannot write into them without privilege");
|
|
@@ -81854,7 +82023,7 @@ function copyExampleConfig2(name) {
|
|
|
81854
82023
|
}
|
|
81855
82024
|
const embedded = EMBEDDED_EXAMPLES[name];
|
|
81856
82025
|
if (embedded !== undefined) {
|
|
81857
|
-
|
|
82026
|
+
writeFileSync37(dest, embedded, { encoding: "utf8" });
|
|
81858
82027
|
console.log(source_default.green(`Copied ${name}.yaml -> switchroom.yaml`));
|
|
81859
82028
|
return;
|
|
81860
82029
|
}
|
|
@@ -82049,7 +82218,7 @@ function runRedactStdin() {
|
|
|
82049
82218
|
}
|
|
82050
82219
|
|
|
82051
82220
|
// src/cli/status-ask.ts
|
|
82052
|
-
import { readFileSync as
|
|
82221
|
+
import { readFileSync as readFileSync63, existsSync as existsSync75, readdirSync as readdirSync27 } from "node:fs";
|
|
82053
82222
|
import { join as join75 } from "node:path";
|
|
82054
82223
|
import { homedir as homedir44 } from "node:os";
|
|
82055
82224
|
|
|
@@ -82325,7 +82494,7 @@ function runReport(opts) {
|
|
|
82325
82494
|
for (const src of sources) {
|
|
82326
82495
|
let content;
|
|
82327
82496
|
try {
|
|
82328
|
-
content =
|
|
82497
|
+
content = readFileSync63(src.path, "utf-8");
|
|
82329
82498
|
} catch (err) {
|
|
82330
82499
|
process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
|
|
82331
82500
|
`);
|
|
@@ -82430,7 +82599,7 @@ import {
|
|
|
82430
82599
|
mkdirSync as mkdirSync43,
|
|
82431
82600
|
openSync as openSync13,
|
|
82432
82601
|
readdirSync as readdirSync28,
|
|
82433
|
-
readFileSync as
|
|
82602
|
+
readFileSync as readFileSync64,
|
|
82434
82603
|
renameSync as renameSync15,
|
|
82435
82604
|
statSync as statSync30,
|
|
82436
82605
|
unlinkSync as unlinkSync14,
|
|
@@ -82554,7 +82723,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
|
|
|
82554
82723
|
continue;
|
|
82555
82724
|
const full = join76(paths.skillsDir, name);
|
|
82556
82725
|
try {
|
|
82557
|
-
const raw =
|
|
82726
|
+
const raw = readFileSync64(full, "utf-8");
|
|
82558
82727
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
82559
82728
|
out.push({ slug, path: full, raw });
|
|
82560
82729
|
} catch {}
|
|
@@ -82581,7 +82750,7 @@ function listOverlayEntries(agent, opts = {}) {
|
|
|
82581
82750
|
continue;
|
|
82582
82751
|
const full = join76(paths.scheduleDir, name);
|
|
82583
82752
|
try {
|
|
82584
|
-
const raw =
|
|
82753
|
+
const raw = readFileSync64(full, "utf-8");
|
|
82585
82754
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
82586
82755
|
out.push({ slug, path: full, raw });
|
|
82587
82756
|
} catch {}
|
|
@@ -82729,10 +82898,10 @@ import {
|
|
|
82729
82898
|
mkdirSync as mkdirSync44,
|
|
82730
82899
|
openSync as openSync14,
|
|
82731
82900
|
readdirSync as readdirSync29,
|
|
82732
|
-
readFileSync as
|
|
82901
|
+
readFileSync as readFileSync65,
|
|
82733
82902
|
renameSync as renameSync16,
|
|
82734
82903
|
unlinkSync as unlinkSync15,
|
|
82735
|
-
writeFileSync as
|
|
82904
|
+
writeFileSync as writeFileSync38,
|
|
82736
82905
|
writeSync as writeSync9
|
|
82737
82906
|
} from "node:fs";
|
|
82738
82907
|
import { join as join77 } from "node:path";
|
|
@@ -82775,7 +82944,7 @@ function stagePendingScheduleEntry(opts) {
|
|
|
82775
82944
|
}
|
|
82776
82945
|
renameSync16(yamlTmp, yamlPath);
|
|
82777
82946
|
}
|
|
82778
|
-
|
|
82947
|
+
writeFileSync38(metaPath, JSON.stringify(meta, null, 2) + `
|
|
82779
82948
|
`, { mode: 384 });
|
|
82780
82949
|
return { stageId, yamlPath, metaPath };
|
|
82781
82950
|
}
|
|
@@ -82793,7 +82962,7 @@ function listPendingScheduleEntries(agent, opts = {}) {
|
|
|
82793
82962
|
if (!existsSync77(yamlPath))
|
|
82794
82963
|
continue;
|
|
82795
82964
|
try {
|
|
82796
|
-
const meta = JSON.parse(
|
|
82965
|
+
const meta = JSON.parse(readFileSync65(metaPath, "utf-8"));
|
|
82797
82966
|
if (meta?.v !== 1 || typeof meta.stage_id !== "string")
|
|
82798
82967
|
continue;
|
|
82799
82968
|
out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
|
|
@@ -82831,7 +83000,7 @@ function denyPendingScheduleEntry(opts) {
|
|
|
82831
83000
|
}
|
|
82832
83001
|
|
|
82833
83002
|
// src/cli/agent-config-write.ts
|
|
82834
|
-
import { existsSync as existsSync78, readFileSync as
|
|
83003
|
+
import { existsSync as existsSync78, readFileSync as readFileSync66 } from "node:fs";
|
|
82835
83004
|
import { execFileSync as execFileSync25 } from "node:child_process";
|
|
82836
83005
|
|
|
82837
83006
|
// src/scheduler/schedule-report.ts
|
|
@@ -83199,7 +83368,7 @@ function scheduleRemove(opts) {
|
|
|
83199
83368
|
let priorContent = null;
|
|
83200
83369
|
try {
|
|
83201
83370
|
if (existsSync78(match.path))
|
|
83202
|
-
priorContent =
|
|
83371
|
+
priorContent = readFileSync66(match.path, "utf-8");
|
|
83203
83372
|
} catch {}
|
|
83204
83373
|
deleteOverlayEntry(agent, match.slug, { root: opts.root });
|
|
83205
83374
|
const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
|
|
@@ -83402,7 +83571,7 @@ function registerAgentConfigWriteCommands(program3) {
|
|
|
83402
83571
|
}
|
|
83403
83572
|
let blob;
|
|
83404
83573
|
if (opts.jsonl) {
|
|
83405
|
-
blob = existsSync78(opts.jsonl) ?
|
|
83574
|
+
blob = existsSync78(opts.jsonl) ? readFileSync66(opts.jsonl, "utf-8") : "";
|
|
83406
83575
|
} else {
|
|
83407
83576
|
try {
|
|
83408
83577
|
blob = execFileSync25("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
|
|
@@ -83682,13 +83851,13 @@ import {
|
|
|
83682
83851
|
mkdirSync as mkdirSync45,
|
|
83683
83852
|
mkdtempSync as mkdtempSync5,
|
|
83684
83853
|
openSync as openSync15,
|
|
83685
|
-
readFileSync as
|
|
83854
|
+
readFileSync as readFileSync67,
|
|
83686
83855
|
readdirSync as readdirSync30,
|
|
83687
83856
|
realpathSync as realpathSync7,
|
|
83688
83857
|
renameSync as renameSync17,
|
|
83689
83858
|
rmSync as rmSync16,
|
|
83690
83859
|
statSync as statSync31,
|
|
83691
|
-
writeFileSync as
|
|
83860
|
+
writeFileSync as writeFileSync39
|
|
83692
83861
|
} from "node:fs";
|
|
83693
83862
|
import { tmpdir as tmpdir5, homedir as homedir45 } from "node:os";
|
|
83694
83863
|
import { dirname as dirname23, join as join79, relative as relative2, resolve as resolve46 } from "node:path";
|
|
@@ -83918,7 +84087,7 @@ function isTarballPath(p) {
|
|
|
83918
84087
|
function loadFromDir(dir) {
|
|
83919
84088
|
const abs = realpathSync7(dir);
|
|
83920
84089
|
if (!statSync31(abs).isDirectory()) {
|
|
83921
|
-
|
|
84090
|
+
fail3(`--from path is not a directory: ${dir}`);
|
|
83922
84091
|
}
|
|
83923
84092
|
const files = {};
|
|
83924
84093
|
const walk2 = (sub) => {
|
|
@@ -83927,14 +84096,14 @@ function loadFromDir(dir) {
|
|
|
83927
84096
|
const full = join79(sub, ent.name);
|
|
83928
84097
|
const rel = relative2(abs, full);
|
|
83929
84098
|
if (ent.isSymbolicLink()) {
|
|
83930
|
-
|
|
84099
|
+
fail3(`refusing to read symlink inside --from dir: ${rel}`);
|
|
83931
84100
|
}
|
|
83932
84101
|
if (ent.isDirectory()) {
|
|
83933
84102
|
walk2(full);
|
|
83934
84103
|
continue;
|
|
83935
84104
|
}
|
|
83936
84105
|
if (ent.isFile()) {
|
|
83937
|
-
const buf =
|
|
84106
|
+
const buf = readFileSync67(full);
|
|
83938
84107
|
files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
|
|
83939
84108
|
}
|
|
83940
84109
|
}
|
|
@@ -83950,13 +84119,13 @@ function loadFromTarball(tarPath) {
|
|
|
83950
84119
|
stdio: ["ignore", "pipe", "pipe"]
|
|
83951
84120
|
});
|
|
83952
84121
|
if (list2.status !== 0) {
|
|
83953
|
-
|
|
84122
|
+
fail3(`tar list failed (exit ${list2.status}): ${(list2.stderr ?? "").trim()}`);
|
|
83954
84123
|
}
|
|
83955
84124
|
const entries = (list2.stdout ?? "").split(`
|
|
83956
84125
|
`).map((s) => s.trim()).filter((s) => s.length > 0 && !s.endsWith("/"));
|
|
83957
84126
|
for (const entry of entries) {
|
|
83958
84127
|
if (!validateRelPath(entry)) {
|
|
83959
|
-
|
|
84128
|
+
fail3(`tarball contains disallowed path: ${JSON.stringify(entry)} \u2014 ` + `refusing to extract before any file is written`);
|
|
83960
84129
|
}
|
|
83961
84130
|
}
|
|
83962
84131
|
const staging = mkdtempSync5(join79(tmpdir5(), "skill-apply-extract-"));
|
|
@@ -83973,7 +84142,7 @@ function loadFromTarball(tarPath) {
|
|
|
83973
84142
|
], { stdio: "pipe" });
|
|
83974
84143
|
if (r.status !== 0) {
|
|
83975
84144
|
const stderr = r.stderr?.toString("utf-8") ?? "(no stderr)";
|
|
83976
|
-
|
|
84145
|
+
fail3(`tar extraction failed (exit ${r.status}): ${stderr.trim()}`);
|
|
83977
84146
|
}
|
|
83978
84147
|
return loadFromDir(staging);
|
|
83979
84148
|
} finally {
|
|
@@ -83983,13 +84152,13 @@ function loadFromTarball(tarPath) {
|
|
|
83983
84152
|
}
|
|
83984
84153
|
}
|
|
83985
84154
|
function loadSingleFile(filePath) {
|
|
83986
|
-
const content =
|
|
84155
|
+
const content = readFileSync67(filePath, "utf-8");
|
|
83987
84156
|
return { "SKILL.md": content };
|
|
83988
84157
|
}
|
|
83989
84158
|
function loadFromStdin() {
|
|
83990
84159
|
const content = readStdinSync();
|
|
83991
84160
|
if (content.length === 0) {
|
|
83992
|
-
|
|
84161
|
+
fail3("no content on stdin; either pipe SKILL.md content in or pass --from");
|
|
83993
84162
|
}
|
|
83994
84163
|
return { "SKILL.md": content };
|
|
83995
84164
|
}
|
|
@@ -84048,7 +84217,7 @@ function validatePayload(name, files) {
|
|
|
84048
84217
|
const tmp = mkdtempSync5(join79(tmpdir5(), "skill-apply-py-"));
|
|
84049
84218
|
const tmpPy = join79(tmp, "check.py");
|
|
84050
84219
|
try {
|
|
84051
|
-
|
|
84220
|
+
writeFileSync39(tmpPy, content);
|
|
84052
84221
|
const r = spawnSync11("python3", ["-m", "py_compile", tmpPy], {
|
|
84053
84222
|
encoding: "utf-8"
|
|
84054
84223
|
});
|
|
@@ -84074,7 +84243,7 @@ function diffSummary(currentDir, files) {
|
|
|
84074
84243
|
if (ent.isDirectory()) {
|
|
84075
84244
|
walk2(full);
|
|
84076
84245
|
} else if (ent.isFile()) {
|
|
84077
|
-
currentFiles[rel.replace(/\\/g, "/")] =
|
|
84246
|
+
currentFiles[rel.replace(/\\/g, "/")] = readFileSync67(full, "utf-8");
|
|
84078
84247
|
}
|
|
84079
84248
|
}
|
|
84080
84249
|
};
|
|
@@ -84114,7 +84283,7 @@ function writePayload(poolDir, name, files) {
|
|
|
84114
84283
|
}
|
|
84115
84284
|
} catch {}
|
|
84116
84285
|
if (targetIsSymlink) {
|
|
84117
|
-
|
|
84286
|
+
fail3(`refusing to overwrite symlink at ${target}; investigate manually`);
|
|
84118
84287
|
}
|
|
84119
84288
|
const staging = mkdtempSync5(join79(poolDir, `.skill-apply-stage-${name}-`));
|
|
84120
84289
|
let oldRename = null;
|
|
@@ -84124,7 +84293,7 @@ function writePayload(poolDir, name, files) {
|
|
|
84124
84293
|
mkdirSync45(dirname23(full), { recursive: true, mode: 493 });
|
|
84125
84294
|
const fd = openSync15(full, "wx");
|
|
84126
84295
|
try {
|
|
84127
|
-
|
|
84296
|
+
writeFileSync39(fd, content);
|
|
84128
84297
|
} finally {
|
|
84129
84298
|
closeSync15(fd);
|
|
84130
84299
|
}
|
|
@@ -84162,7 +84331,7 @@ function writePayload(poolDir, name, files) {
|
|
|
84162
84331
|
throw err2;
|
|
84163
84332
|
}
|
|
84164
84333
|
}
|
|
84165
|
-
function
|
|
84334
|
+
function fail3(msg) {
|
|
84166
84335
|
console.error(source_default.red(`error: ${msg}`));
|
|
84167
84336
|
process.exit(2);
|
|
84168
84337
|
}
|
|
@@ -84175,7 +84344,7 @@ function registerSkillCommand(program3) {
|
|
|
84175
84344
|
} else {
|
|
84176
84345
|
const fromPath = resolve46(opts.from);
|
|
84177
84346
|
if (!existsSync80(fromPath)) {
|
|
84178
|
-
|
|
84347
|
+
fail3(`--from path does not exist: ${opts.from}`);
|
|
84179
84348
|
}
|
|
84180
84349
|
const st = statSync31(fromPath);
|
|
84181
84350
|
if (st.isDirectory()) {
|
|
@@ -84185,7 +84354,7 @@ function registerSkillCommand(program3) {
|
|
|
84185
84354
|
} else if (fromPath.endsWith(".md")) {
|
|
84186
84355
|
files = loadSingleFile(fromPath);
|
|
84187
84356
|
} else {
|
|
84188
|
-
|
|
84357
|
+
fail3(`--from must be a directory, a .tar/.tar.gz/.tgz tarball, or a ` + `.md file. Got: ${opts.from}`);
|
|
84189
84358
|
}
|
|
84190
84359
|
}
|
|
84191
84360
|
const v = validatePayload(name, files);
|
|
@@ -84234,13 +84403,13 @@ import {
|
|
|
84234
84403
|
mkdirSync as mkdirSync46,
|
|
84235
84404
|
mkdtempSync as mkdtempSync6,
|
|
84236
84405
|
openSync as openSync16,
|
|
84237
|
-
readFileSync as
|
|
84406
|
+
readFileSync as readFileSync68,
|
|
84238
84407
|
readdirSync as readdirSync31,
|
|
84239
84408
|
renameSync as renameSync18,
|
|
84240
84409
|
rmSync as rmSync17,
|
|
84241
84410
|
statSync as statSync32,
|
|
84242
84411
|
utimesSync,
|
|
84243
|
-
writeFileSync as
|
|
84412
|
+
writeFileSync as writeFileSync40
|
|
84244
84413
|
} from "node:fs";
|
|
84245
84414
|
import { dirname as dirname24, join as join80, relative as relative3, resolve as resolve47 } from "node:path";
|
|
84246
84415
|
import { homedir as homedir46, tmpdir as tmpdir6 } from "node:os";
|
|
@@ -84316,7 +84485,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
84316
84485
|
if (ent.isDirectory())
|
|
84317
84486
|
walk2(s, d);
|
|
84318
84487
|
else if (ent.isFile()) {
|
|
84319
|
-
|
|
84488
|
+
writeFileSync40(d, readFileSync68(s));
|
|
84320
84489
|
}
|
|
84321
84490
|
}
|
|
84322
84491
|
};
|
|
@@ -84331,7 +84500,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
84331
84500
|
`));
|
|
84332
84501
|
}
|
|
84333
84502
|
}
|
|
84334
|
-
function
|
|
84503
|
+
function fail4(msg, exit = 2) {
|
|
84335
84504
|
console.error(source_default.red(`error: ${msg}`));
|
|
84336
84505
|
process.exit(exit);
|
|
84337
84506
|
}
|
|
@@ -84339,10 +84508,10 @@ function resolveAgent(opts) {
|
|
|
84339
84508
|
const fromEnv = process.env.SWITCHROOM_AGENT_NAME;
|
|
84340
84509
|
const agent = opts.agent ?? fromEnv;
|
|
84341
84510
|
if (!agent) {
|
|
84342
|
-
|
|
84511
|
+
fail4("agent name required: pass --agent <name>, or set SWITCHROOM_AGENT_NAME " + "in the calling environment (set by switchroom for in-container agents).");
|
|
84343
84512
|
}
|
|
84344
84513
|
if (!SKILL_SLUG_RE.test(agent)) {
|
|
84345
|
-
|
|
84514
|
+
fail4(`agent name has invalid shape: ${JSON.stringify(agent)}`);
|
|
84346
84515
|
}
|
|
84347
84516
|
return agent;
|
|
84348
84517
|
}
|
|
@@ -84380,14 +84549,14 @@ function readStdinSync2() {
|
|
|
84380
84549
|
function loadFromDir2(dir) {
|
|
84381
84550
|
const abs = resolve47(dir);
|
|
84382
84551
|
if (!statSync32(abs).isDirectory()) {
|
|
84383
|
-
|
|
84552
|
+
fail4(`--from path is not a directory: ${dir}`);
|
|
84384
84553
|
}
|
|
84385
84554
|
const files = {};
|
|
84386
84555
|
const walk2 = (sub) => {
|
|
84387
84556
|
for (const ent of readdirSync31(sub, { withFileTypes: true })) {
|
|
84388
84557
|
const full = join80(sub, ent.name);
|
|
84389
84558
|
if (ent.isSymbolicLink()) {
|
|
84390
|
-
|
|
84559
|
+
fail4(`refusing to read symlink in --from dir: ${relative3(abs, full)}`);
|
|
84391
84560
|
}
|
|
84392
84561
|
if (ent.isDirectory()) {
|
|
84393
84562
|
walk2(full);
|
|
@@ -84395,7 +84564,7 @@ function loadFromDir2(dir) {
|
|
|
84395
84564
|
}
|
|
84396
84565
|
if (ent.isFile()) {
|
|
84397
84566
|
const rel = relative3(abs, full).replace(/\\/g, "/");
|
|
84398
|
-
files[rel] =
|
|
84567
|
+
files[rel] = readFileSync68(full, "utf-8");
|
|
84399
84568
|
}
|
|
84400
84569
|
}
|
|
84401
84570
|
};
|
|
@@ -84405,7 +84574,7 @@ function loadFromDir2(dir) {
|
|
|
84405
84574
|
function loadFromStdin2() {
|
|
84406
84575
|
const raw = readStdinSync2();
|
|
84407
84576
|
if (raw.length === 0) {
|
|
84408
|
-
|
|
84577
|
+
fail4("no content on stdin; pipe a SKILL.md or JSON file-map");
|
|
84409
84578
|
}
|
|
84410
84579
|
const trimmed = raw.trimStart();
|
|
84411
84580
|
if (trimmed.startsWith("{")) {
|
|
@@ -84413,15 +84582,15 @@ function loadFromStdin2() {
|
|
|
84413
84582
|
try {
|
|
84414
84583
|
parsed = JSON.parse(raw);
|
|
84415
84584
|
} catch (err2) {
|
|
84416
|
-
|
|
84585
|
+
fail4(`stdin starts with '{' but is not valid JSON: ${err2.message}`);
|
|
84417
84586
|
}
|
|
84418
84587
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
84419
|
-
|
|
84588
|
+
fail4("stdin JSON must be an object of {path: content, ...}");
|
|
84420
84589
|
}
|
|
84421
84590
|
const files = {};
|
|
84422
84591
|
for (const [k, v] of Object.entries(parsed)) {
|
|
84423
84592
|
if (typeof v !== "string") {
|
|
84424
|
-
|
|
84593
|
+
fail4(`stdin JSON: value for ${JSON.stringify(k)} must be a string`);
|
|
84425
84594
|
}
|
|
84426
84595
|
files[k] = v;
|
|
84427
84596
|
}
|
|
@@ -84441,7 +84610,7 @@ function behavioralValidate(files) {
|
|
|
84441
84610
|
const tmp = mkdtempSync6(join80(tmpdir6(), "skill-personal-py-"));
|
|
84442
84611
|
const tmpPy = join80(tmp, "check.py");
|
|
84443
84612
|
try {
|
|
84444
|
-
|
|
84613
|
+
writeFileSync40(tmpPy, content);
|
|
84445
84614
|
const r = spawnSync12("python3", ["-m", "py_compile", tmpPy], {
|
|
84446
84615
|
encoding: "utf-8"
|
|
84447
84616
|
});
|
|
@@ -84481,7 +84650,7 @@ function writePersonalSkill(targetDir, files) {
|
|
|
84481
84650
|
}
|
|
84482
84651
|
} catch {}
|
|
84483
84652
|
if (targetIsSymlink) {
|
|
84484
|
-
|
|
84653
|
+
fail4(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
|
|
84485
84654
|
}
|
|
84486
84655
|
mkdirSync46(dirname24(targetDir), { recursive: true, mode: 493 });
|
|
84487
84656
|
const staging = mkdtempSync6(join80(dirname24(targetDir), `.skill-personal-stage-`));
|
|
@@ -84492,7 +84661,7 @@ function writePersonalSkill(targetDir, files) {
|
|
|
84492
84661
|
mkdirSync46(dirname24(full), { recursive: true, mode: 493 });
|
|
84493
84662
|
const fd = openSync16(full, "wx");
|
|
84494
84663
|
try {
|
|
84495
|
-
|
|
84664
|
+
writeFileSync40(fd, content);
|
|
84496
84665
|
} finally {
|
|
84497
84666
|
closeSync16(fd);
|
|
84498
84667
|
}
|
|
@@ -84533,7 +84702,7 @@ function writePersonalSkill(targetDir, files) {
|
|
|
84533
84702
|
function loadValidateWrite(agentsRoot, agent, name, files, ensureNew) {
|
|
84534
84703
|
sweepTrash(agentsRoot, agent);
|
|
84535
84704
|
if (!SKILL_SLUG_RE.test(name)) {
|
|
84536
|
-
|
|
84705
|
+
fail4(`skill name must match ${SKILL_SLUG_RE.source}: got ${JSON.stringify(name)}`);
|
|
84537
84706
|
}
|
|
84538
84707
|
const target = personalSkillDir(agentsRoot, agent, name);
|
|
84539
84708
|
const exists = (() => {
|
|
@@ -84545,10 +84714,10 @@ function loadValidateWrite(agentsRoot, agent, name, files, ensureNew) {
|
|
|
84545
84714
|
}
|
|
84546
84715
|
})();
|
|
84547
84716
|
if (ensureNew && exists) {
|
|
84548
|
-
|
|
84717
|
+
fail4(`personal skill ${JSON.stringify(name)} already exists for agent ${JSON.stringify(agent)}. ` + `Use \`skill edit-personal\` to overwrite, or \`skill remove-personal\` first.`, 9);
|
|
84549
84718
|
}
|
|
84550
84719
|
if (!ensureNew && !exists) {
|
|
84551
|
-
|
|
84720
|
+
fail4(`personal skill ${JSON.stringify(name)} does not exist for agent ${JSON.stringify(agent)}. ` + `Use \`skill init-personal\` to create it.`, 9);
|
|
84552
84721
|
}
|
|
84553
84722
|
const v = validateSkillBundle(name, files);
|
|
84554
84723
|
if (!v.ok) {
|
|
@@ -84574,16 +84743,16 @@ function loadFiles(opts) {
|
|
|
84574
84743
|
}
|
|
84575
84744
|
const p = resolve47(opts.from);
|
|
84576
84745
|
if (!existsSync81(p)) {
|
|
84577
|
-
|
|
84746
|
+
fail4(`--from path does not exist: ${opts.from}`);
|
|
84578
84747
|
}
|
|
84579
84748
|
const st = statSync32(p);
|
|
84580
84749
|
if (st.isDirectory()) {
|
|
84581
84750
|
return loadFromDir2(p);
|
|
84582
84751
|
}
|
|
84583
84752
|
if (p.endsWith(".md")) {
|
|
84584
|
-
return { "SKILL.md":
|
|
84753
|
+
return { "SKILL.md": readFileSync68(p, "utf-8") };
|
|
84585
84754
|
}
|
|
84586
|
-
|
|
84755
|
+
fail4(`--from must be a directory or a .md file. Got: ${opts.from}`);
|
|
84587
84756
|
}
|
|
84588
84757
|
function initPersonalAction(name, opts) {
|
|
84589
84758
|
const agent = resolveAgent(opts);
|
|
@@ -84629,18 +84798,18 @@ function defaultBundledRoot() {
|
|
|
84629
84798
|
function resolveCloneSource(source, opts) {
|
|
84630
84799
|
const m = CLONE_SOURCE_RE.exec(source);
|
|
84631
84800
|
if (!m) {
|
|
84632
|
-
|
|
84801
|
+
fail4(`source must be \`shared:<name>\` or \`bundled:<name>\` (got ${JSON.stringify(source)})`);
|
|
84633
84802
|
}
|
|
84634
84803
|
const tier = m[1];
|
|
84635
84804
|
const slug = m[2];
|
|
84636
84805
|
const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
|
|
84637
84806
|
const dir = join80(root, slug);
|
|
84638
84807
|
if (!existsSync81(dir)) {
|
|
84639
|
-
|
|
84808
|
+
fail4(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
|
|
84640
84809
|
}
|
|
84641
84810
|
const st = lstatSync9(dir);
|
|
84642
84811
|
if (st.isSymbolicLink()) {
|
|
84643
|
-
|
|
84812
|
+
fail4(`clone source ${JSON.stringify(source)} is a symlink at ${dir}; ` + `point clone at the canonical pool path instead`);
|
|
84644
84813
|
}
|
|
84645
84814
|
return { tier, slug, dir };
|
|
84646
84815
|
}
|
|
@@ -84667,10 +84836,10 @@ function readSourceFiles(dir) {
|
|
|
84667
84836
|
try {
|
|
84668
84837
|
const st = lstatSync9(full);
|
|
84669
84838
|
if (st.size > CLONE_MAX_FILE_BYTES) {
|
|
84670
|
-
|
|
84839
|
+
fail4(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
|
|
84671
84840
|
}
|
|
84672
84841
|
} catch {}
|
|
84673
|
-
files[rel] =
|
|
84842
|
+
files[rel] = readFileSync68(full, "utf-8");
|
|
84674
84843
|
}
|
|
84675
84844
|
}
|
|
84676
84845
|
};
|
|
@@ -84701,11 +84870,11 @@ function clonePersonalAction(source, opts) {
|
|
|
84701
84870
|
const src = resolveCloneSource(source, opts);
|
|
84702
84871
|
const newName = opts.name ?? src.slug;
|
|
84703
84872
|
if (!SKILL_SLUG_RE.test(newName)) {
|
|
84704
|
-
|
|
84873
|
+
fail4(`destination name must match ${SKILL_SLUG_RE.source}: got ${JSON.stringify(newName)}`);
|
|
84705
84874
|
}
|
|
84706
84875
|
const { files, skipped } = readSourceFiles(src.dir);
|
|
84707
84876
|
if (!files["SKILL.md"]) {
|
|
84708
|
-
|
|
84877
|
+
fail4(`source ${JSON.stringify(source)} has no SKILL.md at ${src.dir}`);
|
|
84709
84878
|
}
|
|
84710
84879
|
if (newName !== src.slug) {
|
|
84711
84880
|
files["SKILL.md"] = rewriteSkillMdName(files["SKILL.md"], newName);
|
|
@@ -84743,18 +84912,18 @@ function removePersonalAction(name, opts) {
|
|
|
84743
84912
|
const agentsRoot = resolveAgentsRoot(opts);
|
|
84744
84913
|
sweepTrash(agentsRoot, agent);
|
|
84745
84914
|
if (!SKILL_SLUG_RE.test(name)) {
|
|
84746
|
-
|
|
84915
|
+
fail4(`skill name must match ${SKILL_SLUG_RE.source}: got ${JSON.stringify(name)}`);
|
|
84747
84916
|
}
|
|
84748
84917
|
const target = personalSkillDir(agentsRoot, agent, name);
|
|
84749
84918
|
try {
|
|
84750
84919
|
const st = lstatSync9(target);
|
|
84751
84920
|
if (st.isSymbolicLink()) {
|
|
84752
|
-
|
|
84921
|
+
fail4(`refusing to remove symlink at ${target}; investigate manually`);
|
|
84753
84922
|
}
|
|
84754
84923
|
} catch (err2) {
|
|
84755
84924
|
const e = err2;
|
|
84756
84925
|
if (e.code === "ENOENT") {
|
|
84757
|
-
|
|
84926
|
+
fail4(`personal skill ${JSON.stringify(name)} does not exist for agent ${JSON.stringify(agent)}`, 1);
|
|
84758
84927
|
}
|
|
84759
84928
|
throw err2;
|
|
84760
84929
|
}
|
|
@@ -84839,7 +85008,7 @@ function registerSkillPersonalCommands(program3) {
|
|
|
84839
85008
|
// src/cli/skill-search.ts
|
|
84840
85009
|
init_helpers();
|
|
84841
85010
|
var import_yaml23 = __toESM(require_dist(), 1);
|
|
84842
|
-
import { existsSync as existsSync82, readdirSync as readdirSync32, readFileSync as
|
|
85011
|
+
import { existsSync as existsSync82, readdirSync as readdirSync32, readFileSync as readFileSync69, statSync as statSync33 } from "node:fs";
|
|
84843
85012
|
import { homedir as homedir47 } from "node:os";
|
|
84844
85013
|
import { join as join81, resolve as resolve48 } from "node:path";
|
|
84845
85014
|
var PERSONAL_PREFIX2 = "personal-";
|
|
@@ -84860,7 +85029,7 @@ function readSkillFrontmatter(skillDir) {
|
|
|
84860
85029
|
return null;
|
|
84861
85030
|
let content;
|
|
84862
85031
|
try {
|
|
84863
|
-
content =
|
|
85032
|
+
content = readFileSync69(mdPath, "utf-8");
|
|
84864
85033
|
} catch {
|
|
84865
85034
|
return null;
|
|
84866
85035
|
}
|
|
@@ -85132,7 +85301,7 @@ function registerHostdMcpCommand(program3) {
|
|
|
85132
85301
|
// src/cli/hostd.ts
|
|
85133
85302
|
init_source();
|
|
85134
85303
|
init_helpers();
|
|
85135
|
-
import { existsSync as existsSync84, mkdirSync as mkdirSync47, readdirSync as readdirSync33, readFileSync as
|
|
85304
|
+
import { existsSync as existsSync84, mkdirSync as mkdirSync47, readdirSync as readdirSync33, readFileSync as readFileSync71, writeFileSync as writeFileSync41, statSync as statSync34, copyFileSync as copyFileSync12 } from "node:fs";
|
|
85136
85305
|
import { homedir as homedir48 } from "node:os";
|
|
85137
85306
|
import { join as join82 } from "node:path";
|
|
85138
85307
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
@@ -85308,7 +85477,7 @@ async function doInstall(opts, program3) {
|
|
|
85308
85477
|
const bak = backupExistingCompose();
|
|
85309
85478
|
if (bak)
|
|
85310
85479
|
console.log(source_default.dim(` Backed up existing compose to ${bak}`));
|
|
85311
|
-
|
|
85480
|
+
writeFileSync41(composePath, yaml, "utf8");
|
|
85312
85481
|
console.log(source_default.green(` \u2713 Wrote ${composePath}`));
|
|
85313
85482
|
const adminAgents = Object.entries(cfg.agents ?? {}).filter(([, a]) => a?.admin === true).map(([name]) => name);
|
|
85314
85483
|
console.log(source_default.dim(` agents served (one socket each): ${allAgents.length === 0 ? "(none)" : allAgents.join(", ")}`));
|
|
@@ -85415,7 +85584,7 @@ function registerHostdCommand(program3) {
|
|
|
85415
85584
|
The log is created when hostd handles its first privileged-verb request.`));
|
|
85416
85585
|
return;
|
|
85417
85586
|
}
|
|
85418
|
-
const raw =
|
|
85587
|
+
const raw = readFileSync71(logPath, "utf-8");
|
|
85419
85588
|
const limit = Math.max(1, parseInt(opts.tail ?? "50", 10) || 50);
|
|
85420
85589
|
const filters = {
|
|
85421
85590
|
agent: opts.agent,
|
|
@@ -85457,7 +85626,7 @@ The log is created when hostd handles its first privileged-verb request.`));
|
|
|
85457
85626
|
// src/cli/webd.ts
|
|
85458
85627
|
init_source();
|
|
85459
85628
|
init_helpers();
|
|
85460
|
-
import { existsSync as existsSync85, mkdirSync as mkdirSync48, writeFileSync as
|
|
85629
|
+
import { existsSync as existsSync85, mkdirSync as mkdirSync48, writeFileSync as writeFileSync42, copyFileSync as copyFileSync13 } from "node:fs";
|
|
85461
85630
|
import { homedir as homedir49 } from "node:os";
|
|
85462
85631
|
import { join as join83 } from "node:path";
|
|
85463
85632
|
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
@@ -85593,7 +85762,7 @@ async function doInstall2(opts, program3) {
|
|
|
85593
85762
|
const bak = backupExistingCompose2();
|
|
85594
85763
|
if (bak)
|
|
85595
85764
|
console.log(source_default.dim(` Backed up existing compose to ${bak}`));
|
|
85596
|
-
|
|
85765
|
+
writeFileSync42(composePath, yaml, "utf8");
|
|
85597
85766
|
console.log(source_default.green(` \u2713 Wrote ${composePath}`));
|
|
85598
85767
|
console.log(source_default.dim(` running as uid ${operatorUid} (operator), network_mode: host`));
|
|
85599
85768
|
console.log(source_default.dim(` Pulling ghcr.io/switchroom/switchroom-web:${imageTag}\u2026`));
|
|
@@ -85698,6 +85867,7 @@ registerTopicsCommand(program3);
|
|
|
85698
85867
|
registerAuthCommand(program3);
|
|
85699
85868
|
registerVaultCommand(program3);
|
|
85700
85869
|
registerTelegramCommand(program3);
|
|
85870
|
+
registerLinearAgentCommand(program3);
|
|
85701
85871
|
registerMemoryCommand(program3);
|
|
85702
85872
|
registerWebCommand(program3);
|
|
85703
85873
|
registerHandoffCommand(program3);
|