switchroom 0.14.58 → 0.14.60
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 -1
- package/dist/auth-broker/index.js +19 -9
- package/dist/cli/notion-write-pretool.mjs +1 -1
- package/dist/cli/switchroom.js +29 -70
- package/dist/host-control/main.js +1 -1
- package/dist/vault/approvals/kernel-server.js +1 -1
- package/dist/vault/broker/server.js +1 -1
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +216 -12
- package/telegram-plugin/gateway/gateway.ts +216 -2
- package/telegram-plugin/gateway/obligation-ledger.ts +216 -0
- package/telegram-plugin/tests/obligation-ledger.test.ts +167 -0
- package/telegram-plugin/tests/tool-activity-summary.test.ts +44 -0
- package/telegram-plugin/tool-activity-summary.ts +14 -4
|
@@ -11144,7 +11144,7 @@ var GoogleWorkspaceConfigSchema = exports_external.object({
|
|
|
11144
11144
|
tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet — see RFC G §5).")
|
|
11145
11145
|
}).optional();
|
|
11146
11146
|
var MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
11147
|
-
microsoft_client_id: exports_external.string().min(1).describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id')."),
|
|
11147
|
+
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL — omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
11148
11148
|
microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional — public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
|
|
11149
11149
|
authority: exports_external.string().url().optional().describe("Microsoft authority endpoint. Defaults to " + "'https://login.microsoftonline.com/common' which accepts both " + "personal MSA and work/school tenants. Override only for " + "single-tenant deployments."),
|
|
11150
11150
|
org_mode: exports_external.boolean().optional().describe("Opt-in to Teams + SharePoint surfaces (RFC §6.4). When true, " + "the v1 scope set adds Sites.ReadWrite.All AND the launcher " + "spawns softeria with --org-mode. Defaults to false — personal " + "MSA + standard work surfaces only. Flipping for an existing " + "consented account requires re-running 'auth microsoft account " + "add --replace' to consent the additional scope.")
|
|
@@ -11144,7 +11144,7 @@ var GoogleWorkspaceConfigSchema = exports_external.object({
|
|
|
11144
11144
|
tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet — see RFC G §5).")
|
|
11145
11145
|
}).optional();
|
|
11146
11146
|
var MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
11147
|
-
microsoft_client_id: exports_external.string().min(1).describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id')."),
|
|
11147
|
+
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL — omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
11148
11148
|
microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional — public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
|
|
11149
11149
|
authority: exports_external.string().url().optional().describe("Microsoft authority endpoint. Defaults to " + "'https://login.microsoftonline.com/common' which accepts both " + "personal MSA and work/school tenants. Override only for " + "single-tenant deployments."),
|
|
11150
11150
|
org_mode: exports_external.boolean().optional().describe("Opt-in to Teams + SharePoint surfaces (RFC §6.4). When true, " + "the v1 scope set adds Sites.ReadWrite.All AND the launcher " + "spawns softeria with --org-mode. Defaults to false — personal " + "MSA + standard work surfaces only. Flipping for an existing " + "consented account requires re-running 'auth microsoft account " + "add --replace' to consent the additional scope.")
|
|
@@ -12954,6 +12954,19 @@ function classifyAsyncError2(err) {
|
|
|
12954
12954
|
return { ok: false, kind: "provider_error", detail: msg };
|
|
12955
12955
|
}
|
|
12956
12956
|
|
|
12957
|
+
// src/auth/default-oauth-clients.ts
|
|
12958
|
+
var DEFAULT_MICROSOFT_CLIENT_ID = "9dff88fa-3126-457b-9d1d-37e58c219019";
|
|
12959
|
+
function resolveMicrosoftClientId(configClientId) {
|
|
12960
|
+
const env = process.env.SWITCHROOM_MICROSOFT_CLIENT_ID;
|
|
12961
|
+
if (env !== undefined && env.trim().length > 0) {
|
|
12962
|
+
return { clientId: env.trim(), source: "env" };
|
|
12963
|
+
}
|
|
12964
|
+
if (configClientId !== undefined && configClientId.length > 0) {
|
|
12965
|
+
return { clientId: configClientId, source: "config" };
|
|
12966
|
+
}
|
|
12967
|
+
return { clientId: DEFAULT_MICROSOFT_CLIENT_ID, source: "default" };
|
|
12968
|
+
}
|
|
12969
|
+
|
|
12957
12970
|
// src/auth/broker/google-storage.ts
|
|
12958
12971
|
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync4, rmSync as rmSync3, statSync as statSync3 } from "node:fs";
|
|
12959
12972
|
import { dirname, join as join2, resolve as resolve5 } from "node:path";
|
|
@@ -13503,14 +13516,11 @@ class AuthBroker {
|
|
|
13503
13516
|
fetcher: opts.fetcher
|
|
13504
13517
|
}));
|
|
13505
13518
|
}
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
|
|
13510
|
-
|
|
13511
|
-
fetcher: opts.fetcher
|
|
13512
|
-
}));
|
|
13513
|
-
}
|
|
13519
|
+
this.providers.register(new MicrosoftProvider({
|
|
13520
|
+
clientId: resolveMicrosoftClientId(config.microsoft_workspace?.microsoft_client_id).clientId,
|
|
13521
|
+
clientSecret: config.microsoft_workspace?.microsoft_client_secret,
|
|
13522
|
+
fetcher: opts.fetcher
|
|
13523
|
+
}));
|
|
13514
13524
|
this.assertConfigConsistent(config);
|
|
13515
13525
|
}
|
|
13516
13526
|
homeRoot() {
|
|
@@ -11892,7 +11892,7 @@ var GoogleWorkspaceConfigSchema = exports_external.object({
|
|
|
11892
11892
|
tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet \u2014 see RFC G \u00a75).")
|
|
11893
11893
|
}).optional();
|
|
11894
11894
|
var MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
11895
|
-
microsoft_client_id: exports_external.string().min(1).describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id')."),
|
|
11895
|
+
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL \u2014 omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
11896
11896
|
microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional \u2014 public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
|
|
11897
11897
|
authority: exports_external.string().url().optional().describe("Microsoft authority endpoint. Defaults to " + "'https://login.microsoftonline.com/common' which accepts both " + "personal MSA and work/school tenants. Override only for " + "single-tenant deployments."),
|
|
11898
11898
|
org_mode: exports_external.boolean().optional().describe("Opt-in to Teams + SharePoint surfaces (RFC \u00a76.4). When true, " + "the v1 scope set adds Sites.ReadWrite.All AND the launcher " + "spawns softeria with --org-mode. Defaults to false \u2014 personal " + "MSA + standard work surfaces only. Flipping for an existing " + "consented account requires re-running 'auth microsoft account " + "add --replace' to consent the additional scope.")
|
package/dist/cli/switchroom.js
CHANGED
|
@@ -13708,7 +13708,7 @@ var init_schema = __esm(() => {
|
|
|
13708
13708
|
tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet \u2014 see RFC G \u00a75).")
|
|
13709
13709
|
}).optional();
|
|
13710
13710
|
MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
13711
|
-
microsoft_client_id: exports_external.string().min(1).describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id')."),
|
|
13711
|
+
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL \u2014 omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
13712
13712
|
microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional \u2014 public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
|
|
13713
13713
|
authority: exports_external.string().url().optional().describe("Microsoft authority endpoint. Defaults to " + "'https://login.microsoftonline.com/common' which accepts both " + "personal MSA and work/school tenants. Override only for " + "single-tenant deployments."),
|
|
13714
13714
|
org_mode: exports_external.boolean().optional().describe("Opt-in to Teams + SharePoint surfaces (RFC \u00a76.4). When true, " + "the v1 scope set adds Sites.ReadWrite.All AND the launcher " + "spawns softeria with --org-mode. Defaults to false \u2014 personal " + "MSA + standard work surfaces only. Flipping for an existing " + "consented account requires re-running 'auth microsoft account " + "add --replace' to consent the additional scope.")
|
|
@@ -30156,23 +30156,12 @@ function checkOAuthClient2(config, anyAgentEnabled) {
|
|
|
30156
30156
|
if (!anyAgentEnabled)
|
|
30157
30157
|
return [];
|
|
30158
30158
|
const mw = config.microsoft_workspace;
|
|
30159
|
-
if (!mw) {
|
|
30159
|
+
if (!mw || !clientValuePresent2(mw.microsoft_client_id)) {
|
|
30160
30160
|
return [
|
|
30161
30161
|
{
|
|
30162
30162
|
name: "microsoft:oauth-client-configured",
|
|
30163
|
-
status: "
|
|
30164
|
-
detail: "
|
|
30165
|
-
fix: "Add a microsoft_workspace block with microsoft_client_id (and optionally microsoft_client_secret) to switchroom.yaml. See `switchroom auth microsoft account add` error output for the full walkthrough."
|
|
30166
|
-
}
|
|
30167
|
-
];
|
|
30168
|
-
}
|
|
30169
|
-
if (!clientValuePresent2(mw.microsoft_client_id)) {
|
|
30170
|
-
return [
|
|
30171
|
-
{
|
|
30172
|
-
name: "microsoft:oauth-client-configured",
|
|
30173
|
-
status: "fail",
|
|
30174
|
-
detail: "microsoft_workspace block present but microsoft_client_id is empty",
|
|
30175
|
-
fix: "Register an Entra app at https://entra.microsoft.com \u2192 App registrations \u2192 New. Copy the Application (client) ID and vault it: `switchroom vault set microsoft-oauth-client-id`."
|
|
30163
|
+
status: "ok",
|
|
30164
|
+
detail: "using switchroom's shipped default Microsoft OAuth app (no BYO app configured)"
|
|
30176
30165
|
}
|
|
30177
30166
|
];
|
|
30178
30167
|
}
|
|
@@ -49463,8 +49452,8 @@ var {
|
|
|
49463
49452
|
} = import__.default;
|
|
49464
49453
|
|
|
49465
49454
|
// src/build-info.ts
|
|
49466
|
-
var VERSION = "0.14.
|
|
49467
|
-
var COMMIT_SHA = "
|
|
49455
|
+
var VERSION = "0.14.60";
|
|
49456
|
+
var COMMIT_SHA = "7a03004e";
|
|
49468
49457
|
|
|
49469
49458
|
// src/cli/agent.ts
|
|
49470
49459
|
init_source();
|
|
@@ -57729,6 +57718,21 @@ function pruneEmptyMap(doc, path) {
|
|
|
57729
57718
|
|
|
57730
57719
|
// src/cli/auth-microsoft.ts
|
|
57731
57720
|
init_helpers();
|
|
57721
|
+
|
|
57722
|
+
// src/auth/default-oauth-clients.ts
|
|
57723
|
+
var DEFAULT_MICROSOFT_CLIENT_ID = "9dff88fa-3126-457b-9d1d-37e58c219019";
|
|
57724
|
+
function resolveMicrosoftClientId(configClientId) {
|
|
57725
|
+
const env2 = process.env.SWITCHROOM_MICROSOFT_CLIENT_ID;
|
|
57726
|
+
if (env2 !== undefined && env2.trim().length > 0) {
|
|
57727
|
+
return { clientId: env2.trim(), source: "env" };
|
|
57728
|
+
}
|
|
57729
|
+
if (configClientId !== undefined && configClientId.length > 0) {
|
|
57730
|
+
return { clientId: configClientId, source: "config" };
|
|
57731
|
+
}
|
|
57732
|
+
return { clientId: DEFAULT_MICROSOFT_CLIENT_ID, source: "default" };
|
|
57733
|
+
}
|
|
57734
|
+
|
|
57735
|
+
// src/cli/auth-microsoft.ts
|
|
57732
57736
|
function registerAuthMicrosoftSubcommands(program3, authParent) {
|
|
57733
57737
|
const microsoft = authParent.command("microsoft").description("Manage Microsoft 365 accounts shared across agents (RFC #1873 \u2014 see docs/rfcs/microsoft-workspace.md)");
|
|
57734
57738
|
registerEnable2(microsoft, program3);
|
|
@@ -57871,13 +57875,13 @@ function registerAccountAdd2(accountParent) {
|
|
|
57871
57875
|
]);
|
|
57872
57876
|
const config = loadConfig2();
|
|
57873
57877
|
const mw = config.microsoft_workspace;
|
|
57874
|
-
|
|
57875
|
-
|
|
57876
|
-
|
|
57877
|
-
|
|
57878
|
-
|
|
57879
|
-
|
|
57880
|
-
|
|
57878
|
+
const resolvedClientId = resolveMicrosoftClientId(mw?.microsoft_client_id);
|
|
57879
|
+
let clientIdRaw = resolvedClientId.clientId;
|
|
57880
|
+
let clientSecretRaw = process.env.SWITCHROOM_MICROSOFT_CLIENT_SECRET ?? mw?.microsoft_client_secret;
|
|
57881
|
+
if (resolvedClientId.source === "default") {
|
|
57882
|
+
console.error(source_default.gray(` Using switchroom's shipped Microsoft OAuth app (zero-config).
|
|
57883
|
+
` + " To use your own Entra app instead, set " + `microsoft_workspace.microsoft_client_id in switchroom.yaml
|
|
57884
|
+
` + " (or the SWITCHROOM_MICROSOFT_CLIENT_ID env var)."));
|
|
57881
57885
|
}
|
|
57882
57886
|
const needsVault = isVaultReference2(clientIdRaw) || clientSecretRaw !== undefined && isVaultReference2(clientSecretRaw);
|
|
57883
57887
|
if (needsVault) {
|
|
@@ -57928,7 +57932,7 @@ function registerAccountAdd2(accountParent) {
|
|
|
57928
57932
|
clientSecretRaw = await resolveRef(clientSecretRaw, "microsoft_client_secret");
|
|
57929
57933
|
}
|
|
57930
57934
|
}
|
|
57931
|
-
const orgMode = opts["orgMode"] ?? mw
|
|
57935
|
+
const orgMode = opts["orgMode"] ?? mw?.org_mode ?? false;
|
|
57932
57936
|
const scopes = selectMicrosoftScopes(orgMode);
|
|
57933
57937
|
const oauthCfg = {
|
|
57934
57938
|
client_id: clientIdRaw,
|
|
@@ -58195,51 +58199,6 @@ async function readHiddenLine2(prompt) {
|
|
|
58195
58199
|
process.stdin.on("data", onData);
|
|
58196
58200
|
});
|
|
58197
58201
|
}
|
|
58198
|
-
function microsoftClientSetupGuidance(reason) {
|
|
58199
|
-
return [
|
|
58200
|
-
reason,
|
|
58201
|
-
"",
|
|
58202
|
-
"Switchroom ships no shared Microsoft OAuth app \u2014 register your own.",
|
|
58203
|
-
"One-time per install:",
|
|
58204
|
-
"",
|
|
58205
|
-
" 1. Go to https://entra.microsoft.com \u2192 App registrations \u2192 New",
|
|
58206
|
-
" registration",
|
|
58207
|
-
" 2. Supported account types: 'Accounts in any organizational",
|
|
58208
|
-
" directory AND personal Microsoft accounts' (multi-tenant + MSA)",
|
|
58209
|
-
" 3. Redirect URI: platform 'Mobile and desktop applications',",
|
|
58210
|
-
" value `http://localhost` (port-agnostic; Microsoft ignores port",
|
|
58211
|
-
" for loopback URIs)",
|
|
58212
|
-
" 4. Authentication \u2192 Advanced settings \u2192 'Allow public client",
|
|
58213
|
-
" flows': Yes (enables device-code on personal MSA)",
|
|
58214
|
-
" 5. Copy the Application (client) ID from the Overview page",
|
|
58215
|
-
" 6. Optional: create a client secret in 'Certificates & secrets'",
|
|
58216
|
-
" (skip if using public-client flow only)",
|
|
58217
|
-
" 7. Vault the credentials:",
|
|
58218
|
-
"",
|
|
58219
|
-
" switchroom vault set microsoft-oauth-client-id",
|
|
58220
|
-
" switchroom vault set microsoft-oauth-client-secret # optional",
|
|
58221
|
-
"",
|
|
58222
|
-
" 8. If your work tenant requires admin consent, your IT admin must",
|
|
58223
|
-
" grant the requested Graph scopes (Files.ReadWrite.All etc.) at",
|
|
58224
|
-
" first sign-in. Personal MSA accounts (outlook.com / hotmail.com)",
|
|
58225
|
-
" don't need this step.",
|
|
58226
|
-
" 9. Add to ~/.switchroom/switchroom.yaml (top level):",
|
|
58227
|
-
"",
|
|
58228
|
-
" microsoft_workspace:",
|
|
58229
|
-
' microsoft_client_id: "vault:microsoft-oauth-client-id"',
|
|
58230
|
-
' microsoft_client_secret: "vault:microsoft-oauth-client-secret" # omit if public-client',
|
|
58231
|
-
" authority: https://login.microsoftonline.com/common",
|
|
58232
|
-
" org_mode: false",
|
|
58233
|
-
"",
|
|
58234
|
-
"Env vars SWITCHROOM_MICROSOFT_CLIENT_ID / _SECRET override the block",
|
|
58235
|
-
"for one-off debugging.",
|
|
58236
|
-
"",
|
|
58237
|
-
"Full walkthrough: docs/microsoft-workspace.md (PR 5 will land this).",
|
|
58238
|
-
"Don't reuse an existing Entra app \u2014 see RFC \u00a74.1 (signInAudience",
|
|
58239
|
-
"mismatch + token-version drift make app sharing brittle)."
|
|
58240
|
-
].join(`
|
|
58241
|
-
`);
|
|
58242
|
-
}
|
|
58243
58202
|
|
|
58244
58203
|
// src/cli/auth.ts
|
|
58245
58204
|
init_auth_active_yaml();
|
|
@@ -13879,7 +13879,7 @@ var GoogleWorkspaceConfigSchema = exports_external.object({
|
|
|
13879
13879
|
tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet — see RFC G §5).")
|
|
13880
13880
|
}).optional();
|
|
13881
13881
|
var MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
13882
|
-
microsoft_client_id: exports_external.string().min(1).describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id')."),
|
|
13882
|
+
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL — omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
13883
13883
|
microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional — public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
|
|
13884
13884
|
authority: exports_external.string().url().optional().describe("Microsoft authority endpoint. Defaults to " + "'https://login.microsoftonline.com/common' which accepts both " + "personal MSA and work/school tenants. Override only for " + "single-tenant deployments."),
|
|
13885
13885
|
org_mode: exports_external.boolean().optional().describe("Opt-in to Teams + SharePoint surfaces (RFC §6.4). When true, " + "the v1 scope set adds Sites.ReadWrite.All AND the launcher " + "spawns softeria with --org-mode. Defaults to false — personal " + "MSA + standard work surfaces only. Flipping for an existing " + "consented account requires re-running 'auth microsoft account " + "add --replace' to consent the additional scope.")
|
|
@@ -11465,7 +11465,7 @@ var init_schema = __esm(() => {
|
|
|
11465
11465
|
tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet — see RFC G §5).")
|
|
11466
11466
|
}).optional();
|
|
11467
11467
|
MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
11468
|
-
microsoft_client_id: exports_external.string().min(1).describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id')."),
|
|
11468
|
+
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL — omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
11469
11469
|
microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional — public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
|
|
11470
11470
|
authority: exports_external.string().url().optional().describe("Microsoft authority endpoint. Defaults to " + "'https://login.microsoftonline.com/common' which accepts both " + "personal MSA and work/school tenants. Override only for " + "single-tenant deployments."),
|
|
11471
11471
|
org_mode: exports_external.boolean().optional().describe("Opt-in to Teams + SharePoint surfaces (RFC §6.4). When true, " + "the v1 scope set adds Sites.ReadWrite.All AND the launcher " + "spawns softeria with --org-mode. Defaults to false — personal " + "MSA + standard work surfaces only. Flipping for an existing " + "consented account requires re-running 'auth microsoft account " + "add --replace' to consent the additional scope.")
|
|
@@ -11465,7 +11465,7 @@ var init_schema = __esm(() => {
|
|
|
11465
11465
|
tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet — see RFC G §5).")
|
|
11466
11466
|
}).optional();
|
|
11467
11467
|
MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
11468
|
-
microsoft_client_id: exports_external.string().min(1).describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id')."),
|
|
11468
|
+
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL — omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
11469
11469
|
microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional — public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
|
|
11470
11470
|
authority: exports_external.string().url().optional().describe("Microsoft authority endpoint. Defaults to " + "'https://login.microsoftonline.com/common' which accepts both " + "personal MSA and work/school tenants. Override only for " + "single-tenant deployments."),
|
|
11471
11471
|
org_mode: exports_external.boolean().optional().describe("Opt-in to Teams + SharePoint surfaces (RFC §6.4). When true, " + "the v1 scope set adds Sites.ReadWrite.All AND the launcher " + "spawns softeria with --org-mode. Defaults to false — personal " + "MSA + standard work surfaces only. Flipping for an existing " + "consented account requires re-running 'auth microsoft account " + "add --replace' to consent the additional scope.")
|
package/package.json
CHANGED
|
@@ -23874,7 +23874,7 @@ var init_schema = __esm(() => {
|
|
|
23874
23874
|
tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet \u2014 see RFC G \u00a75).")
|
|
23875
23875
|
}).optional();
|
|
23876
23876
|
MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
23877
|
-
microsoft_client_id: exports_external.string().min(1).describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id')."),
|
|
23877
|
+
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL \u2014 omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
23878
23878
|
microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional \u2014 public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
|
|
23879
23879
|
authority: exports_external.string().url().optional().describe("Microsoft authority endpoint. Defaults to " + "'https://login.microsoftonline.com/common' which accepts both " + "personal MSA and work/school tenants. Override only for " + "single-tenant deployments."),
|
|
23880
23880
|
org_mode: exports_external.boolean().optional().describe("Opt-in to Teams + SharePoint surfaces (RFC \u00a76.4). When true, " + "the v1 scope set adds Sites.ReadWrite.All AND the launcher " + "spawns softeria with --org-mode. Defaults to false \u2014 personal " + "MSA + standard work surfaces only. Flipping for an existing " + "consented account requires re-running 'auth microsoft account " + "add --replace' to consent the additional scope.")
|
|
@@ -32729,7 +32729,7 @@ var MIRROR_MAX_LINES = 6;
|
|
|
32729
32729
|
function escapeFeedHtml(s) {
|
|
32730
32730
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
32731
32731
|
}
|
|
32732
|
-
function renderActivityFeed(lines, final = false) {
|
|
32732
|
+
function renderActivityFeed(lines, final = false, liveSuffix = "") {
|
|
32733
32733
|
if (lines.length === 0)
|
|
32734
32734
|
return null;
|
|
32735
32735
|
const shown = lines.slice(-MIRROR_MAX_LINES);
|
|
@@ -32740,7 +32740,7 @@ function renderActivityFeed(lines, final = false) {
|
|
|
32740
32740
|
const lastIdx = shown.length - 1;
|
|
32741
32741
|
shown.forEach((l, i) => {
|
|
32742
32742
|
const esc = escapeFeedHtml(l);
|
|
32743
|
-
out.push(i === lastIdx && !final ? `<b>\u2192 ${esc}</b>` : `<i>\u2713 ${esc}</i>`);
|
|
32743
|
+
out.push(i === lastIdx && !final ? `<b>\u2192 ${esc}${liveSuffix}</b>` : `<i>\u2713 ${esc}</i>`);
|
|
32744
32744
|
});
|
|
32745
32745
|
return out.join(`
|
|
32746
32746
|
`);
|
|
@@ -32748,10 +32748,10 @@ function renderActivityFeed(lines, final = false) {
|
|
|
32748
32748
|
var NESTED_MAX_LINES = 4;
|
|
32749
32749
|
var NESTED_LINE_MAX = 90;
|
|
32750
32750
|
var NESTED_PREFIX = " \u21b3 ";
|
|
32751
|
-
function renderActivityFeedWithNested(lines, childLines, final = false) {
|
|
32751
|
+
function renderActivityFeedWithNested(lines, childLines, final = false, liveSuffix = "") {
|
|
32752
32752
|
const children = childLines.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
32753
32753
|
if (children.length === 0)
|
|
32754
|
-
return renderActivityFeed(lines, final);
|
|
32754
|
+
return renderActivityFeed(lines, final, liveSuffix);
|
|
32755
32755
|
const out = [];
|
|
32756
32756
|
const shownParent = lines.slice(-MIRROR_MAX_LINES);
|
|
32757
32757
|
const hiddenParent = lines.length - shownParent.length;
|
|
@@ -32767,7 +32767,7 @@ function renderActivityFeedWithNested(lines, childLines, final = false) {
|
|
|
32767
32767
|
shownChild.forEach((l, i) => {
|
|
32768
32768
|
const t = l.length > NESTED_LINE_MAX ? l.slice(0, NESTED_LINE_MAX - 1) + "\u2026" : l;
|
|
32769
32769
|
const esc = escapeFeedHtml(t);
|
|
32770
|
-
out.push(i === lastChildIdx && !final ? `${NESTED_PREFIX}<b>\u2192 ${esc}</b>` : `${NESTED_PREFIX}<i>${esc}</i>`);
|
|
32770
|
+
out.push(i === lastChildIdx && !final ? `${NESTED_PREFIX}<b>\u2192 ${esc}${liveSuffix}</b>` : `${NESTED_PREFIX}<i>${esc}</i>`);
|
|
32771
32771
|
});
|
|
32772
32772
|
return out.length > 0 ? out.join(`
|
|
32773
32773
|
`) : null;
|
|
@@ -47132,6 +47132,92 @@ function createPendingInboundBuffer(opts = {}) {
|
|
|
47132
47132
|
};
|
|
47133
47133
|
}
|
|
47134
47134
|
|
|
47135
|
+
// gateway/obligation-ledger.ts
|
|
47136
|
+
class ObligationLedger {
|
|
47137
|
+
maxRepresents;
|
|
47138
|
+
open = new Map;
|
|
47139
|
+
constructor(maxRepresents = 2) {
|
|
47140
|
+
this.maxRepresents = maxRepresents;
|
|
47141
|
+
}
|
|
47142
|
+
openIfAbsent(input) {
|
|
47143
|
+
if (this.open.has(input.originTurnId))
|
|
47144
|
+
return false;
|
|
47145
|
+
this.open.set(input.originTurnId, { ...input, representCount: 0 });
|
|
47146
|
+
return true;
|
|
47147
|
+
}
|
|
47148
|
+
close(originTurnId) {
|
|
47149
|
+
if (originTurnId == null)
|
|
47150
|
+
return false;
|
|
47151
|
+
return this.open.delete(originTurnId);
|
|
47152
|
+
}
|
|
47153
|
+
isOpen(originTurnId) {
|
|
47154
|
+
return this.open.has(originTurnId);
|
|
47155
|
+
}
|
|
47156
|
+
hasOpen() {
|
|
47157
|
+
return this.open.size > 0;
|
|
47158
|
+
}
|
|
47159
|
+
size() {
|
|
47160
|
+
return this.open.size;
|
|
47161
|
+
}
|
|
47162
|
+
list() {
|
|
47163
|
+
return [...this.open.values()].sort((a, b) => a.openedAt - b.openedAt);
|
|
47164
|
+
}
|
|
47165
|
+
oldest() {
|
|
47166
|
+
let best;
|
|
47167
|
+
for (const o of this.open.values()) {
|
|
47168
|
+
if (best === undefined || o.openedAt < best.openedAt)
|
|
47169
|
+
best = o;
|
|
47170
|
+
}
|
|
47171
|
+
return best;
|
|
47172
|
+
}
|
|
47173
|
+
decideAtIdle() {
|
|
47174
|
+
const o = this.oldest();
|
|
47175
|
+
if (o === undefined)
|
|
47176
|
+
return { action: "none" };
|
|
47177
|
+
if (o.representCount >= this.maxRepresents)
|
|
47178
|
+
return { action: "escalate", obligation: o };
|
|
47179
|
+
return { action: "represent", obligation: o };
|
|
47180
|
+
}
|
|
47181
|
+
resolveCloseTarget(echoedTurnId, liveTurnId) {
|
|
47182
|
+
if (echoedTurnId != null)
|
|
47183
|
+
return echoedTurnId;
|
|
47184
|
+
if (liveTurnId != null && this.open.size === 1 && this.open.has(liveTurnId))
|
|
47185
|
+
return liveTurnId;
|
|
47186
|
+
return null;
|
|
47187
|
+
}
|
|
47188
|
+
markRepresented(originTurnId) {
|
|
47189
|
+
const o = this.open.get(originTurnId);
|
|
47190
|
+
if (o === undefined)
|
|
47191
|
+
return 0;
|
|
47192
|
+
o.representCount += 1;
|
|
47193
|
+
return o.representCount;
|
|
47194
|
+
}
|
|
47195
|
+
}
|
|
47196
|
+
var REPRESENT_PREVIEW_MAX = 200;
|
|
47197
|
+
function buildObligationRepresentInbound(o, now) {
|
|
47198
|
+
const preview = o.text.length > REPRESENT_PREVIEW_MAX ? o.text.slice(0, REPRESENT_PREVIEW_MAX - 1) + "\u2026" : o.text;
|
|
47199
|
+
const topicClause = o.threadId != null ? " in this topic" : "";
|
|
47200
|
+
return {
|
|
47201
|
+
type: "inbound",
|
|
47202
|
+
chatId: o.chatId,
|
|
47203
|
+
...o.threadId != null ? { threadId: o.threadId } : {},
|
|
47204
|
+
messageId: o.messageId,
|
|
47205
|
+
user: "switchroom",
|
|
47206
|
+
userId: 0,
|
|
47207
|
+
ts: now,
|
|
47208
|
+
text: `You have an earlier message${topicClause} that you started but never actually ` + `answered (you may have set it aside mid-work): "${preview}". Answer it now via the ` + `reply tool \u2014 deliver the real answer, don't just acknowledge it. If you've lost the ` + `surrounding context, call get_recent_messages for this chat${topicClause} first. ` + `That quoted text may be only the first ~200 characters of the original.`,
|
|
47209
|
+
meta: {
|
|
47210
|
+
source: "obligation_represent",
|
|
47211
|
+
origin_turn_id: o.originTurnId,
|
|
47212
|
+
represent_count: String(o.representCount + 1)
|
|
47213
|
+
}
|
|
47214
|
+
};
|
|
47215
|
+
}
|
|
47216
|
+
function obligationEscalationText(o) {
|
|
47217
|
+
const preview = o.text.length > REPRESENT_PREVIEW_MAX ? o.text.slice(0, REPRESENT_PREVIEW_MAX - 1) + "\u2026" : o.text;
|
|
47218
|
+
return `\u26a0\ufe0f I may have missed an earlier message and I'm not sure I answered it: ` + `"${preview}". If you still need it, please re-send.`;
|
|
47219
|
+
}
|
|
47220
|
+
|
|
47135
47221
|
// gateway/inbound-spool.ts
|
|
47136
47222
|
function spoolId(msg) {
|
|
47137
47223
|
if (msg.meta?.source === "subagent_handback" && typeof msg.meta?.subagent_jsonl_id === "string" && msg.meta.subagent_jsonl_id.length > 0) {
|
|
@@ -52224,10 +52310,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
52224
52310
|
}
|
|
52225
52311
|
|
|
52226
52312
|
// ../src/build-info.ts
|
|
52227
|
-
var VERSION = "0.14.
|
|
52228
|
-
var COMMIT_SHA = "
|
|
52229
|
-
var COMMIT_DATE = "2026-06-
|
|
52230
|
-
var LATEST_PR =
|
|
52313
|
+
var VERSION = "0.14.60";
|
|
52314
|
+
var COMMIT_SHA = "7a03004e";
|
|
52315
|
+
var COMMIT_DATE = "2026-06-04T07:56:20Z";
|
|
52316
|
+
var LATEST_PR = 2148;
|
|
52231
52317
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
52232
52318
|
|
|
52233
52319
|
// gateway/boot-version.ts
|
|
@@ -53425,6 +53511,10 @@ var _deliveryTimeoutParsed = _deliveryTimeoutRaw != null && _deliveryTimeoutRaw
|
|
|
53425
53511
|
var DELIVERY_CONFIRM_TIMEOUT_MS = Number.isFinite(_deliveryTimeoutParsed) && _deliveryTimeoutParsed > 0 ? _deliveryTimeoutParsed : 15000;
|
|
53426
53512
|
var DELIVERY_CONFIRM_SWEEP_MS = 5000;
|
|
53427
53513
|
var deliveryQueue = createDeliveryQueue();
|
|
53514
|
+
var OBLIGATION_LEDGER_ENABLED = process.env.SWITCHROOM_OBLIGATION_LEDGER === "1";
|
|
53515
|
+
var OBLIGATION_REPRESENT_MAX = 2;
|
|
53516
|
+
var OBLIGATION_SWEEP_MS = 5000;
|
|
53517
|
+
var obligationLedger = new ObligationLedger(OBLIGATION_REPRESENT_MAX);
|
|
53428
53518
|
var SERIALIZE_UNTIL_REPLIED_ENABLED = process.env.SWITCHROOM_SERIALIZE_UNTIL_REPLIED !== "0";
|
|
53429
53519
|
var _noReplyDrainRaw = process.env.SWITCHROOM_SERIALIZE_NOREPLY_DRAIN_MS;
|
|
53430
53520
|
var _noReplyDrainParsed = _noReplyDrainRaw != null && _noReplyDrainRaw !== "" ? Number(_noReplyDrainRaw) : 2500;
|
|
@@ -53433,6 +53523,16 @@ var TURN_ORIGIN_ROUTING_ENABLED = process.env.SWITCHROOM_TURN_ORIGIN_ROUTING !==
|
|
|
53433
53523
|
var TOPIC_FRAMING_ENABLED = process.env.SWITCHROOM_TOPIC_FRAMING !== "0";
|
|
53434
53524
|
var QUEUED_STATUS_UX_ENABLED = process.env.SWITCHROOM_QUEUED_STATUS_UX !== "0";
|
|
53435
53525
|
var FEED_REOPEN_AFTER_ACK_ENABLED = process.env.SWITCHROOM_FEED_REOPEN_AFTER_ACK !== "0";
|
|
53526
|
+
var FEED_HEARTBEAT_ENABLED = process.env.SWITCHROOM_FEED_HEARTBEAT !== "0";
|
|
53527
|
+
var FEED_HEARTBEAT_TICK_MS = 6000;
|
|
53528
|
+
var FEED_HEARTBEAT_MIN_STALE_MS = 6000;
|
|
53529
|
+
function formatFeedElapsed(ms) {
|
|
53530
|
+
const s = Math.floor(ms / 1000);
|
|
53531
|
+
if (s < 60)
|
|
53532
|
+
return `${s}s`;
|
|
53533
|
+
const m = Math.floor(s / 60);
|
|
53534
|
+
return `${m}m${(s % 60).toString().padStart(2, "0")}s`;
|
|
53535
|
+
}
|
|
53436
53536
|
function turnInFlightForGate() {
|
|
53437
53537
|
return isDeliveryCutoverEnabled() ? isMachineInTurn() : claudeBusyKeys.size > 0;
|
|
53438
53538
|
}
|
|
@@ -53473,6 +53573,37 @@ function findTurnByOriginId(originTurnId) {
|
|
|
53473
53573
|
return currentTurn;
|
|
53474
53574
|
return recentTurnsById.get(originTurnId) ?? null;
|
|
53475
53575
|
}
|
|
53576
|
+
function closeObligationOnSubstantiveReply(args, liveTurn) {
|
|
53577
|
+
if (!OBLIGATION_LEDGER_ENABLED)
|
|
53578
|
+
return;
|
|
53579
|
+
const echoed = findTurnByOriginId(args.origin_turn_id);
|
|
53580
|
+
const target = obligationLedger.resolveCloseTarget(echoed?.turnId, liveTurn?.turnId);
|
|
53581
|
+
if (target != null)
|
|
53582
|
+
obligationLedger.close(target);
|
|
53583
|
+
}
|
|
53584
|
+
function openObligationFromInbound(inboundMsg, gate) {
|
|
53585
|
+
if (!OBLIGATION_LEDGER_ENABLED)
|
|
53586
|
+
return;
|
|
53587
|
+
if (!shouldTrackDelivery({
|
|
53588
|
+
isSteering: gate.isSteering,
|
|
53589
|
+
isInterrupt: gate.isInterrupt,
|
|
53590
|
+
hasSource: inboundMsg.meta?.source != null,
|
|
53591
|
+
effectiveText: gate.effectiveText
|
|
53592
|
+
})) {
|
|
53593
|
+
return;
|
|
53594
|
+
}
|
|
53595
|
+
const oid = deriveTurnId(inboundMsg.chatId, inboundMsg.threadId, inboundMsg.messageId);
|
|
53596
|
+
if (oid == null)
|
|
53597
|
+
return;
|
|
53598
|
+
obligationLedger.openIfAbsent({
|
|
53599
|
+
originTurnId: oid,
|
|
53600
|
+
chatId: inboundMsg.chatId,
|
|
53601
|
+
threadId: inboundMsg.threadId,
|
|
53602
|
+
messageId: inboundMsg.messageId,
|
|
53603
|
+
text: inboundMsg.text ?? "",
|
|
53604
|
+
openedAt: Date.now()
|
|
53605
|
+
});
|
|
53606
|
+
}
|
|
53476
53607
|
function postQueuedStatus(chatId, bufferedThread, inFlightThread) {
|
|
53477
53608
|
if (!QUEUED_STATUS_UX_ENABLED)
|
|
53478
53609
|
return;
|
|
@@ -53675,6 +53806,9 @@ function endCurrentTurnAtomic(turn) {
|
|
|
53675
53806
|
if (currentTurn !== turn)
|
|
53676
53807
|
return;
|
|
53677
53808
|
currentTurn = null;
|
|
53809
|
+
if (OBLIGATION_LEDGER_ENABLED && turn.finalAnswerDelivered) {
|
|
53810
|
+
obligationLedger.close(turn.turnId);
|
|
53811
|
+
}
|
|
53678
53812
|
if (turn.noReplyDrainTimer != null) {
|
|
53679
53813
|
clearTimeout(turn.noReplyDrainTimer);
|
|
53680
53814
|
turn.noReplyDrainTimer = null;
|
|
@@ -54748,6 +54882,40 @@ var inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
|
54748
54882
|
}
|
|
54749
54883
|
});
|
|
54750
54884
|
var pendingInboundBuffer = createPendingInboundBuffer({ spool: inboundSpool });
|
|
54885
|
+
function obligationSweep() {
|
|
54886
|
+
if (!OBLIGATION_LEDGER_ENABLED)
|
|
54887
|
+
return;
|
|
54888
|
+
if (!obligationLedger.hasOpen())
|
|
54889
|
+
return;
|
|
54890
|
+
if (turnInFlightForGate())
|
|
54891
|
+
return;
|
|
54892
|
+
const agent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
54893
|
+
if (pendingInboundBuffer.depth(agent) > 0)
|
|
54894
|
+
return;
|
|
54895
|
+
const decision = obligationLedger.decideAtIdle();
|
|
54896
|
+
const o = decision.obligation;
|
|
54897
|
+
if (decision.action === "none" || o == null)
|
|
54898
|
+
return;
|
|
54899
|
+
if (decision.action === "represent") {
|
|
54900
|
+
pendingInboundBuffer.push(agent, buildObligationRepresentInbound(o, Date.now()));
|
|
54901
|
+
const attempt = obligationLedger.markRepresented(o.originTurnId);
|
|
54902
|
+
process.stderr.write(`telegram gateway: obligation re-presented origin=${o.originTurnId} attempt=${attempt}/${OBLIGATION_REPRESENT_MAX}
|
|
54903
|
+
`);
|
|
54904
|
+
return;
|
|
54905
|
+
}
|
|
54906
|
+
obligationLedger.close(o.originTurnId);
|
|
54907
|
+
process.stderr.write(`telegram gateway: obligation escalated (exhausted ${OBLIGATION_REPRESENT_MAX} re-presents) origin=${o.originTurnId}
|
|
54908
|
+
`);
|
|
54909
|
+
robustApiCall(() => bot.api.sendMessage(o.chatId, obligationEscalationText(o), {
|
|
54910
|
+
...o.threadId != null ? { message_thread_id: o.threadId } : {}
|
|
54911
|
+
}), { chat_id: o.chatId, ...o.threadId != null ? { threadId: o.threadId } : {}, verb: "obligation.escalate" }).catch((err) => {
|
|
54912
|
+
process.stderr.write(`telegram gateway: obligation escalation send failed: ${err}
|
|
54913
|
+
`);
|
|
54914
|
+
});
|
|
54915
|
+
}
|
|
54916
|
+
if (!STATIC && OBLIGATION_LEDGER_ENABLED) {
|
|
54917
|
+
setInterval(obligationSweep, OBLIGATION_SWEEP_MS).unref();
|
|
54918
|
+
}
|
|
54751
54919
|
if (bootResumeInbound != null) {
|
|
54752
54920
|
if (inboundSpool != null) {
|
|
54753
54921
|
inboundSpool.put(bootResumeInbound.agent, bootResumeInbound.msg);
|
|
@@ -55724,6 +55892,8 @@ ${url}`;
|
|
|
55724
55892
|
text: decision.mergedText,
|
|
55725
55893
|
disableNotification
|
|
55726
55894
|
});
|
|
55895
|
+
if (turn2.finalAnswerSubstantive)
|
|
55896
|
+
closeObligationOnSubstantiveReply(args, turn2);
|
|
55727
55897
|
}
|
|
55728
55898
|
outboundDedup.record(chat_id, threadId, decision.mergedText, Date.now(), turn2?.registryKey ?? null);
|
|
55729
55899
|
silentAnchorEditDone = true;
|
|
@@ -55925,6 +56095,8 @@ ${url}`;
|
|
|
55925
56095
|
turn.finalAnswerDelivered = true;
|
|
55926
56096
|
turn.finalAnswerSubstantive = isSubstantiveFinalReply({ text: rawText, disableNotification });
|
|
55927
56097
|
finalizeStatusReaction(chat_id, threadId, "done");
|
|
56098
|
+
if (turn.finalAnswerSubstantive)
|
|
56099
|
+
closeObligationOnSubstantiveReply(args, turn);
|
|
55928
56100
|
}
|
|
55929
56101
|
releaseTurnBufferGate(statusKey(chat_id, threadId), turn ?? undefined);
|
|
55930
56102
|
if (turn?.finalAnswerDelivered === true) {
|
|
@@ -56095,6 +56267,8 @@ async function executeStreamReply(args) {
|
|
|
56095
56267
|
disableNotification: args.disable_notification === true,
|
|
56096
56268
|
done: args.done === true
|
|
56097
56269
|
});
|
|
56270
|
+
if (turn.finalAnswerSubstantive)
|
|
56271
|
+
closeObligationOnSubstantiveReply(args, turn);
|
|
56098
56272
|
const streamThreadIdForClear = args.message_thread_id != null ? Number(args.message_thread_id) : undefined;
|
|
56099
56273
|
clearSilentEndState(statusKey(streamChatId, streamThreadIdForClear));
|
|
56100
56274
|
}
|
|
@@ -57086,12 +57260,12 @@ function closeProgressLane(chatId, threadId) {
|
|
|
57086
57260
|
}
|
|
57087
57261
|
}
|
|
57088
57262
|
var FOREGROUND_SUBAGENT_ACCUM_MAX = 12;
|
|
57089
|
-
function composeTurnActivity(turn, final = false) {
|
|
57263
|
+
function composeTurnActivity(turn, final = false, liveSuffix = "") {
|
|
57090
57264
|
const childLines = [];
|
|
57091
57265
|
for (const narrative of turn.foregroundSubAgents.values()) {
|
|
57092
57266
|
childLines.push(...narrative);
|
|
57093
57267
|
}
|
|
57094
|
-
return renderActivityFeedWithNested(turn.mirrorLines, childLines, final);
|
|
57268
|
+
return renderActivityFeedWithNested(turn.mirrorLines, childLines, final, liveSuffix);
|
|
57095
57269
|
}
|
|
57096
57270
|
async function drainActivitySummary(turn) {
|
|
57097
57271
|
try {
|
|
@@ -57130,6 +57304,30 @@ async function drainActivitySummary(turn) {
|
|
|
57130
57304
|
turn.activityInFlight = null;
|
|
57131
57305
|
}
|
|
57132
57306
|
}
|
|
57307
|
+
function feedHeartbeatTick() {
|
|
57308
|
+
const turn = currentTurn;
|
|
57309
|
+
if (turn == null)
|
|
57310
|
+
return;
|
|
57311
|
+
if (turn.activityMessageId == null)
|
|
57312
|
+
return;
|
|
57313
|
+
if (turn.finalAnswerDelivered)
|
|
57314
|
+
return;
|
|
57315
|
+
if (turn.lastToolLabelAt == null)
|
|
57316
|
+
return;
|
|
57317
|
+
const elapsed = Date.now() - turn.lastToolLabelAt;
|
|
57318
|
+
if (elapsed < FEED_HEARTBEAT_MIN_STALE_MS)
|
|
57319
|
+
return;
|
|
57320
|
+
const rendered = composeTurnActivity(turn, false, ` \xB7 ${formatFeedElapsed(elapsed)}`);
|
|
57321
|
+
if (rendered == null)
|
|
57322
|
+
return;
|
|
57323
|
+
turn.activityPendingRender = rendered;
|
|
57324
|
+
if (turn.activityInFlight == null) {
|
|
57325
|
+
turn.activityInFlight = drainActivitySummary(turn);
|
|
57326
|
+
}
|
|
57327
|
+
}
|
|
57328
|
+
if (!STATIC && FEED_HEARTBEAT_ENABLED) {
|
|
57329
|
+
setInterval(feedHeartbeatTick, FEED_HEARTBEAT_TICK_MS).unref();
|
|
57330
|
+
}
|
|
57133
57331
|
function clearActivitySummary(turn, finalHtmlOverride) {
|
|
57134
57332
|
const chat = turn.sessionChatId;
|
|
57135
57333
|
const thread = turn.sessionThreadId;
|
|
@@ -57314,6 +57512,7 @@ function handleSessionEvent(ev) {
|
|
|
57314
57512
|
}
|
|
57315
57513
|
const rendered = appendActivityLabel(turn.mirrorLines, ev.label);
|
|
57316
57514
|
if (rendered != null) {
|
|
57515
|
+
turn.lastToolLabelAt = Date.now();
|
|
57317
57516
|
turn.activityPendingRender = composeTurnActivity(turn) ?? rendered;
|
|
57318
57517
|
if (turn.activityInFlight == null) {
|
|
57319
57518
|
turn.activityInFlight = drainActivitySummary(turn);
|
|
@@ -58638,6 +58837,11 @@ ${preBlock(write.output)}`;
|
|
|
58638
58837
|
}
|
|
58639
58838
|
return;
|
|
58640
58839
|
}
|
|
58840
|
+
openObligationFromInbound(inboundMsg, {
|
|
58841
|
+
isSteering,
|
|
58842
|
+
isInterrupt: interrupt.isInterrupt,
|
|
58843
|
+
effectiveText
|
|
58844
|
+
});
|
|
58641
58845
|
if (decideInboundDelivery({
|
|
58642
58846
|
turnInFlight: turnInFlightAtReceipt,
|
|
58643
58847
|
isSteering,
|