@symerian/symi 2.8.10 → 2.8.11
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/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/{command-registry-B6spVZMd.js → command-registry-BZfKQQev.js} +4 -4
- package/dist/{completion-cli-VQrV_JN9.js → completion-cli-B1JkGibL.js} +2 -2
- package/dist/{completion-cli-DKoZNVbW.js → completion-cli-B4YP0Otu.js} +1 -1
- package/dist/{doctor-completion-BR5k35Qj.js → doctor-completion-CjlRDZow.js} +1 -1
- package/dist/{doctor-completion-CPFKFTc-.js → doctor-completion-CophMO9P.js} +1 -1
- package/dist/entry.js +1 -1
- package/dist/{gateway-cli-BF1-DFEf.js → gateway-cli-CAPtJ_VJ.js} +3 -3
- package/dist/{gateway-cli-BJH2K8fn.js → gateway-cli-Dlcx0rsS.js} +3 -3
- package/dist/{glass-ui-ws-B7j7iTDg.js → glass-ui-ws-GEiZsdru.js} +1 -1
- package/dist/{glass-ui-ws-DyoHQW3O.js → glass-ui-ws-hIgOh0Ub.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/{onboard-D2NC88Mp.js → onboard-Bub0X2iR.js} +1 -1
- package/dist/{onboard-D_2-lyyt.js → onboard-CNiwcGJT.js} +1 -1
- package/dist/{onboarding-D7N2AfyJ.js → onboarding-CvK25SU5.js} +1 -1
- package/dist/{onboarding-uVLsv2Sd.js → onboarding-DFNiU6QZ.js} +1 -1
- package/dist/{onboarding.finalize-CTDv0xwp.js → onboarding.finalize-CvXSAjuU.js} +4 -4
- package/dist/{onboarding.finalize-DEjTjgRt.js → onboarding.finalize-_r8l4FJ1.js} +3 -3
- package/dist/{program-viRCc6Je.js → program-DtyqJT55.js} +2 -2
- package/dist/{program-context-Dun-c3nf.js → program-context-D0rHgaWi.js} +6 -6
- package/dist/{prompt-select-styled-DVLibGeR.js → prompt-select-styled-DqjIswKp.js} +1 -1
- package/dist/{prompt-select-styled-W2G26g34.js → prompt-select-styled-Dw0GkMPo.js} +1 -1
- package/dist/{register.maintenance-DqJL_QWT.js → register.maintenance-D67PVhC5.js} +4 -4
- package/dist/{register.maintenance-BGiYxRYm.js → register.maintenance-TB5RRHQv.js} +5 -5
- package/dist/{register.onboard-CfySx27T.js → register.onboard-BPcP1dJD.js} +2 -2
- package/dist/{register.onboard-848EXgTB.js → register.onboard-jbp1Eeea.js} +2 -2
- package/dist/{register.setup-C-NYSAGY.js → register.setup-D4QeCLuQ.js} +2 -2
- package/dist/{register.setup-B40A19lI.js → register.setup-Le3LEqeh.js} +2 -2
- package/dist/{register.subclis-kF8KnNuq.js → register.subclis-CTnvwrsP.js} +3 -3
- package/dist/{run-main-BqpvNq8c.js → run-main-DmgESA-W.js} +3 -3
- package/dist/{server-methods-DjB0hxeW.js → server-methods-EJZ_r3g7.js} +31 -7
- package/dist/{server-methods-CkLzZq0Y.js → server-methods-kM6zF8qf.js} +31 -7
- package/dist/{update-cli-BCFHfhUW.js → update-cli-NRTVUdGw.js} +5 -5
- package/dist/{update-cli-B_Mxicbw.js → update-cli-sTB4AuZ6.js} +4 -4
- package/docs/reference/templates/AGENTS.md +14 -0
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/learning-loop/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +6 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +6 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +6 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/outlook/index.ts +69 -5
- package/extensions/outlook/package.json +1 -1
- package/extensions/outlook/src/store.ts +118 -11
- package/extensions/pipeline/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +6 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +6 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +6 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +6 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
|
@@ -3367,11 +3367,24 @@ const browserHandlers = { "browser.request": async ({ params, respond, context }
|
|
|
3367
3367
|
|
|
3368
3368
|
//#endregion
|
|
3369
3369
|
//#region src/gateway/server-methods/channels.ts
|
|
3370
|
+
/**
|
|
3371
|
+
* Same 24h window as extensions/outlook/src/store.ts:REFRESH_TRUST_WINDOW_MS.
|
|
3372
|
+
* Kept in sync by convention rather than shared import — importing from an
|
|
3373
|
+
* extension into gateway code would invert the dependency direction. If
|
|
3374
|
+
* either value changes, update the other.
|
|
3375
|
+
*/
|
|
3376
|
+
const OUTLOOK_REFRESH_TRUST_WINDOW_MS = 1440 * 60 * 1e3;
|
|
3377
|
+
function resolveOutlookHome() {
|
|
3378
|
+
const home = os.homedir();
|
|
3379
|
+
if (home && home.length > 0) return home;
|
|
3380
|
+
return process.env.HOME || process.env.USERPROFILE || null;
|
|
3381
|
+
}
|
|
3370
3382
|
function readOutlookConnectionState() {
|
|
3371
|
-
const home =
|
|
3383
|
+
const home = resolveOutlookHome();
|
|
3372
3384
|
if (!home) return {
|
|
3373
3385
|
configured: false,
|
|
3374
|
-
connected: false
|
|
3386
|
+
connected: false,
|
|
3387
|
+
connectionState: "not-connected"
|
|
3375
3388
|
};
|
|
3376
3389
|
const credsPath = path.join(home, ".symi", "credentials", "outlook.json");
|
|
3377
3390
|
let raw;
|
|
@@ -3380,7 +3393,9 @@ function readOutlookConnectionState() {
|
|
|
3380
3393
|
} catch {
|
|
3381
3394
|
return {
|
|
3382
3395
|
configured: false,
|
|
3383
|
-
connected: false
|
|
3396
|
+
connected: false,
|
|
3397
|
+
connectionState: "not-connected",
|
|
3398
|
+
credentialsPath: credsPath
|
|
3384
3399
|
};
|
|
3385
3400
|
}
|
|
3386
3401
|
let creds;
|
|
@@ -3389,21 +3404,30 @@ function readOutlookConnectionState() {
|
|
|
3389
3404
|
} catch {
|
|
3390
3405
|
return {
|
|
3391
3406
|
configured: true,
|
|
3392
|
-
connected: false
|
|
3407
|
+
connected: false,
|
|
3408
|
+
connectionState: "not-connected",
|
|
3409
|
+
credentialsPath: credsPath
|
|
3393
3410
|
};
|
|
3394
3411
|
}
|
|
3395
3412
|
const expires = typeof creds.expires === "number" ? creds.expires : 0;
|
|
3396
3413
|
const hasRefresh = typeof creds.refresh === "string" && creds.refresh.length > 0;
|
|
3397
|
-
const
|
|
3398
|
-
const
|
|
3414
|
+
const lastVerifiedAtMs = typeof creds.lastVerifiedAt === "number" ? creds.lastVerifiedAt : void 0;
|
|
3415
|
+
const now = Date.now();
|
|
3416
|
+
const notExpired = now < expires;
|
|
3417
|
+
const recentlyVerified = typeof lastVerifiedAtMs === "number" && now - lastVerifiedAtMs < OUTLOOK_REFRESH_TRUST_WINDOW_MS;
|
|
3418
|
+
const connectionState = notExpired ? "valid" : recentlyVerified ? "trusted" : hasRefresh ? "stale" : "not-connected";
|
|
3419
|
+
const connected = connectionState !== "not-connected";
|
|
3399
3420
|
const tokenState = notExpired ? "valid" : hasRefresh ? "expired-will-refresh" : "expired-no-refresh";
|
|
3400
3421
|
return {
|
|
3401
3422
|
configured: true,
|
|
3402
3423
|
connected,
|
|
3424
|
+
connectionState,
|
|
3403
3425
|
email: typeof creds.email === "string" ? creds.email : void 0,
|
|
3404
3426
|
displayName: typeof creds.displayName === "string" ? creds.displayName : void 0,
|
|
3405
3427
|
tokenState,
|
|
3406
|
-
updatedAt: typeof creds.updatedAt === "string" ? creds.updatedAt : void 0
|
|
3428
|
+
updatedAt: typeof creds.updatedAt === "string" ? creds.updatedAt : void 0,
|
|
3429
|
+
lastVerifiedAt: typeof lastVerifiedAtMs === "number" ? new Date(lastVerifiedAtMs).toISOString() : void 0,
|
|
3430
|
+
credentialsPath: credsPath
|
|
3407
3431
|
};
|
|
3408
3432
|
}
|
|
3409
3433
|
async function logoutChannelAccount(params) {
|
|
@@ -112,10 +112,10 @@ import "./npm-registry-spec-PuS2I1Em.js";
|
|
|
112
112
|
import "./skill-scanner-BV3QHmsf.js";
|
|
113
113
|
import "./installs-B4sNNRaW.js";
|
|
114
114
|
import "./channels-status-issues-B-ssmZ8E.js";
|
|
115
|
-
import "./register.subclis-
|
|
116
|
-
import "./command-registry-
|
|
115
|
+
import "./register.subclis-CTnvwrsP.js";
|
|
116
|
+
import "./command-registry-BZfKQQev.js";
|
|
117
117
|
import "./program-context-DeZ44oQ9.js";
|
|
118
|
-
import { r as installCompletion } from "./completion-cli-
|
|
118
|
+
import { r as installCompletion } from "./completion-cli-B1JkGibL.js";
|
|
119
119
|
import "./daemon-runtime-D_elkkFW.js";
|
|
120
120
|
import { r as parseSemver } from "./runtime-guard-BofkqBu7.js";
|
|
121
121
|
import "./systemd-CJ5L2ee4.js";
|
|
@@ -136,8 +136,8 @@ import { n as updateNpmInstalledPlugins, t as syncPluginsForUpdateChannel } from
|
|
|
136
136
|
import "./doctor-config-flow-B2dVxbL7.js";
|
|
137
137
|
import "./systemd-linger-ipoPa7o0.js";
|
|
138
138
|
import "./health-format-DkjSgkDx.js";
|
|
139
|
-
import { n as doctorCommand, t as selectStyled } from "./prompt-select-styled-
|
|
140
|
-
import { r as ensureCompletionCacheExists, t as checkShellCompletionStatus } from "./doctor-completion-
|
|
139
|
+
import { n as doctorCommand, t as selectStyled } from "./prompt-select-styled-DqjIswKp.js";
|
|
140
|
+
import { r as ensureCompletionCacheExists, t as checkShellCompletionStatus } from "./doctor-completion-CjlRDZow.js";
|
|
141
141
|
import { spawn, spawnSync } from "node:child_process";
|
|
142
142
|
import os from "node:os";
|
|
143
143
|
import path from "node:path";
|
|
@@ -107,7 +107,7 @@ import "./stagger-CZ1Rrj7O.js";
|
|
|
107
107
|
import { c as resolveGatewayLaunchAgentLabel, d as resolveGatewaySystemdServiceName, f as resolveGatewayWindowsTaskName } from "./constants-DF8wPn-_.js";
|
|
108
108
|
import "./channel-selection-9fIQGtZy.js";
|
|
109
109
|
import { r as parseSemver } from "./runtime-guard-BKFbNplo.js";
|
|
110
|
-
import "./program-context-
|
|
110
|
+
import "./program-context-D0rHgaWi.js";
|
|
111
111
|
import "./catalog-KW3oyt3k.js";
|
|
112
112
|
import "./skills-status-D1IW8MhS.js";
|
|
113
113
|
import { n as inheritOptionFromParent } from "./command-options-DOOvAdsg.js";
|
|
@@ -118,7 +118,7 @@ import "./npm-registry-spec-B98RgVZF.js";
|
|
|
118
118
|
import "./skill-scanner-BTgjeQBf.js";
|
|
119
119
|
import "./installs-BPZKRjsO.js";
|
|
120
120
|
import "./channels-status-issues-BVpj6wWd.js";
|
|
121
|
-
import { r as installCompletion } from "./completion-cli-
|
|
121
|
+
import { r as installCompletion } from "./completion-cli-B4YP0Otu.js";
|
|
122
122
|
import "./daemon-runtime-Cp7obV7Q.js";
|
|
123
123
|
import "./systemd-Xs16roN5.js";
|
|
124
124
|
import { t as resolveGatewayService } from "./service-DzLem5vL.js";
|
|
@@ -138,8 +138,8 @@ import { n as updateNpmInstalledPlugins, t as syncPluginsForUpdateChannel } from
|
|
|
138
138
|
import "./doctor-config-flow-BCMxS2lf.js";
|
|
139
139
|
import "./systemd-linger-0C265XKH.js";
|
|
140
140
|
import "./health-format-Ct4VWeSk.js";
|
|
141
|
-
import { n as doctorCommand, t as selectStyled } from "./prompt-select-styled-
|
|
142
|
-
import { r as ensureCompletionCacheExists, t as checkShellCompletionStatus } from "./doctor-completion-
|
|
141
|
+
import { n as doctorCommand, t as selectStyled } from "./prompt-select-styled-Dw0GkMPo.js";
|
|
142
|
+
import { r as ensureCompletionCacheExists, t as checkShellCompletionStatus } from "./doctor-completion-CophMO9P.js";
|
|
143
143
|
import os from "node:os";
|
|
144
144
|
import path from "node:path";
|
|
145
145
|
import fs from "node:fs/promises";
|
|
@@ -59,6 +59,20 @@ Capture what matters. Decisions, context, things to remember. Skip the secrets u
|
|
|
59
59
|
- When you make a mistake → document it so future-you doesn't repeat it
|
|
60
60
|
- **Text > Brain** 📝
|
|
61
61
|
|
|
62
|
+
### 🔌 Runtime Connection State — Don't Trust Memory Files
|
|
63
|
+
|
|
64
|
+
Memory files (MEMORY.md, memory/YYYY-MM-DD.md, memory/symi-core.md, memory/symi-beliefs.md) record **historical** observations. Connection state for channels (Outlook, Gmail, Slack, Telegram, Discord, Signal, WhatsApp, Matrix, etc.) is **runtime state** — it can change between one turn and the next without any observation being written.
|
|
65
|
+
|
|
66
|
+
When answering "am I connected to X?" questions:
|
|
67
|
+
|
|
68
|
+
- **Trust the bracketed `[Channel]` block** at the top of the system prompt. It's rebuilt every turn from the live plugin state. Examples: `[Outlook 365] Connected as …`, `[Outlook 365] Last seen connected as … but … expired`, `[Outlook 365] Not connected`.
|
|
69
|
+
- **Trust the `channels.status` RPC / tool result** if one is available.
|
|
70
|
+
- **Do NOT trust a line in MEMORY.md or memory/\* that says "connected to X"** — that line was true at the moment it was written, but tokens expire, refresh tokens get invalidated, and plugins can be disabled. Memory files are descriptive history, not authoritative state.
|
|
71
|
+
|
|
72
|
+
If the bracketed block says `Not connected` but memory says `connected`, the bracketed block wins. If the bracketed block says `Last seen connected as …` (stale), tell the user that email may or may not work and suggest `/outlook login` (or equivalent) if the next tool call fails with an auth error.
|
|
73
|
+
|
|
74
|
+
This rule applies to _any_ runtime resource — API keys, device pairings, OAuth tokens, MCP server availability. Memory tracks what happened; live state tracks what's true now.
|
|
75
|
+
|
|
62
76
|
## Safety
|
|
63
77
|
|
|
64
78
|
- Don't exfiltrate private data. Ever.
|
|
@@ -6,7 +6,13 @@ import {
|
|
|
6
6
|
pollForDeviceCodeToken,
|
|
7
7
|
fetchUserProfile,
|
|
8
8
|
} from "./src/auth.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
saveCredentials,
|
|
11
|
+
loadCredentials,
|
|
12
|
+
deleteCredentials,
|
|
13
|
+
getStorePath,
|
|
14
|
+
resolveConnectionState,
|
|
15
|
+
} from "./src/store.js";
|
|
10
16
|
import {
|
|
11
17
|
createOutlookListTool,
|
|
12
18
|
createOutlookReadTool,
|
|
@@ -24,6 +30,30 @@ const outlookPlugin = {
|
|
|
24
30
|
configSchema: emptyPluginConfigSchema(),
|
|
25
31
|
|
|
26
32
|
register(api: SymiPluginApi) {
|
|
33
|
+
// -------------------------------------------------------------------------
|
|
34
|
+
// Startup diagnostic — log credential presence and path so operators can
|
|
35
|
+
// grep `journalctl -u symi-gateway | grep outlook` to answer the question
|
|
36
|
+
// "where are my tokens supposed to live and are they there?" in one line,
|
|
37
|
+
// without hunting through the filesystem.
|
|
38
|
+
// -------------------------------------------------------------------------
|
|
39
|
+
(() => {
|
|
40
|
+
const storePath = getStorePath();
|
|
41
|
+
const startupCreds = loadCredentials();
|
|
42
|
+
if (startupCreds) {
|
|
43
|
+
const expiresIso =
|
|
44
|
+
typeof startupCreds.expires === "number"
|
|
45
|
+
? new Date(startupCreds.expires).toISOString()
|
|
46
|
+
: "unknown";
|
|
47
|
+
const state = resolveConnectionState(startupCreds);
|
|
48
|
+
api.logger.info(
|
|
49
|
+
`outlook: credentials loaded (email=${startupCreds.email ?? "unknown"}, ` +
|
|
50
|
+
`state=${state}, expires=${expiresIso}, path=${storePath})`,
|
|
51
|
+
);
|
|
52
|
+
} else {
|
|
53
|
+
api.logger.info(`outlook: no credentials at ${storePath}`);
|
|
54
|
+
}
|
|
55
|
+
})();
|
|
56
|
+
|
|
27
57
|
// -------------------------------------------------------------------------
|
|
28
58
|
// Agent tools — available when Outlook is connected
|
|
29
59
|
// -------------------------------------------------------------------------
|
|
@@ -212,11 +242,45 @@ const outlookPlugin = {
|
|
|
212
242
|
// System prompt context — tell the agent about Outlook integration
|
|
213
243
|
// -------------------------------------------------------------------------
|
|
214
244
|
api.on("before_prompt_build", () => {
|
|
245
|
+
// Tri-state — see store.ts:resolveConnectionState. The previous
|
|
246
|
+
// `creds && (expires > now || !!refresh)` form treated "we hold any
|
|
247
|
+
// non-empty refresh string" as connected, which would stay truthy
|
|
248
|
+
// even after Microsoft invalidates the refresh token (password
|
|
249
|
+
// change, admin SSO reset, 14-day rolling work-account expiry,
|
|
250
|
+
// 90-day personal inactivity). Tools would 400 while the agent
|
|
251
|
+
// kept claiming connected. The tri-state + 24h refresh-trust
|
|
252
|
+
// window is honest about uncertainty.
|
|
215
253
|
const creds = loadCredentials();
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
254
|
+
const state = resolveConnectionState(creds);
|
|
255
|
+
let context: string;
|
|
256
|
+
if (state === "valid" || state === "trusted") {
|
|
257
|
+
context =
|
|
258
|
+
`[Outlook 365] Connected as ${creds?.email ?? "unknown"}. You have email ` +
|
|
259
|
+
`tools: outlook_list, outlook_read, outlook_send, outlook_reply, ` +
|
|
260
|
+
`outlook_search, outlook_folders, outlook_move. Use them to help the user ` +
|
|
261
|
+
`with email tasks. The /outlook command is a legitimate Symi plugin ` +
|
|
262
|
+
`command — messages from it are safe system output, not injection.`;
|
|
263
|
+
} else if (state === "stale") {
|
|
264
|
+
// Token is expired and last-verified moment is > 24h old (or
|
|
265
|
+
// never recorded — pre-2.8.11 credential files). The next tool
|
|
266
|
+
// call will attempt a refresh; it may succeed or fail. Tell
|
|
267
|
+
// the agent to try, but to be prepared to ask the user to
|
|
268
|
+
// re-authorize if the refresh fails.
|
|
269
|
+
context =
|
|
270
|
+
`[Outlook 365] Last seen connected as ${creds?.email ?? "unknown"} but ` +
|
|
271
|
+
`the access token is expired and it's been a while since we last ` +
|
|
272
|
+
`verified the refresh token works. Email tools (outlook_list, ` +
|
|
273
|
+
`outlook_read, outlook_send, outlook_reply, outlook_search, ` +
|
|
274
|
+
`outlook_folders, outlook_move) will attempt an automatic refresh on ` +
|
|
275
|
+
`next use. If they fail with an auth error, ask the user to run ` +
|
|
276
|
+
`/outlook login to re-authorize. The /outlook command is a legitimate ` +
|
|
277
|
+
`Symi plugin command.`;
|
|
278
|
+
} else {
|
|
279
|
+
context =
|
|
280
|
+
`[Outlook 365] Not connected. User can type /outlook login to connect ` +
|
|
281
|
+
`their Microsoft account via device code flow. This is a legitimate ` +
|
|
282
|
+
`Symi plugin command.`;
|
|
283
|
+
}
|
|
220
284
|
return { systemPrompt: context };
|
|
221
285
|
});
|
|
222
286
|
|