switchroom 0.14.74 → 0.14.75
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 +1 -0
- package/dist/auth-broker/index.js +1 -0
- package/dist/cli/notion-write-pretool.mjs +1 -0
- package/dist/cli/switchroom.js +251 -25
- package/dist/cli/ui/index.html +57 -5
- package/dist/host-control/main.js +1 -0
- package/dist/vault/approvals/kernel-server.js +1 -0
- package/dist/vault/broker/server.js +1 -0
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +5 -4
|
@@ -10991,6 +10991,7 @@ var AgentToolsSchema = exports_external.object({
|
|
|
10991
10991
|
var AgentMemorySchema = exports_external.object({
|
|
10992
10992
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
10993
10993
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
10994
|
+
file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
|
|
10994
10995
|
isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
|
|
10995
10996
|
bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize results"),
|
|
10996
10997
|
retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain"),
|
|
@@ -10991,6 +10991,7 @@ var AgentToolsSchema = exports_external.object({
|
|
|
10991
10991
|
var AgentMemorySchema = exports_external.object({
|
|
10992
10992
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
10993
10993
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
10994
|
+
file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
|
|
10994
10995
|
isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
|
|
10995
10996
|
bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize results"),
|
|
10996
10997
|
retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain"),
|
|
@@ -11739,6 +11739,7 @@ var AgentToolsSchema = exports_external.object({
|
|
|
11739
11739
|
var AgentMemorySchema = exports_external.object({
|
|
11740
11740
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
11741
11741
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
11742
|
+
file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
|
|
11742
11743
|
isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
|
|
11743
11744
|
bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize results"),
|
|
11744
11745
|
retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain"),
|
package/dist/cli/switchroom.js
CHANGED
|
@@ -13555,6 +13555,7 @@ var init_schema = __esm(() => {
|
|
|
13555
13555
|
AgentMemorySchema = exports_external.object({
|
|
13556
13556
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
13557
13557
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
13558
|
+
file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
|
|
13558
13559
|
isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
|
|
13559
13560
|
bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize results"),
|
|
13560
13561
|
retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain"),
|
|
@@ -28938,6 +28939,82 @@ var init_manifest = __esm(() => {
|
|
|
28938
28939
|
]);
|
|
28939
28940
|
});
|
|
28940
28941
|
|
|
28942
|
+
// src/cli/doctor-memory.ts
|
|
28943
|
+
import { execFileSync as execFileSync17 } from "node:child_process";
|
|
28944
|
+
function classifyShmSize(bytes) {
|
|
28945
|
+
const mib = Math.round(bytes / 1024 / 1024);
|
|
28946
|
+
if (bytes < MIN_HINDSIGHT_SHM_BYTES) {
|
|
28947
|
+
return {
|
|
28948
|
+
name: "hindsight shm-size",
|
|
28949
|
+
status: "fail",
|
|
28950
|
+
detail: `${mib}MB \u2014 PostgreSQL needs ~533MB+ for shared segments; writes will ` + `fail with "No space left on device"`,
|
|
28951
|
+
fix: "Recreate hindsight with a larger shm. The launch path now sets " + "--shm-size=2g (#2190); pull a release that includes it and run " + "`switchroom memory --restart`, or recreate the container manually " + "preserving the `switchroom-hindsight-data` volume."
|
|
28952
|
+
};
|
|
28953
|
+
}
|
|
28954
|
+
const gib = (bytes / 1024 / 1024 / 1024).toFixed(bytes % 1024 ** 3 === 0 ? 0 : 1);
|
|
28955
|
+
return { name: "hindsight shm-size", status: "ok", detail: `${gib}g` };
|
|
28956
|
+
}
|
|
28957
|
+
function classifyExtractionLogs(logs) {
|
|
28958
|
+
const noSpace = /No space left on device|could not resize shared memory/i.test(logs);
|
|
28959
|
+
const llmError = /Claude Code returned an error result|claude_code_llm[\s\S]{0,80}error|Fact extraction failed|Content extraction failed/i.test(logs);
|
|
28960
|
+
const quotaHint = /weekly limit|api_error_status["':\s]+429|\b429\b|hit your[\s\S]{0,24}limit/i.test(logs);
|
|
28961
|
+
const zeroFacts = (logs.match(/Extract facts:\s*0 facts/gi) ?? []).length;
|
|
28962
|
+
const okFacts = (logs.match(/Extract facts:\s*[1-9]\d* facts/gi) ?? []).length;
|
|
28963
|
+
if (noSpace) {
|
|
28964
|
+
return {
|
|
28965
|
+
name: "hindsight extraction",
|
|
28966
|
+
status: "fail",
|
|
28967
|
+
detail: "shared-memory exhaustion in recent logs \u2014 memory writes are failing",
|
|
28968
|
+
fix: "See the `hindsight shm-size` check \u2014 the container's /dev/shm is too small."
|
|
28969
|
+
};
|
|
28970
|
+
}
|
|
28971
|
+
if (llmError && okFacts === 0) {
|
|
28972
|
+
return {
|
|
28973
|
+
name: "hindsight extraction",
|
|
28974
|
+
status: "fail",
|
|
28975
|
+
detail: "fact-extraction LLM calls are failing" + (quotaHint ? " (429 / weekly-limit detected)" : "") + " \u2014 retains are accepted but extract 0 facts, so nothing becomes recallable",
|
|
28976
|
+
fix: "Usually hindsight's `auth.consumers[hindsight].account` is quota-" + "exhausted or its OAuth broke. Repoint it to an account with quota in " + "switchroom.yaml, then `docker restart switchroom-auth-broker` and " + "`docker restart switchroom-hindsight` (single-file config mount needs " + "the broker restart to re-read). Confirm with a `claude -p` inside the " + "container."
|
|
28977
|
+
};
|
|
28978
|
+
}
|
|
28979
|
+
if (zeroFacts >= 3 && okFacts === 0) {
|
|
28980
|
+
return {
|
|
28981
|
+
name: "hindsight extraction",
|
|
28982
|
+
status: "warn",
|
|
28983
|
+
detail: `${zeroFacts} recent extractions produced 0 facts and none succeeded \u2014 ` + "fact extraction may be failing",
|
|
28984
|
+
fix: "Inspect `docker logs switchroom-hindsight` for the extraction error."
|
|
28985
|
+
};
|
|
28986
|
+
}
|
|
28987
|
+
return {
|
|
28988
|
+
name: "hindsight extraction",
|
|
28989
|
+
status: "ok",
|
|
28990
|
+
detail: okFacts > 0 ? `healthy (${okFacts} recent successful extractions)` : "no recent extraction activity to assess"
|
|
28991
|
+
};
|
|
28992
|
+
}
|
|
28993
|
+
function checkHindsightContainerHealth(opts) {
|
|
28994
|
+
const name = opts?.containerName ?? "switchroom-hindsight";
|
|
28995
|
+
const exec = opts?.exec ?? ((cmd, args) => execFileSync17(cmd, args, { stdio: ["ignore", "pipe", "ignore"], timeout: 8000 }).toString());
|
|
28996
|
+
const results = [];
|
|
28997
|
+
let shmRaw;
|
|
28998
|
+
try {
|
|
28999
|
+
shmRaw = exec("docker", ["inspect", name, "--format", "{{.HostConfig.ShmSize}}"]).trim();
|
|
29000
|
+
} catch {
|
|
29001
|
+
return [];
|
|
29002
|
+
}
|
|
29003
|
+
const shmBytes = parseInt(shmRaw, 10);
|
|
29004
|
+
if (Number.isFinite(shmBytes) && shmBytes > 0) {
|
|
29005
|
+
results.push(classifyShmSize(shmBytes));
|
|
29006
|
+
}
|
|
29007
|
+
try {
|
|
29008
|
+
const logs = exec("docker", ["logs", "--since", "10m", name]);
|
|
29009
|
+
results.push(classifyExtractionLogs(logs));
|
|
29010
|
+
} catch {}
|
|
29011
|
+
return results;
|
|
29012
|
+
}
|
|
29013
|
+
var MIN_HINDSIGHT_SHM_BYTES;
|
|
29014
|
+
var init_doctor_memory = __esm(() => {
|
|
29015
|
+
MIN_HINDSIGHT_SHM_BYTES = 1024 * 1024 * 1024;
|
|
29016
|
+
});
|
|
29017
|
+
|
|
28941
29018
|
// src/cli/doctor-docker.ts
|
|
28942
29019
|
import { readFileSync as readFileSync47 } from "node:fs";
|
|
28943
29020
|
function imageTagOf(ref) {
|
|
@@ -31017,7 +31094,7 @@ var init_doctor_agent_smoke = __esm(() => {
|
|
|
31017
31094
|
});
|
|
31018
31095
|
|
|
31019
31096
|
// src/cli/doctor-vault-broker-durability.ts
|
|
31020
|
-
import { execFileSync as
|
|
31097
|
+
import { execFileSync as execFileSync18 } from "node:child_process";
|
|
31021
31098
|
import { existsSync as existsSync54, statSync as statSync22 } from "node:fs";
|
|
31022
31099
|
import { homedir as homedir33 } from "node:os";
|
|
31023
31100
|
import { join as join55 } from "node:path";
|
|
@@ -31079,7 +31156,7 @@ function spawnDockerStat(p) {
|
|
|
31079
31156
|
}
|
|
31080
31157
|
function spawnDockerStatForContainer(containerName2, p) {
|
|
31081
31158
|
try {
|
|
31082
|
-
const stdout =
|
|
31159
|
+
const stdout = execFileSync18("docker", ["exec", containerName2, "stat", "-c", "%i %s", p], { stdio: ["ignore", "pipe", "pipe"], timeout: 3000, encoding: "utf8" });
|
|
31083
31160
|
return { status: 0, stdout, stderr: "", error: null };
|
|
31084
31161
|
} catch (err) {
|
|
31085
31162
|
const e = err;
|
|
@@ -31153,7 +31230,7 @@ function probeBrokerUnlocked(opts) {
|
|
|
31153
31230
|
}
|
|
31154
31231
|
function defaultBrokerStatusProbe() {
|
|
31155
31232
|
try {
|
|
31156
|
-
const out =
|
|
31233
|
+
const out = execFileSync18("switchroom", ["vault", "broker", "status"], { stdio: ["ignore", "pipe", "pipe"], timeout: 3000, encoding: "utf8" });
|
|
31157
31234
|
const parsed = JSON.parse(out.trim());
|
|
31158
31235
|
if (!parsed.running)
|
|
31159
31236
|
return null;
|
|
@@ -31947,6 +32024,7 @@ async function checkHindsight(config) {
|
|
|
31947
32024
|
detail: `${probe2.serverName} ${probe2.serverVersion} at ${host}:${port}`
|
|
31948
32025
|
});
|
|
31949
32026
|
results.push(checkHindsightConsumer(config));
|
|
32027
|
+
results.push(...checkHindsightContainerHealth());
|
|
31950
32028
|
for (const [agentName, agentConfig] of Object.entries(config.agents)) {
|
|
31951
32029
|
const bankId = agentConfig.memory?.collection ?? agentName;
|
|
31952
32030
|
const hasBankMission = !!agentConfig.memory?.bank_mission;
|
|
@@ -33076,6 +33154,7 @@ var init_doctor = __esm(() => {
|
|
|
33076
33154
|
init_accounts();
|
|
33077
33155
|
init_manifest();
|
|
33078
33156
|
init_hindsight();
|
|
33157
|
+
init_doctor_memory();
|
|
33079
33158
|
init_doctor_docker();
|
|
33080
33159
|
init_doctor_auth_broker();
|
|
33081
33160
|
init_doctor_hostd();
|
|
@@ -49601,8 +49680,8 @@ var {
|
|
|
49601
49680
|
} = import__.default;
|
|
49602
49681
|
|
|
49603
49682
|
// src/build-info.ts
|
|
49604
|
-
var VERSION = "0.14.
|
|
49605
|
-
var COMMIT_SHA = "
|
|
49683
|
+
var VERSION = "0.14.75";
|
|
49684
|
+
var COMMIT_SHA = "8c331b53";
|
|
49606
49685
|
|
|
49607
49686
|
// src/cli/agent.ts
|
|
49608
49687
|
init_source();
|
|
@@ -51112,6 +51191,10 @@ function seedWorkspaceBootstrapFiles(params) {
|
|
|
51112
51191
|
}
|
|
51113
51192
|
if (entry === ".gitkeep")
|
|
51114
51193
|
continue;
|
|
51194
|
+
if (params.seedMemoryFile === false && relPath.replace(/\.hbs$/, "") === "MEMORY.md") {
|
|
51195
|
+
params.skipped.push(join8(agentWorkspaceDir, "MEMORY.md"));
|
|
51196
|
+
continue;
|
|
51197
|
+
}
|
|
51115
51198
|
if (entry.endsWith(".hbs")) {
|
|
51116
51199
|
const destRel = relPath.replace(/\.hbs$/, "");
|
|
51117
51200
|
const destPath = join8(agentWorkspaceDir, destRel);
|
|
@@ -51757,7 +51840,8 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
51757
51840
|
context,
|
|
51758
51841
|
created,
|
|
51759
51842
|
skipped,
|
|
51760
|
-
rewrittenWithBackup
|
|
51843
|
+
rewrittenWithBackup,
|
|
51844
|
+
seedMemoryFile: agentConfig.memory?.file !== false
|
|
51761
51845
|
});
|
|
51762
51846
|
ensureClaudeMdSymlinks(phase5WorkspaceDir, created);
|
|
51763
51847
|
const persistentHomeDir = join8(agentDir, "home");
|
|
@@ -52786,7 +52870,8 @@ ${body}
|
|
|
52786
52870
|
context: workspaceContext,
|
|
52787
52871
|
created: changes,
|
|
52788
52872
|
skipped: [],
|
|
52789
|
-
rewrittenWithBackup: changes
|
|
52873
|
+
rewrittenWithBackup: changes,
|
|
52874
|
+
seedMemoryFile: agentConfig.memory?.file !== false
|
|
52790
52875
|
});
|
|
52791
52876
|
ensureClaudeMdSymlinks(reconcileWorkspaceDir, changes);
|
|
52792
52877
|
}
|
|
@@ -66066,6 +66151,7 @@ var HINDSIGHT_DEFAULT_RECALL_MAX_CONCURRENT = 8;
|
|
|
66066
66151
|
var HINDSIGHT_DEFAULT_MEM_LIMIT = "4g";
|
|
66067
66152
|
var HINDSIGHT_DEFAULT_MEM_RESERVATION = "2g";
|
|
66068
66153
|
var HINDSIGHT_DEFAULT_PIDS_LIMIT = 1000;
|
|
66154
|
+
var HINDSIGHT_DEFAULT_SHM_SIZE = "2g";
|
|
66069
66155
|
function isPortFree(port) {
|
|
66070
66156
|
return new Promise((resolve27) => {
|
|
66071
66157
|
const server = createServer4();
|
|
@@ -66156,6 +66242,7 @@ function startHindsight(ports) {
|
|
|
66156
66242
|
`--memory=${HINDSIGHT_DEFAULT_MEM_LIMIT}`,
|
|
66157
66243
|
`--memory-reservation=${HINDSIGHT_DEFAULT_MEM_RESERVATION}`,
|
|
66158
66244
|
`--pids-limit=${HINDSIGHT_DEFAULT_PIDS_LIMIT}`,
|
|
66245
|
+
`--shm-size=${HINDSIGHT_DEFAULT_SHM_SIZE}`,
|
|
66159
66246
|
"-p",
|
|
66160
66247
|
`127.0.0.1:${apiPort}:8888`,
|
|
66161
66248
|
"-p",
|
|
@@ -66209,6 +66296,7 @@ function generateHindsightComposeSnippet() {
|
|
|
66209
66296
|
` mem_limit: ${HINDSIGHT_DEFAULT_MEM_LIMIT}`,
|
|
66210
66297
|
` mem_reservation: ${HINDSIGHT_DEFAULT_MEM_RESERVATION}`,
|
|
66211
66298
|
` pids_limit: ${HINDSIGHT_DEFAULT_PIDS_LIMIT}`,
|
|
66299
|
+
` shm_size: ${HINDSIGHT_DEFAULT_SHM_SIZE}`,
|
|
66212
66300
|
" volumes:",
|
|
66213
66301
|
" - switchroom-hindsight-data:/home/hindsight/.pg0",
|
|
66214
66302
|
` - ${HINDSIGHT_BROKER_SOCK_VOLUME}:/run/switchroom/auth-broker`,
|
|
@@ -71403,10 +71491,66 @@ async function proposeConfigEditViaHostd(args) {
|
|
|
71403
71491
|
}
|
|
71404
71492
|
}
|
|
71405
71493
|
|
|
71494
|
+
// src/web/api.ts
|
|
71495
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
71496
|
+
|
|
71497
|
+
// src/web/microsoft-connect.ts
|
|
71498
|
+
init_oauth2();
|
|
71499
|
+
init_resolver();
|
|
71500
|
+
init_client2();
|
|
71501
|
+
async function startMicrosoftConnect(deps = {}) {
|
|
71502
|
+
const resolved = resolveMicrosoftClientId(deps.configClientId);
|
|
71503
|
+
if (isVaultReference(resolved.clientId)) {
|
|
71504
|
+
return { kind: "byo-vault", ref: resolved.clientId };
|
|
71505
|
+
}
|
|
71506
|
+
const scopes = selectMicrosoftScopes(deps.orgMode ?? false);
|
|
71507
|
+
const cfg = { client_id: resolved.clientId, scopes };
|
|
71508
|
+
try {
|
|
71509
|
+
const device = await (deps.requestDeviceCode ?? requestDeviceCode2)(cfg);
|
|
71510
|
+
return { kind: "started", device, clientId: resolved.clientId, scopes, source: resolved.source };
|
|
71511
|
+
} catch (err) {
|
|
71512
|
+
return { kind: "error", message: err.message };
|
|
71513
|
+
}
|
|
71514
|
+
}
|
|
71515
|
+
async function runMicrosoftConnectPoll(flow, deps = {}) {
|
|
71516
|
+
const now = deps.now ?? Date.now;
|
|
71517
|
+
const cfg = { client_id: flow.clientId, scopes: flow.scopes };
|
|
71518
|
+
let tokens;
|
|
71519
|
+
try {
|
|
71520
|
+
tokens = await (deps.pollDeviceToken ?? pollDeviceToken2)(cfg, flow.device, { now });
|
|
71521
|
+
} catch (err) {
|
|
71522
|
+
return { state: "failed", message: err.message };
|
|
71523
|
+
}
|
|
71524
|
+
const built = buildMicrosoftCredentials({
|
|
71525
|
+
tokens,
|
|
71526
|
+
clientId: flow.clientId,
|
|
71527
|
+
accountEmail: "",
|
|
71528
|
+
fallbackScope: flow.scopes.join(" "),
|
|
71529
|
+
now
|
|
71530
|
+
});
|
|
71531
|
+
if (!built.credentials.microsoftOauth.refreshToken) {
|
|
71532
|
+
return { state: "no-refresh-token" };
|
|
71533
|
+
}
|
|
71534
|
+
const account = built.resolvedEmail;
|
|
71535
|
+
if (!account) {
|
|
71536
|
+
return { state: "failed", message: "Microsoft returned no account identity (no id_token)." };
|
|
71537
|
+
}
|
|
71538
|
+
const addAccount = deps.addAccount ?? ((label, creds) => withAuthBrokerClient((client2) => client2.addAccount(label, creds, true, "microsoft")));
|
|
71539
|
+
try {
|
|
71540
|
+
await addAccount(account, built.credentials);
|
|
71541
|
+
} catch (err) {
|
|
71542
|
+
return { state: "failed", message: err.message };
|
|
71543
|
+
}
|
|
71544
|
+
return {
|
|
71545
|
+
state: "connected",
|
|
71546
|
+
account,
|
|
71547
|
+
accountType: built.credentials.microsoftOauth.accountType
|
|
71548
|
+
};
|
|
71549
|
+
}
|
|
71550
|
+
|
|
71406
71551
|
// src/web/api.ts
|
|
71407
71552
|
init_account_store();
|
|
71408
71553
|
init_client2();
|
|
71409
|
-
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
71410
71554
|
|
|
71411
71555
|
// telegram-plugin/registry/turns-schema.ts
|
|
71412
71556
|
import { chmodSync as chmodSync8, mkdirSync as mkdirSync26 } from "fs";
|
|
@@ -72017,6 +72161,71 @@ function reapConnectionAccessStatuses(now = Date.now()) {
|
|
|
72017
72161
|
function handleGetConnectionAccessStatus(requestId) {
|
|
72018
72162
|
return connectionAccessStatuses.get(requestId) ?? { state: "unknown" };
|
|
72019
72163
|
}
|
|
72164
|
+
var microsoftConnectStatuses = new Map;
|
|
72165
|
+
function reapMicrosoftConnects(now = Date.now()) {
|
|
72166
|
+
for (const [id, s] of microsoftConnectStatuses) {
|
|
72167
|
+
const ttl = s.state === "pending" ? s.expiresInSec * 1000 + 60000 : 30 * 60000;
|
|
72168
|
+
if (now - s.startedAt > ttl)
|
|
72169
|
+
microsoftConnectStatuses.delete(id);
|
|
72170
|
+
}
|
|
72171
|
+
}
|
|
72172
|
+
async function handleStartMicrosoftConnect(config, deps = {}) {
|
|
72173
|
+
const now = deps.now ?? Date.now;
|
|
72174
|
+
const configClientId = config.microsoft_workspace?.microsoft_client_id;
|
|
72175
|
+
const orgMode = deps.orgMode ?? config.microsoft_workspace?.org_mode === true;
|
|
72176
|
+
const started = await startMicrosoftConnect({ ...deps, configClientId, orgMode });
|
|
72177
|
+
if (started.kind === "byo-vault") {
|
|
72178
|
+
return {
|
|
72179
|
+
ok: false,
|
|
72180
|
+
error: `This install uses a vaulted custom Microsoft app (${started.ref}) the dashboard can't read. ` + `Connect from the host: switchroom auth microsoft account add <email>.`
|
|
72181
|
+
};
|
|
72182
|
+
}
|
|
72183
|
+
if (started.kind === "error") {
|
|
72184
|
+
return { ok: false, error: started.message };
|
|
72185
|
+
}
|
|
72186
|
+
const requestId = randomUUID4();
|
|
72187
|
+
microsoftConnectStatuses.set(requestId, {
|
|
72188
|
+
state: "pending",
|
|
72189
|
+
startedAt: now(),
|
|
72190
|
+
userCode: started.device.user_code,
|
|
72191
|
+
verificationUri: started.device.verification_uri,
|
|
72192
|
+
expiresInSec: started.device.expires_in
|
|
72193
|
+
});
|
|
72194
|
+
reapMicrosoftConnects(now());
|
|
72195
|
+
runMicrosoftConnectPoll({ device: started.device, clientId: started.clientId, scopes: started.scopes }, deps).then((res) => {
|
|
72196
|
+
const startedAt = microsoftConnectStatuses.get(requestId)?.startedAt ?? now();
|
|
72197
|
+
if (res.state === "connected") {
|
|
72198
|
+
microsoftConnectStatuses.set(requestId, {
|
|
72199
|
+
state: "connected",
|
|
72200
|
+
startedAt,
|
|
72201
|
+
account: res.account,
|
|
72202
|
+
accountType: res.accountType
|
|
72203
|
+
});
|
|
72204
|
+
captureEvent("microsoft_connect", { outcome: "connected", source: "web_api" });
|
|
72205
|
+
} else {
|
|
72206
|
+
const reason = res.state === "no-refresh-token" ? "Microsoft returned no refresh token (account would expire in ~1h)." : res.message;
|
|
72207
|
+
microsoftConnectStatuses.set(requestId, { state: "failed", startedAt, reason });
|
|
72208
|
+
}
|
|
72209
|
+
}).catch((err) => {
|
|
72210
|
+
const startedAt = microsoftConnectStatuses.get(requestId)?.startedAt ?? now();
|
|
72211
|
+
microsoftConnectStatuses.set(requestId, {
|
|
72212
|
+
state: "failed",
|
|
72213
|
+
startedAt,
|
|
72214
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
72215
|
+
});
|
|
72216
|
+
captureException(err, { action: "microsoft_connect" });
|
|
72217
|
+
});
|
|
72218
|
+
return {
|
|
72219
|
+
ok: true,
|
|
72220
|
+
requestId,
|
|
72221
|
+
userCode: started.device.user_code,
|
|
72222
|
+
verificationUri: started.device.verification_uri,
|
|
72223
|
+
expiresInSec: started.device.expires_in
|
|
72224
|
+
};
|
|
72225
|
+
}
|
|
72226
|
+
function handleGetMicrosoftConnectStatus(requestId) {
|
|
72227
|
+
return microsoftConnectStatuses.get(requestId) ?? { state: "unknown" };
|
|
72228
|
+
}
|
|
72020
72229
|
function handleSetConnectionAccess(configPath, config, args, deps = {}) {
|
|
72021
72230
|
const provider = args.provider;
|
|
72022
72231
|
if (provider !== "google" && provider !== "microsoft") {
|
|
@@ -72800,6 +73009,16 @@ function parseRoute(pathname, method) {
|
|
|
72800
73009
|
params: { requestId: decodeURIComponent(accessStatusMatch[1]) }
|
|
72801
73010
|
};
|
|
72802
73011
|
}
|
|
73012
|
+
if (method === "POST" && pathname === "/api/connections/microsoft/connect") {
|
|
73013
|
+
return { handler: "startMicrosoftConnect", params: {} };
|
|
73014
|
+
}
|
|
73015
|
+
const msConnectMatch = pathname.match(/^\/api\/connections\/microsoft\/connect\/([^/]+)$/);
|
|
73016
|
+
if (method === "GET" && msConnectMatch) {
|
|
73017
|
+
return {
|
|
73018
|
+
handler: "getMicrosoftConnectStatus",
|
|
73019
|
+
params: { requestId: decodeURIComponent(msConnectMatch[1]) }
|
|
73020
|
+
};
|
|
73021
|
+
}
|
|
72803
73022
|
if (method === "POST" && pathname === "/api/auth/use") {
|
|
72804
73023
|
return { handler: "useAccount", params: {} };
|
|
72805
73024
|
}
|
|
@@ -72976,6 +73195,13 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
|
|
|
72976
73195
|
}
|
|
72977
73196
|
case "getConnectionAccessStatus":
|
|
72978
73197
|
return jsonResponse(handleGetConnectionAccessStatus(route.params.requestId));
|
|
73198
|
+
case "startMicrosoftConnect":
|
|
73199
|
+
return (async () => {
|
|
73200
|
+
const result = await handleStartMicrosoftConnect(freshConfig());
|
|
73201
|
+
return jsonResponse(result, result.ok ? 200 : 400);
|
|
73202
|
+
})();
|
|
73203
|
+
case "getMicrosoftConnectStatus":
|
|
73204
|
+
return jsonResponse(handleGetMicrosoftConnectStatus(route.params.requestId));
|
|
72979
73205
|
case "refreshQuota": {
|
|
72980
73206
|
return (async () => {
|
|
72981
73207
|
let body = {};
|
|
@@ -75714,7 +75940,7 @@ import {
|
|
|
75714
75940
|
} from "node:fs";
|
|
75715
75941
|
import { dirname as dirname15, join as join60 } from "node:path";
|
|
75716
75942
|
import { homedir as homedir35 } from "node:os";
|
|
75717
|
-
import { execFileSync as
|
|
75943
|
+
import { execFileSync as execFileSync19 } from "node:child_process";
|
|
75718
75944
|
|
|
75719
75945
|
class PythonEnvError extends Error {
|
|
75720
75946
|
stderr;
|
|
@@ -75761,7 +75987,7 @@ function ensurePythonEnv(opts) {
|
|
|
75761
75987
|
}
|
|
75762
75988
|
mkdirSync33(dirname15(venvDir), { recursive: true });
|
|
75763
75989
|
try {
|
|
75764
|
-
|
|
75990
|
+
execFileSync19(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
|
|
75765
75991
|
} catch (err) {
|
|
75766
75992
|
const e = err;
|
|
75767
75993
|
throw new PythonEnvError(`Failed to create venv for skill "${skillName}" with ${hostPython}: ${e.message}`, e.stderr?.toString());
|
|
@@ -75773,7 +75999,7 @@ function ensurePythonEnv(opts) {
|
|
|
75773
75999
|
delete childEnv.PIP_TARGET;
|
|
75774
76000
|
delete childEnv.PIP_PREFIX;
|
|
75775
76001
|
delete childEnv.PYTHONUSERBASE;
|
|
75776
|
-
|
|
76002
|
+
execFileSync19(pipBin, ["install", "--disable-pip-version-check", "-r", requirementsPath], { stdio: "pipe", env: childEnv });
|
|
75777
76003
|
} catch (err) {
|
|
75778
76004
|
const e = err;
|
|
75779
76005
|
throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
|
|
@@ -75802,7 +76028,7 @@ import {
|
|
|
75802
76028
|
} from "node:fs";
|
|
75803
76029
|
import { dirname as dirname16, join as join61 } from "node:path";
|
|
75804
76030
|
import { homedir as homedir36 } from "node:os";
|
|
75805
|
-
import { execFileSync as
|
|
76031
|
+
import { execFileSync as execFileSync20 } from "node:child_process";
|
|
75806
76032
|
|
|
75807
76033
|
class NodeEnvError extends Error {
|
|
75808
76034
|
stderr;
|
|
@@ -75886,10 +76112,10 @@ function ensureNodeEnv(opts) {
|
|
|
75886
76112
|
try {
|
|
75887
76113
|
if (installer === "bun") {
|
|
75888
76114
|
const args = copiedLockfile ? ["install", "--frozen-lockfile"] : ["install"];
|
|
75889
|
-
|
|
76115
|
+
execFileSync20("bun", args, { cwd: envDir, stdio: "pipe" });
|
|
75890
76116
|
} else {
|
|
75891
76117
|
const args = copiedLockfile ? ["ci"] : ["install"];
|
|
75892
|
-
|
|
76118
|
+
execFileSync20("npm", args, { cwd: envDir, stdio: "pipe" });
|
|
75893
76119
|
}
|
|
75894
76120
|
} catch (err) {
|
|
75895
76121
|
const e = err;
|
|
@@ -77217,7 +77443,7 @@ function registerDebugCommand(program3) {
|
|
|
77217
77443
|
init_source();
|
|
77218
77444
|
|
|
77219
77445
|
// src/worktree/claim.ts
|
|
77220
|
-
import { execFileSync as
|
|
77446
|
+
import { execFileSync as execFileSync21 } from "node:child_process";
|
|
77221
77447
|
import { closeSync as closeSync12, mkdirSync as mkdirSync36, openSync as openSync12, existsSync as existsSync66, unlinkSync as unlinkSync13 } from "node:fs";
|
|
77222
77448
|
import { join as join66, resolve as resolve42 } from "node:path";
|
|
77223
77449
|
import { homedir as homedir39 } from "node:os";
|
|
@@ -77384,7 +77610,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
77384
77610
|
releaseLock();
|
|
77385
77611
|
}
|
|
77386
77612
|
try {
|
|
77387
|
-
|
|
77613
|
+
execFileSync21("git", ["worktree", "add", "-b", branch, worktreePath], {
|
|
77388
77614
|
cwd: repoPath,
|
|
77389
77615
|
stdio: "pipe"
|
|
77390
77616
|
});
|
|
@@ -77397,7 +77623,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
77397
77623
|
}
|
|
77398
77624
|
|
|
77399
77625
|
// src/worktree/release.ts
|
|
77400
|
-
import { execFileSync as
|
|
77626
|
+
import { execFileSync as execFileSync22 } from "node:child_process";
|
|
77401
77627
|
import { existsSync as existsSync67 } from "node:fs";
|
|
77402
77628
|
function releaseWorktree(input) {
|
|
77403
77629
|
const { id } = input;
|
|
@@ -77408,7 +77634,7 @@ function releaseWorktree(input) {
|
|
|
77408
77634
|
let gitSuccess = true;
|
|
77409
77635
|
if (existsSync67(record2.path)) {
|
|
77410
77636
|
try {
|
|
77411
|
-
|
|
77637
|
+
execFileSync22("git", ["worktree", "remove", "--force", record2.path], {
|
|
77412
77638
|
cwd: record2.repo,
|
|
77413
77639
|
stdio: "pipe"
|
|
77414
77640
|
});
|
|
@@ -77444,16 +77670,16 @@ function listWorktrees() {
|
|
|
77444
77670
|
}
|
|
77445
77671
|
|
|
77446
77672
|
// src/worktree/reaper.ts
|
|
77447
|
-
import { execFileSync as
|
|
77673
|
+
import { execFileSync as execFileSync23 } from "node:child_process";
|
|
77448
77674
|
import { existsSync as existsSync68 } from "node:fs";
|
|
77449
77675
|
var STALE_THRESHOLD_MS = 10 * 60 * 1000;
|
|
77450
77676
|
function isPathInUse(path7) {
|
|
77451
77677
|
try {
|
|
77452
|
-
|
|
77678
|
+
execFileSync23("fuser", [path7], { stdio: "pipe" });
|
|
77453
77679
|
return true;
|
|
77454
77680
|
} catch {}
|
|
77455
77681
|
try {
|
|
77456
|
-
const out =
|
|
77682
|
+
const out = execFileSync23("lsof", ["-t", path7], {
|
|
77457
77683
|
stdio: ["ignore", "pipe", "ignore"]
|
|
77458
77684
|
}).toString().trim();
|
|
77459
77685
|
if (out.length > 0)
|
|
@@ -77463,7 +77689,7 @@ function isPathInUse(path7) {
|
|
|
77463
77689
|
}
|
|
77464
77690
|
function hasUncommittedChanges(repoPath, worktreePath) {
|
|
77465
77691
|
try {
|
|
77466
|
-
const out =
|
|
77692
|
+
const out = execFileSync23("git", ["-C", worktreePath, "status", "--porcelain"], { stdio: "pipe" }).toString();
|
|
77467
77693
|
return out.trim().length > 0;
|
|
77468
77694
|
} catch {
|
|
77469
77695
|
return false;
|
|
@@ -77477,7 +77703,7 @@ function reapRecord(record2) {
|
|
|
77477
77703
|
warning = `[worktree-reaper] Reaped worktree with uncommitted changes: ` + `id=${id} branch=${branch} agent=${ownerAgent ?? "unknown"} path=${path7}`;
|
|
77478
77704
|
}
|
|
77479
77705
|
try {
|
|
77480
|
-
|
|
77706
|
+
execFileSync23("git", ["worktree", "remove", "--force", path7], {
|
|
77481
77707
|
cwd: repo,
|
|
77482
77708
|
stdio: "pipe"
|
|
77483
77709
|
});
|
|
@@ -78960,7 +79186,7 @@ agents:
|
|
|
78960
79186
|
init_resolver();
|
|
78961
79187
|
import { dirname as dirname21, join as join72, resolve as resolve44 } from "node:path";
|
|
78962
79188
|
import { homedir as homedir41 } from "node:os";
|
|
78963
|
-
import { execFileSync as
|
|
79189
|
+
import { execFileSync as execFileSync24 } from "node:child_process";
|
|
78964
79190
|
init_vault();
|
|
78965
79191
|
init_loader();
|
|
78966
79192
|
init_loader();
|
|
@@ -79368,7 +79594,7 @@ async function ensureHostMountSources(config) {
|
|
|
79368
79594
|
}
|
|
79369
79595
|
function detectComposeV2() {
|
|
79370
79596
|
try {
|
|
79371
|
-
const out =
|
|
79597
|
+
const out = execFileSync24("docker", ["compose", "version"], {
|
|
79372
79598
|
stdio: ["ignore", "pipe", "pipe"],
|
|
79373
79599
|
encoding: "utf8"
|
|
79374
79600
|
});
|
package/dist/cli/ui/index.html
CHANGED
|
@@ -559,6 +559,51 @@
|
|
|
559
559
|
}
|
|
560
560
|
}
|
|
561
561
|
|
|
562
|
+
// Start an in-browser Microsoft connect: show the device code + link,
|
|
563
|
+
// then poll until the operator completes sign-in on Microsoft's site.
|
|
564
|
+
async function connectMicrosoft() {
|
|
565
|
+
const card = document.getElementById('ms-connect-card');
|
|
566
|
+
const show = (html) => { if (card) card.innerHTML = html; };
|
|
567
|
+
show('<div class="loading" style="padding:.8rem">Starting…</div>');
|
|
568
|
+
try {
|
|
569
|
+
const res = await fetch(`${API}/api/connections/microsoft/connect`, { method: 'POST', headers: authHeaders() });
|
|
570
|
+
const data = await res.json();
|
|
571
|
+
if (!res.ok || !data.ok) { show(''); showError(data.error || `HTTP ${res.status}`); return; }
|
|
572
|
+
const url = data.verificationUri, code = data.userCode;
|
|
573
|
+
show(`<div class="account-card" style="border-color:var(--accent)">
|
|
574
|
+
<div class="account-card-header"><div class="account-label">Connect a Microsoft account</div></div>
|
|
575
|
+
<div style="padding:.3rem 0;line-height:1.7">
|
|
576
|
+
1. Open <a href="${escapeHtml(url)}" target="_blank" rel="noopener" style="color:var(--accent)">${escapeHtml(url)}</a><br>
|
|
577
|
+
2. Enter code: <code style="font-size:1.15rem;letter-spacing:.08em">${escapeHtml(code)}</code><br>
|
|
578
|
+
3. Approve the requested permissions (Mail, Calendar, Files).
|
|
579
|
+
</div>
|
|
580
|
+
<div id="ms-connect-status" style="color:var(--text-dim);margin-top:.3rem">Waiting for sign-in… (this card expires in ~15 min)</div>
|
|
581
|
+
</div>`);
|
|
582
|
+
const statusEl = () => document.getElementById('ms-connect-status');
|
|
583
|
+
const started = Date.now();
|
|
584
|
+
const poll = async () => {
|
|
585
|
+
const sres = await fetch(`${API}/api/connections/microsoft/connect/${encodeURIComponent(data.requestId)}`, { headers: authHeaders() });
|
|
586
|
+
const s = sres.ok ? await sres.json() : { state: 'failed', reason: `HTTP ${sres.status}` };
|
|
587
|
+
if (s.state === 'pending') {
|
|
588
|
+
if (Date.now() - started > ((data.expiresInSec || 900) * 1000 + 30000)) { const e = statusEl(); if (e) e.textContent = 'Expired — click Connect to try again.'; return; }
|
|
589
|
+
setTimeout(poll, 3000);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
if (s.state === 'connected') {
|
|
593
|
+
show(`<div class="loading" style="padding:.8rem;color:var(--green)">✓ Connected ${escapeHtml(s.account)} (${escapeHtml(s.accountType)}). Use the access toggles below to grant an agent.</div>`);
|
|
594
|
+
fetchConnections();
|
|
595
|
+
} else {
|
|
596
|
+
show('');
|
|
597
|
+
showError(s.reason || 'connect failed');
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
setTimeout(poll, 3000);
|
|
601
|
+
} catch (err) {
|
|
602
|
+
show('');
|
|
603
|
+
showError(err.message);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
562
607
|
async function fetchSchedule() {
|
|
563
608
|
try {
|
|
564
609
|
const res = await fetch(`${API}/api/schedule`, { headers: authHeaders() });
|
|
@@ -1115,11 +1160,18 @@
|
|
|
1115
1160
|
google.map(a => renderOAuthAccountCard(a, { showType: false, provider: 'google', agentNames })).join(''),
|
|
1116
1161
|
);
|
|
1117
1162
|
|
|
1118
|
-
const
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1163
|
+
const msCards = microsoft.map(a => renderOAuthAccountCard(a, { showType: true, provider: 'microsoft', agentNames })).join('');
|
|
1164
|
+
const microsoftSection = `
|
|
1165
|
+
<div style="margin-bottom:1.5rem">
|
|
1166
|
+
<h3 style="margin:0 0 .6rem;font-size:.95rem;color:var(--text-dim);text-transform:uppercase;letter-spacing:.04em">
|
|
1167
|
+
Microsoft 365
|
|
1168
|
+
<button onclick="connectMicrosoft()" class="usage-pill primary" style="margin-left:.6rem;cursor:pointer;border:none;text-transform:none;font-weight:600">+ Connect a Microsoft account</button>
|
|
1169
|
+
</h3>
|
|
1170
|
+
<div id="ms-connect-card"></div>
|
|
1171
|
+
${msCards
|
|
1172
|
+
? `<div class="accounts-grid">${msCards}</div>`
|
|
1173
|
+
: `<div class="loading" style="padding:.8rem">No Microsoft accounts yet — click <b>Connect a Microsoft account</b> above (or <code>/connect microsoft</code> from Telegram).</div>`}
|
|
1174
|
+
</div>`;
|
|
1123
1175
|
|
|
1124
1176
|
let notionCards = '';
|
|
1125
1177
|
if (notion.configured) {
|
|
@@ -13726,6 +13726,7 @@ var AgentToolsSchema = exports_external.object({
|
|
|
13726
13726
|
var AgentMemorySchema = exports_external.object({
|
|
13727
13727
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
13728
13728
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
13729
|
+
file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
|
|
13729
13730
|
isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
|
|
13730
13731
|
bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize results"),
|
|
13731
13732
|
retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain"),
|
|
@@ -11312,6 +11312,7 @@ var init_schema = __esm(() => {
|
|
|
11312
11312
|
AgentMemorySchema = exports_external.object({
|
|
11313
11313
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
11314
11314
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
11315
|
+
file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
|
|
11315
11316
|
isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
|
|
11316
11317
|
bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize results"),
|
|
11317
11318
|
retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain"),
|
|
@@ -11312,6 +11312,7 @@ var init_schema = __esm(() => {
|
|
|
11312
11312
|
AgentMemorySchema = exports_external.object({
|
|
11313
11313
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
11314
11314
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
11315
|
+
file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
|
|
11315
11316
|
isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
|
|
11316
11317
|
bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize results"),
|
|
11317
11318
|
retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain"),
|
package/package.json
CHANGED
|
@@ -23815,6 +23815,7 @@ var init_schema = __esm(() => {
|
|
|
23815
23815
|
AgentMemorySchema = exports_external.object({
|
|
23816
23816
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
23817
23817
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
23818
|
+
file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
|
|
23818
23819
|
isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
|
|
23819
23820
|
bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize results"),
|
|
23820
23821
|
retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain"),
|
|
@@ -52819,10 +52820,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
52819
52820
|
}
|
|
52820
52821
|
|
|
52821
52822
|
// ../src/build-info.ts
|
|
52822
|
-
var VERSION = "0.14.
|
|
52823
|
-
var COMMIT_SHA = "
|
|
52824
|
-
var COMMIT_DATE = "2026-06-
|
|
52825
|
-
var LATEST_PR =
|
|
52823
|
+
var VERSION = "0.14.75";
|
|
52824
|
+
var COMMIT_SHA = "8c331b53";
|
|
52825
|
+
var COMMIT_DATE = "2026-06-06T06:33:56Z";
|
|
52826
|
+
var LATEST_PR = 2192;
|
|
52826
52827
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
52827
52828
|
|
|
52828
52829
|
// gateway/boot-version.ts
|