@rubytech/create-sitedesk-code 0.1.528 → 0.1.529
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/package.json +1 -1
- package/payload/platform/lib/account-ingest-token/dist/index.d.ts +21 -0
- package/payload/platform/lib/account-ingest-token/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/account-ingest-token/dist/index.js +128 -0
- package/payload/platform/lib/account-ingest-token/dist/index.js.map +1 -0
- package/payload/platform/lib/account-ingest-token/src/index.ts +137 -0
- package/payload/platform/lib/account-ingest-token/tsconfig.json +8 -0
- package/payload/platform/lib/agent-dispatch-rule/dist/index.d.ts +5 -0
- package/payload/platform/lib/agent-dispatch-rule/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/agent-dispatch-rule/dist/index.js.map +1 -1
- package/payload/platform/lib/agent-dispatch-rule/src/index.ts +5 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +5 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +37 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/linkedin-ingest-token.d.ts +10 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/linkedin-ingest-token.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/linkedin-ingest-token.js +22 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/linkedin-ingest-token.js.map +1 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +25 -4
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +22 -1
- package/payload/platform/plugins/docs/references/linkedin-extension.md +2 -2
- package/payload/platform/plugins/linkedin-extension/extension/README.md +3 -3
- package/payload/platform/plugins/linkedin-extension/extension/background/sw.js +12 -7
- package/payload/platform/plugins/linkedin-extension/extension/content/profile.js +4 -1
- package/payload/platform/plugins/linkedin-extension/extension/content/thread.js +4 -1
- package/payload/platform/plugins/linkedin-extension/extension/options/options.html +3 -3
- package/payload/platform/plugins/linkedin-extension/extension/options/options.js +24 -16
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/suspension-census.test.js +45 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/suspension-census.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +15 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/server/public/activity.html +5 -5
- package/payload/server/public/agents.html +4 -4
- package/payload/server/public/assets/{AdminLoginScreens-Bx9vPuUg.js → AdminLoginScreens-zfexKfbT.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-zfexKfbT.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-zfexKfbT.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-BxJPbC3p.js → AdminShell-Cbk0TL1B.js} +1 -1
- package/payload/server/public/assets/AdminShell-Cbk0TL1B.js.br +0 -0
- package/payload/server/public/assets/AdminShell-Cbk0TL1B.js.gz +0 -0
- package/payload/server/public/assets/{CdpScreencastSurface-5HLhTQTV.js → CdpScreencastSurface-CLSQHh4e.js} +1 -1
- package/payload/server/public/assets/CdpScreencastSurface-CLSQHh4e.js.br +0 -0
- package/payload/server/public/assets/CdpScreencastSurface-CLSQHh4e.js.gz +0 -0
- package/payload/server/public/assets/{activity-BaSYn62l.js → activity-u275Oc-u.js} +1 -1
- package/payload/server/public/assets/activity-u275Oc-u.js.br +0 -0
- package/payload/server/public/assets/activity-u275Oc-u.js.gz +0 -0
- package/payload/server/public/assets/{admin-CYCKrV_x.js → admin-Du1nR_hP.js} +1 -1
- package/payload/server/public/assets/admin-Du1nR_hP.js.br +0 -0
- package/payload/server/public/assets/admin-Du1nR_hP.js.gz +0 -0
- package/payload/server/public/assets/{agents-D8EJG-ta.js → agents-DJTxRLLU.js} +1 -1
- package/payload/server/public/assets/agents-DJTxRLLU.js.br +0 -0
- package/payload/server/public/assets/agents-DJTxRLLU.js.gz +0 -0
- package/payload/server/public/assets/{browser-D6Y_Zu8C.js → browser-Bft6zVkX.js} +1 -1
- package/payload/server/public/assets/browser-Bft6zVkX.js.br +0 -0
- package/payload/server/public/assets/browser-Bft6zVkX.js.gz +0 -0
- package/payload/server/public/assets/{calendar-DD4oVa-r.js → calendar-Ct-DCCqY.js} +1 -1
- package/payload/server/public/assets/calendar-Ct-DCCqY.js.br +0 -0
- package/payload/server/public/assets/calendar-Ct-DCCqY.js.gz +0 -0
- package/payload/server/public/assets/chat-pqasbAg8.js +1 -0
- package/payload/server/public/assets/chat-pqasbAg8.js.br +0 -0
- package/payload/server/public/assets/chat-pqasbAg8.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-C8LTc7lb.js +1 -0
- package/payload/server/public/assets/chevron-right-Lz9t7Hed.js +1 -0
- package/payload/server/public/assets/chevron-right-Lz9t7Hed.js.br +0 -0
- package/payload/server/public/assets/clock-D6QQFHwJ.js +1 -0
- package/payload/server/public/assets/clock-D6QQFHwJ.js.br +0 -0
- package/payload/server/public/assets/clock-D6QQFHwJ.js.gz +0 -0
- package/payload/server/public/assets/data-B1JJ3Y1T.js +1 -0
- package/payload/server/public/assets/data-B1JJ3Y1T.js.br +0 -0
- package/payload/server/public/assets/data-B1JJ3Y1T.js.gz +0 -0
- package/payload/server/public/assets/{file-download-sXU3_umF.js → file-download-C_fSe4dm.js} +1 -1
- package/payload/server/public/assets/file-download-C_fSe4dm.js.br +0 -0
- package/payload/server/public/assets/file-download-C_fSe4dm.js.gz +0 -0
- package/payload/server/public/assets/{file-text-CeXBviDH.js → file-text-D7GbEcqj.js} +1 -1
- package/payload/server/public/assets/file-text-D7GbEcqj.js.br +0 -0
- package/payload/server/public/assets/file-text-D7GbEcqj.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-D2pQkgYW.js → graph-labels-Dlcb6cW7.js} +1 -1
- package/payload/server/public/assets/graph-labels-Dlcb6cW7.js.br +0 -0
- package/payload/server/public/assets/graph-labels-Dlcb6cW7.js.gz +0 -0
- package/payload/server/public/assets/{graph-BSuDP6k7.js → graph-yl5qU1kO.js} +1 -1
- package/payload/server/public/assets/graph-yl5qU1kO.js.br +0 -0
- package/payload/server/public/assets/graph-yl5qU1kO.js.gz +0 -0
- package/payload/server/public/assets/{maximize-2-DlzSNygU.js → maximize-2-BS689r4W.js} +1 -1
- package/payload/server/public/assets/maximize-2-BS689r4W.js.br +0 -0
- package/payload/server/public/assets/maximize-2-BS689r4W.js.gz +0 -0
- package/payload/server/public/assets/{operator-BP61-xjz.js → operator-CvapnpIW.js} +1 -1
- package/payload/server/public/assets/operator-CvapnpIW.js.br +0 -0
- package/payload/server/public/assets/operator-CvapnpIW.js.gz +0 -0
- package/payload/server/public/assets/{page-eQ4OVros.js → page-987y4JbQ.js} +1 -1
- package/payload/server/public/assets/page-987y4JbQ.js.br +0 -0
- package/payload/server/public/assets/page-987y4JbQ.js.gz +0 -0
- package/payload/server/public/assets/{page-DX7ArY_s.js → page-DWkUH4Z_.js} +1 -1
- package/payload/server/public/assets/page-DWkUH4Z_.js.br +0 -0
- package/payload/server/public/assets/page-DWkUH4Z_.js.gz +0 -0
- package/payload/server/public/assets/{public-DPDKFKM2.js → public-D5pi-VFn.js} +1 -1
- package/payload/server/public/assets/public-D5pi-VFn.js.br +0 -0
- package/payload/server/public/assets/public-D5pi-VFn.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-BR0JbPFV.js → rotate-ccw-zNxnK36R.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-zNxnK36R.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-zNxnK36R.js.gz +0 -0
- package/payload/server/public/assets/routines-mZzrGA5y.js +2 -0
- package/payload/server/public/assets/routines-mZzrGA5y.js.br +0 -0
- package/payload/server/public/assets/routines-mZzrGA5y.js.gz +0 -0
- package/payload/server/public/assets/{skills-fH0uA7cj.js → skills-5A8PockT.js} +1 -1
- package/payload/server/public/assets/skills-5A8PockT.js.br +0 -0
- package/payload/server/public/assets/skills-5A8PockT.js.gz +0 -0
- package/payload/server/public/assets/{tasks-CrVzFrTR.js → tasks-B1_2wc6L.js} +1 -1
- package/payload/server/public/assets/tasks-B1_2wc6L.js.br +0 -0
- package/payload/server/public/assets/tasks-B1_2wc6L.js.gz +0 -0
- package/payload/server/public/assets/{time-entry-format-C_0jiMpQ.js → time-entry-format-CJ2FSSQt.js} +1 -1
- package/payload/server/public/assets/time-entry-format-CJ2FSSQt.js.br +0 -0
- package/payload/server/public/assets/time-entry-format-CJ2FSSQt.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-eLJHC_QJ.js → triangle-alert-CedsrgME.js} +1 -1
- package/payload/server/public/assets/triangle-alert-CedsrgME.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-CedsrgME.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-vPCmdOmY.js → useCopyFeedback-zjZZUC2-.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-zjZZUC2-.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-zjZZUC2-.js.gz +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-DxuUS_C7.css → useSubAccountSwitcher-72THldvm.css} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-72THldvm.css.br +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-DxuUS_C7.css.gz → useSubAccountSwitcher-72THldvm.css.gz} +0 -0
- package/payload/server/public/assets/{useVoiceRecorder-D5bFDRqL.js → useVoiceRecorder-CJecnefX.js} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-CJecnefX.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-CJecnefX.js.gz +0 -0
- package/payload/server/public/assets/{wrench-sXisQXkf.js → wrench-D8BH20W8.js} +1 -1
- package/payload/server/public/assets/wrench-D8BH20W8.js.br +0 -0
- package/payload/server/public/assets/wrench-D8BH20W8.js.gz +0 -0
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +7 -7
- package/payload/server/public/chat.html +13 -13
- package/payload/server/public/data.html +12 -12
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +16 -16
- package/payload/server/public/operator.html +15 -15
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/routines.html +7 -7
- package/payload/server/public/skills.html +5 -5
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +343 -205
- package/payload/server/public/assets/AdminLoginScreens-Bx9vPuUg.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-Bx9vPuUg.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-BxJPbC3p.js.br +0 -0
- package/payload/server/public/assets/AdminShell-BxJPbC3p.js.gz +0 -0
- package/payload/server/public/assets/CdpScreencastSurface-5HLhTQTV.js.br +0 -0
- package/payload/server/public/assets/CdpScreencastSurface-5HLhTQTV.js.gz +0 -0
- package/payload/server/public/assets/activity-BaSYn62l.js.br +0 -0
- package/payload/server/public/assets/activity-BaSYn62l.js.gz +0 -0
- package/payload/server/public/assets/admin-CYCKrV_x.js.br +0 -0
- package/payload/server/public/assets/admin-CYCKrV_x.js.gz +0 -0
- package/payload/server/public/assets/agents-D8EJG-ta.js.br +0 -0
- package/payload/server/public/assets/agents-D8EJG-ta.js.gz +0 -0
- package/payload/server/public/assets/browser-D6Y_Zu8C.js.br +0 -0
- package/payload/server/public/assets/browser-D6Y_Zu8C.js.gz +0 -0
- package/payload/server/public/assets/calendar-DD4oVa-r.js.br +0 -0
- package/payload/server/public/assets/calendar-DD4oVa-r.js.gz +0 -0
- package/payload/server/public/assets/chat-CwWs69PO.js +0 -1
- package/payload/server/public/assets/chat-CwWs69PO.js.br +0 -0
- package/payload/server/public/assets/chat-CwWs69PO.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-ClfIy5Fx.js +0 -1
- package/payload/server/public/assets/chevron-right-B0QvXpxl.js +0 -1
- package/payload/server/public/assets/chevron-right-B0QvXpxl.js.br +0 -0
- package/payload/server/public/assets/clock-BIaRnIP_.js +0 -1
- package/payload/server/public/assets/clock-BIaRnIP_.js.br +0 -0
- package/payload/server/public/assets/clock-BIaRnIP_.js.gz +0 -0
- package/payload/server/public/assets/data-O_9Kiicl.js +0 -1
- package/payload/server/public/assets/data-O_9Kiicl.js.br +0 -2
- package/payload/server/public/assets/data-O_9Kiicl.js.gz +0 -0
- package/payload/server/public/assets/file-download-sXU3_umF.js.br +0 -0
- package/payload/server/public/assets/file-download-sXU3_umF.js.gz +0 -0
- package/payload/server/public/assets/file-text-CeXBviDH.js.br +0 -0
- package/payload/server/public/assets/file-text-CeXBviDH.js.gz +0 -0
- package/payload/server/public/assets/graph-BSuDP6k7.js.br +0 -0
- package/payload/server/public/assets/graph-BSuDP6k7.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-D2pQkgYW.js.br +0 -0
- package/payload/server/public/assets/graph-labels-D2pQkgYW.js.gz +0 -0
- package/payload/server/public/assets/maximize-2-DlzSNygU.js.br +0 -0
- package/payload/server/public/assets/maximize-2-DlzSNygU.js.gz +0 -0
- package/payload/server/public/assets/operator-BP61-xjz.js.br +0 -0
- package/payload/server/public/assets/operator-BP61-xjz.js.gz +0 -0
- package/payload/server/public/assets/page-DX7ArY_s.js.br +0 -0
- package/payload/server/public/assets/page-DX7ArY_s.js.gz +0 -0
- package/payload/server/public/assets/page-eQ4OVros.js.br +0 -0
- package/payload/server/public/assets/page-eQ4OVros.js.gz +0 -0
- package/payload/server/public/assets/public-DPDKFKM2.js.br +0 -0
- package/payload/server/public/assets/public-DPDKFKM2.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-BR0JbPFV.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-BR0JbPFV.js.gz +0 -0
- package/payload/server/public/assets/routines-y413YZa-.js +0 -1
- package/payload/server/public/assets/routines-y413YZa-.js.br +0 -0
- package/payload/server/public/assets/routines-y413YZa-.js.gz +0 -0
- package/payload/server/public/assets/skills-fH0uA7cj.js.br +0 -0
- package/payload/server/public/assets/skills-fH0uA7cj.js.gz +0 -0
- package/payload/server/public/assets/tasks-CrVzFrTR.js.br +0 -0
- package/payload/server/public/assets/tasks-CrVzFrTR.js.gz +0 -0
- package/payload/server/public/assets/time-entry-format-C_0jiMpQ.js.br +0 -1
- package/payload/server/public/assets/time-entry-format-C_0jiMpQ.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-eLJHC_QJ.js.br +0 -1
- package/payload/server/public/assets/triangle-alert-eLJHC_QJ.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-vPCmdOmY.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-vPCmdOmY.js.gz +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-DxuUS_C7.css.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-D5bFDRqL.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-D5bFDRqL.js.gz +0 -0
- package/payload/server/public/assets/wrench-sXisQXkf.js.br +0 -0
- package/payload/server/public/assets/wrench-sXisQXkf.js.gz +0 -0
- /package/payload/server/public/assets/{useSubAccountSwitcher-DMr3DR5N.js → useSubAccountSwitcher-HjQZjJBr.js} +0 -0
- /package/payload/server/public/assets/{useSubAccountSwitcher-DMr3DR5N.js.br → useSubAccountSwitcher-HjQZjJBr.js.br} +0 -0
- /package/payload/server/public/assets/{useSubAccountSwitcher-DMr3DR5N.js.gz → useSubAccountSwitcher-HjQZjJBr.js.gz} +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type IngestTokenAction = "show" | "rotate";
|
|
2
|
+
export interface IngestTokenResult {
|
|
3
|
+
token: string;
|
|
4
|
+
/** True only when this call created the token. */
|
|
5
|
+
minted: boolean;
|
|
6
|
+
/** True only when this call replaced an existing token. */
|
|
7
|
+
rotated: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveIngestToken(accountsDir: string, accountId: string, action: IngestTokenAction): IngestTokenResult;
|
|
10
|
+
//# sourceMappingURL=linkedin-ingest-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linkedin-ingest-token.d.ts","sourceRoot":"","sources":["../../src/tools/linkedin-ingest-token.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAElD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,MAAM,EAAE,OAAO,CAAC;IAChB,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,iBAAiB,GACxB,iBAAiB,CAMnB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* linkedin-ingest-token — hand the operator the LinkedIn extension's durable
|
|
3
|
+
* credential (Task 2208).
|
|
4
|
+
*
|
|
5
|
+
* The agent walks the operator through side-loading the extension and then has
|
|
6
|
+
* to supply a credential. Before this tool the docs pointed at a `session_key`
|
|
7
|
+
* cookie that is never minted, so the operator pasted conversation session keys
|
|
8
|
+
* and every capture came back 401. This is the deterministic source of the one
|
|
9
|
+
* value the extension needs.
|
|
10
|
+
*
|
|
11
|
+
* IDENTITY.md forbids the agent editing account.json directly, so the write
|
|
12
|
+
* goes through here rather than through Edit.
|
|
13
|
+
*/
|
|
14
|
+
import { ensureIngestToken, rotateIngestToken, } from "../../../../../lib/account-ingest-token/dist/index.js";
|
|
15
|
+
export function resolveIngestToken(accountsDir, accountId, action) {
|
|
16
|
+
if (action === "rotate") {
|
|
17
|
+
return { token: rotateIngestToken(accountsDir, accountId), minted: false, rotated: true };
|
|
18
|
+
}
|
|
19
|
+
const { token, minted } = ensureIngestToken(accountsDir, accountId);
|
|
20
|
+
return { token, minted, rotated: false };
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=linkedin-ingest-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linkedin-ingest-token.js","sourceRoot":"","sources":["../../src/tools/linkedin-ingest-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,uDAAuD,CAAC;AAY/D,MAAM,UAAU,kBAAkB,CAChC,WAAmB,EACnB,SAAiB,EACjB,MAAyB;IAEzB,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,OAAO,EAAE,KAAK,EAAE,iBAAiB,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC5F,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACpE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what SiteDesk ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
-
content-hash: sha256:
|
|
4
|
+
content-hash: sha256:a4d904a0b258e267d582d5bd8e968e1de3734c6e60863c401ea5e1b185bccba5
|
|
5
5
|
brand: sitedesk-code
|
|
6
6
|
product-name: SiteDesk
|
|
7
7
|
---
|
|
@@ -2854,7 +2854,7 @@ Capture a LinkedIn profile or DM thread to your SiteDesk graph with one click. T
|
|
|
2854
2854
|
5. Click the puzzle icon → pin **SiteDesk LinkedIn Ingest** → open its options.
|
|
2855
2855
|
6. Paste two values:
|
|
2856
2856
|
- **Admin host** — your tunnel URL, e.g. `https://your-tunnel.example.com`.
|
|
2857
|
-
- **
|
|
2857
|
+
- **Ingest token** — ask your SiteDesk agent for the ingest token. It mints one on request and hands it to you in the chat. The same value keeps working: it survives restarts and new chat sessions, and it does not expire. This is not a conversation session key, and not the admin browser's `session_key`; the route accepts neither.
|
|
2858
2858
|
7. Save. The pill is now armed.
|
|
2859
2859
|
|
|
2860
2860
|
## Use
|
|
@@ -2879,7 +2879,7 @@ The plugin will never create `:Communication`, `:ConversationArchive` rows (i.e.
|
|
|
2879
2879
|
|
|
2880
2880
|
## When the pill turns amber
|
|
2881
2881
|
|
|
2882
|
-
The pill shows **
|
|
2882
|
+
The pill shows **Paste SiteDesk token** when the ingest token is missing or was refused. Click it to open the options page, ask your SiteDesk agent for the ingest token, paste it, and save. The next click on the LinkedIn pill will succeed. There is no sign-in step: the token is the whole credential, and the only way it stops working is if someone rotates it.
|
|
2883
2883
|
|
|
2884
2884
|
## When the pill turns red
|
|
2885
2885
|
|
|
@@ -3363,7 +3363,7 @@ The route (`server/routes/admin/routines.ts`) is account-scoped like `calendar.t
|
|
|
3363
3363
|
| `GET /api/admin/routines/:eventId/runs` | One routine's `:RoutineRun` history, newest first. `limit` clamps to 1..500 and defaults to 50, so a caller that wants the full page must ask for it. |
|
|
3364
3364
|
| `GET /api/admin/routines/:eventId/runs.csv` | The same projection as a `text/csv` attachment with `Content-Disposition`, and **no** limit, so it is not the same row set as a clamped `/runs` call. Re-parses its own output and returns 500 rather than serving a document with fewer rows than the query returned. Zero rows is 404, not a header-only file: the query cannot tell a routine with no runs from an `eventId` on another account. |
|
|
3365
3365
|
| `PATCH /api/admin/routines/:eventId` | Edits `agentPrompt`, `recurrence`, and the `agentChannel`/`agentDestination` pair. Cron validation and the timezone-aware `nextRun` recompute copy the scheduling plugin's `schedule-update` tool. The binding is revalidated against the same house-authority rule, shared as `platform/lib/agent-dispatch-rule`; it is refused `partial-binding`, `invalid-channel`, `no-prompt`, `not-registered`, `cross-account`, `action-routine` (a routine that runs a tool keeps it — an agent binding outranks the action at fire time) or `clear-would-orphan` (clearing the only field holding a one-time routine inside the automation filter would hide it from every routines surface), and no refusal writes. Both fields as `null` clears the binding. An invalid cron is rejected 400 with no write. Only creation and deletion stay agent-only (`schedule-event`/`schedule-cancel`). |
|
|
3366
|
-
| `GET /api/admin/dispatch-destinations` | Every destination the session's account may bind a routine to, across both channels, each labelled by the authoritative list it came from (`House admin`, `Account manager`, `Telegram admin`). Computed from the same lists the validator reads and filtered by the same rule, so the picker cannot offer what the save refuses. |
|
|
3366
|
+
| `GET /api/admin/dispatch-destinations` | Every destination the session's account may bind a routine to, across both channels, each labelled by the authoritative list it came from (`House admin`, `Account manager`, `Telegram admin`), plus an optional `name`: a display-only person name resolved from `:Person` in the row's own account scope — the house for a `House admin` row, the managed sub-account for an `Account manager` row, and never for Telegram, whose destinations are chat ids. Computed from the same lists the validator reads and filtered by the same rule, so the picker cannot offer what the save refuses; `name` is never part of what Save posts, and a graph outage returns an unnamed roster rather than an error. |
|
|
3367
3367
|
| `POST /api/admin/routines/:eventId/suspend` | Writes `eventStatus = 'suspended'` on a routine currently `'scheduled'`. 404s otherwise, so a second suspend is not a silent no-op. |
|
|
3368
3368
|
| `POST /api/admin/routines/:eventId/resume` | Returns a suspended routine to `'scheduled'`. 404s if it is not suspended, 409s if it cannot be resumed. |
|
|
3369
3369
|
| `POST /api/admin/routines/suspend-all` | Suspends every routine currently `'scheduled'` and marks each one. Returns the count. |
|
|
@@ -3397,6 +3397,18 @@ rows — a routine suspended one at a time carries no mark and stays suspended,
|
|
|
3397
3397
|
which is what makes resume-all safe to press. The seeded roster is unmarked by
|
|
3398
3398
|
construction, so resume-all never enables it.
|
|
3399
3399
|
|
|
3400
|
+
**The modal states why a routine is in the state it is in.** Every trigger,
|
|
3401
|
+
dispatch, suspend and resume appends one `[<iso>] <text>` line to the routine's
|
|
3402
|
+
own `notes`, and the detail modal lists that trail newest first under
|
|
3403
|
+
`History (<n> entries)`. So a suspended routine names its reason, the path that
|
|
3404
|
+
suspended it (`Suspended from chat`, `Suspended from the routines dashboard`,
|
|
3405
|
+
`Suspended by a suspend-all from the routines dashboard`) and the time, without
|
|
3406
|
+
reading the graph. Entries render as stored and none is dropped; the box scrolls.
|
|
3407
|
+
A routine with no trail says `No history recorded.`, which is the true state of a
|
|
3408
|
+
seeded roster routine that has never run. This is not the run history: a
|
|
3409
|
+
`:RoutineRun` node records a fire, and a status change is not a fire, so a
|
|
3410
|
+
suspension appears only here.
|
|
3411
|
+
|
|
3400
3412
|
Observability rides `[admin:routines]`: `op=list accountId=<8> count=<n>`,
|
|
3401
3413
|
`op=get id=<8> found=<bool>`, `op=patch id=<8> fields=<…> outcome=ok|rejected
|
|
3402
3414
|
reason=<invalid-cron|not-found> nextRun=<…> cron=<serialized>`, and
|
|
@@ -3406,6 +3418,15 @@ past-one-time|invalid-cron>`. A `count=0` while routines exist for the account i
|
|
|
3406
3418
|
the account-scope-miss signature; the logged `cron=` on `outcome=ok` confirms the
|
|
3407
3419
|
persisted expression without opening the graph.
|
|
3408
3420
|
|
|
3421
|
+
The panel can only show a reason that was written, and a suspend path that wrote
|
|
3422
|
+
no note emits no event of its own. The scheduling sweep's standing census closes
|
|
3423
|
+
that: `[schedule-audit] op=suspension-census` carries `unattributed=<n>`, the
|
|
3424
|
+
count of suspended routines whose notes never record the suspension, on every
|
|
3425
|
+
tick including zero. It sits outside the `other=` arithmetic, which reconciles
|
|
3426
|
+
status buckets against the row count rather than attribution. A routine seeded
|
|
3427
|
+
suspended and never touched carries no notes and is excluded, having nothing to
|
|
3428
|
+
attribute.
|
|
3429
|
+
|
|
3409
3430
|
Two scheduler-side lines close the loop, because a suspend that the sweep ignores
|
|
3410
3431
|
looks identical to a healthy routine until it fires. `[schedule-sweep]
|
|
3411
3432
|
op=skip-suspended account=<8> count=<n>` is emitted every sweep for every local
|
|
@@ -9,6 +9,12 @@ Invoked by the admin agent directly.
|
|
|
9
9
|
|
|
10
10
|
This is the platform's release timeline, newest first. Each entry shows the date it shipped and the version it shipped in, so you can tell the operator how current their install is. To compare, read the installed version from `capabilities-here` and match it against the versions below. Keep answers high level and in plain English; this is a summary, not a full commit log.
|
|
11
11
|
|
|
12
|
+
## 2026-07-30 (0.1.529)
|
|
13
|
+
|
|
14
|
+
- The LinkedIn browser extension now signs in with its own long-lived key, handed to you by an admin tool, instead of borrowing a chat session's key. It keeps working when the session it was set up from ends.
|
|
15
|
+
- The routine editing window has been fixed properly. It is sized to its contents, its dropdowns are styled like the rest of the product, it lists the real places a routine can send its result, and it builds every kind of schedule it offers instead of dropping you into a raw timing expression.
|
|
16
|
+
- A suspended routine now shows why it was suspended, who did it and when, with the most recent entry first. Routines suspended without any reason recorded are counted so they can be found.
|
|
17
|
+
|
|
12
18
|
## 2026-07-30 (0.1.528)
|
|
13
19
|
|
|
14
20
|
- Where two or more accounts share one device, the assistant can no longer edit or write files belonging to a different account. Every account is now checked for that protection being in place.
|
|
@@ -136,7 +136,7 @@ The route (`server/routes/admin/routines.ts`) is account-scoped like `calendar.t
|
|
|
136
136
|
| `GET /api/admin/routines/:eventId/runs` | One routine's `:RoutineRun` history, newest first. `limit` clamps to 1..500 and defaults to 50, so a caller that wants the full page must ask for it. |
|
|
137
137
|
| `GET /api/admin/routines/:eventId/runs.csv` | The same projection as a `text/csv` attachment with `Content-Disposition`, and **no** limit, so it is not the same row set as a clamped `/runs` call. Re-parses its own output and returns 500 rather than serving a document with fewer rows than the query returned. Zero rows is 404, not a header-only file: the query cannot tell a routine with no runs from an `eventId` on another account. |
|
|
138
138
|
| `PATCH /api/admin/routines/:eventId` | Edits `agentPrompt`, `recurrence`, and the `agentChannel`/`agentDestination` pair. Cron validation and the timezone-aware `nextRun` recompute copy the scheduling plugin's `schedule-update` tool. The binding is revalidated against the same house-authority rule, shared as `platform/lib/agent-dispatch-rule`; it is refused `partial-binding`, `invalid-channel`, `no-prompt`, `not-registered`, `cross-account`, `action-routine` (a routine that runs a tool keeps it — an agent binding outranks the action at fire time) or `clear-would-orphan` (clearing the only field holding a one-time routine inside the automation filter would hide it from every routines surface), and no refusal writes. Both fields as `null` clears the binding. An invalid cron is rejected 400 with no write. Only creation and deletion stay agent-only (`schedule-event`/`schedule-cancel`). |
|
|
139
|
-
| `GET /api/admin/dispatch-destinations` | Every destination the session's account may bind a routine to, across both channels, each labelled by the authoritative list it came from (`House admin`, `Account manager`, `Telegram admin`). Computed from the same lists the validator reads and filtered by the same rule, so the picker cannot offer what the save refuses. |
|
|
139
|
+
| `GET /api/admin/dispatch-destinations` | Every destination the session's account may bind a routine to, across both channels, each labelled by the authoritative list it came from (`House admin`, `Account manager`, `Telegram admin`), plus an optional `name`: a display-only person name resolved from `:Person` in the row's own account scope — the house for a `House admin` row, the managed sub-account for an `Account manager` row, and never for Telegram, whose destinations are chat ids. Computed from the same lists the validator reads and filtered by the same rule, so the picker cannot offer what the save refuses; `name` is never part of what Save posts, and a graph outage returns an unnamed roster rather than an error. |
|
|
140
140
|
| `POST /api/admin/routines/:eventId/suspend` | Writes `eventStatus = 'suspended'` on a routine currently `'scheduled'`. 404s otherwise, so a second suspend is not a silent no-op. |
|
|
141
141
|
| `POST /api/admin/routines/:eventId/resume` | Returns a suspended routine to `'scheduled'`. 404s if it is not suspended, 409s if it cannot be resumed. |
|
|
142
142
|
| `POST /api/admin/routines/suspend-all` | Suspends every routine currently `'scheduled'` and marks each one. Returns the count. |
|
|
@@ -170,6 +170,18 @@ rows — a routine suspended one at a time carries no mark and stays suspended,
|
|
|
170
170
|
which is what makes resume-all safe to press. The seeded roster is unmarked by
|
|
171
171
|
construction, so resume-all never enables it.
|
|
172
172
|
|
|
173
|
+
**The modal states why a routine is in the state it is in.** Every trigger,
|
|
174
|
+
dispatch, suspend and resume appends one `[<iso>] <text>` line to the routine's
|
|
175
|
+
own `notes`, and the detail modal lists that trail newest first under
|
|
176
|
+
`History (<n> entries)`. So a suspended routine names its reason, the path that
|
|
177
|
+
suspended it (`Suspended from chat`, `Suspended from the routines dashboard`,
|
|
178
|
+
`Suspended by a suspend-all from the routines dashboard`) and the time, without
|
|
179
|
+
reading the graph. Entries render as stored and none is dropped; the box scrolls.
|
|
180
|
+
A routine with no trail says `No history recorded.`, which is the true state of a
|
|
181
|
+
seeded roster routine that has never run. This is not the run history: a
|
|
182
|
+
`:RoutineRun` node records a fire, and a status change is not a fire, so a
|
|
183
|
+
suspension appears only here.
|
|
184
|
+
|
|
173
185
|
Observability rides `[admin:routines]`: `op=list accountId=<8> count=<n>`,
|
|
174
186
|
`op=get id=<8> found=<bool>`, `op=patch id=<8> fields=<…> outcome=ok|rejected
|
|
175
187
|
reason=<invalid-cron|not-found> nextRun=<…> cron=<serialized>`, and
|
|
@@ -179,6 +191,15 @@ past-one-time|invalid-cron>`. A `count=0` while routines exist for the account i
|
|
|
179
191
|
the account-scope-miss signature; the logged `cron=` on `outcome=ok` confirms the
|
|
180
192
|
persisted expression without opening the graph.
|
|
181
193
|
|
|
194
|
+
The panel can only show a reason that was written, and a suspend path that wrote
|
|
195
|
+
no note emits no event of its own. The scheduling sweep's standing census closes
|
|
196
|
+
that: `[schedule-audit] op=suspension-census` carries `unattributed=<n>`, the
|
|
197
|
+
count of suspended routines whose notes never record the suspension, on every
|
|
198
|
+
tick including zero. It sits outside the `other=` arithmetic, which reconciles
|
|
199
|
+
status buckets against the row count rather than attribution. A routine seeded
|
|
200
|
+
suspended and never touched carries no notes and is excluded, having nothing to
|
|
201
|
+
attribute.
|
|
202
|
+
|
|
182
203
|
Two scheduler-side lines close the loop, because a suspend that the sweep ignores
|
|
183
204
|
looks identical to a healthy routine until it fires. `[schedule-sweep]
|
|
184
205
|
op=skip-suspended account=<8> count=<n>` is emitted every sweep for every local
|
|
@@ -11,7 +11,7 @@ Capture a LinkedIn profile or DM thread to your SiteDesk graph with one click. T
|
|
|
11
11
|
5. Click the puzzle icon → pin **SiteDesk LinkedIn Ingest** → open its options.
|
|
12
12
|
6. Paste two values:
|
|
13
13
|
- **Admin host** — your tunnel URL, e.g. `https://your-tunnel.example.com`.
|
|
14
|
-
- **
|
|
14
|
+
- **Ingest token** — ask your SiteDesk agent for the ingest token. It mints one on request and hands it to you in the chat. The same value keeps working: it survives restarts and new chat sessions, and it does not expire. This is not a conversation session key, and not the admin browser's `session_key`; the route accepts neither.
|
|
15
15
|
7. Save. The pill is now armed.
|
|
16
16
|
|
|
17
17
|
## Use
|
|
@@ -36,7 +36,7 @@ The plugin will never create `:Communication`, `:ConversationArchive` rows (i.e.
|
|
|
36
36
|
|
|
37
37
|
## When the pill turns amber
|
|
38
38
|
|
|
39
|
-
The pill shows **
|
|
39
|
+
The pill shows **Paste SiteDesk token** when the ingest token is missing or was refused. Click it to open the options page, ask your SiteDesk agent for the ingest token, paste it, and save. The next click on the LinkedIn pill will succeed. There is no sign-in step: the token is the whole credential, and the only way it stops working is if someone rotates it.
|
|
40
40
|
|
|
41
41
|
## When the pill turns red
|
|
42
42
|
|
|
@@ -8,7 +8,7 @@ Unpacked-extension dev build. No Chrome Web Store publication.
|
|
|
8
8
|
2. Enable **Developer mode** (top right).
|
|
9
9
|
3. **Load unpacked** → select this `extension/` directory.
|
|
10
10
|
4. Click the new puzzle icon → open **SiteDesk LinkedIn Ingest** options.
|
|
11
|
-
5. Paste your admin host (e.g. `https://your-tunnel.example.com`) and your
|
|
11
|
+
5. Paste your admin host (e.g. `https://your-tunnel.example.com`) and your **ingest token**. Ask your SiteDesk agent for the ingest token; it mints one on request and gives it to you in the chat. The token is stable, so this is a one-time paste unless someone rotates it. Save.
|
|
12
12
|
6. Chrome asks you to allow the extension to talk to that host. **Allow it.** The pill cannot post without it, so declining saves nothing.
|
|
13
13
|
|
|
14
14
|
## Use
|
|
@@ -21,7 +21,7 @@ The pill tells you which thing is wrong:
|
|
|
21
21
|
|
|
22
22
|
| Pill | Meaning | Fix |
|
|
23
23
|
|---|---|---|
|
|
24
|
-
| **
|
|
24
|
+
| **Paste SiteDesk token** (amber) | the ingest token is missing or was refused | ask the agent for the ingest token, paste it in options |
|
|
25
25
|
| **Grant access** (amber) | the admin host was never allowed, so the post never left the browser | open options, Save, allow the prompt |
|
|
26
26
|
| **SiteDesk unreachable** (red) | the host was allowed but did not answer | check the tunnel and the admin server |
|
|
27
27
|
| **Capture failed** (red) | the admin rejected the payload, or the extension's own service worker did not answer | read the service-worker console: `reason=extract` is a rejected payload, `reason=worker-unreachable` is the worker |
|
|
@@ -35,7 +35,7 @@ The pill tells you which thing is wrong:
|
|
|
35
35
|
| `content/profile.js` | Profile pill + click handler. |
|
|
36
36
|
| `content/thread.js` | Thread pill + click handler. |
|
|
37
37
|
| `background/sw.js` | Service worker. Checks the admin-host grant, then POSTs envelopes to the admin route. |
|
|
38
|
-
| `options/options.html` + `options/options.js` | Admin host +
|
|
38
|
+
| `options/options.html` + `options/options.js` | Admin host + ingest-token entry. |
|
|
39
39
|
| `assets/pill.css` | Pill styling. |
|
|
40
40
|
| `__tests__/` | jsdom unit tests for the extractors, run via vitest from `platform/ui`. |
|
|
41
41
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Service worker. Receives envelopes from content scripts, POSTs them
|
|
2
|
-
// to the admin host with the
|
|
2
|
+
// to the admin host with the ingest token stored in extension options.
|
|
3
3
|
//
|
|
4
4
|
// Task 2185 — the manifest's static host_permissions cover linkedin.com only,
|
|
5
5
|
// so the admin host has to be granted at runtime from the options page before
|
|
@@ -14,11 +14,16 @@
|
|
|
14
14
|
|
|
15
15
|
const TAG = '[linkedin-ext-post]'
|
|
16
16
|
|
|
17
|
+
// Task 2208 — the credential is the account's durable ingest token, minted by
|
|
18
|
+
// the linkedin-ingest-token admin tool and pasted in on the options page. The
|
|
19
|
+
// admin browser's session_key it replaced could neither be obtained as
|
|
20
|
+
// documented nor stay valid: in-memory, 24h TTL, wiped by restart, rotated on
|
|
21
|
+
// every new chat session.
|
|
17
22
|
async function getConfig() {
|
|
18
|
-
const stored = await chrome.storage.local.get(['adminHost', '
|
|
23
|
+
const stored = await chrome.storage.local.get(['adminHost', 'ingestToken'])
|
|
19
24
|
return {
|
|
20
25
|
adminHost: typeof stored.adminHost === 'string' ? stored.adminHost.replace(/\/+$/, '') : '',
|
|
21
|
-
|
|
26
|
+
ingestToken: typeof stored.ingestToken === 'string' ? stored.ingestToken : '',
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
29
|
|
|
@@ -28,9 +33,9 @@ function originPattern(adminHost) {
|
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
async function postEnvelope(envelope) {
|
|
31
|
-
const { adminHost,
|
|
36
|
+
const { adminHost, ingestToken } = await getConfig()
|
|
32
37
|
if (!adminHost) return { ok: false, reason: 'auth', detail: 'admin-host-missing' }
|
|
33
|
-
if (!
|
|
38
|
+
if (!ingestToken) return { ok: false, reason: 'auth', detail: 'ingest-token-missing' }
|
|
34
39
|
|
|
35
40
|
let origin
|
|
36
41
|
try {
|
|
@@ -53,7 +58,7 @@ async function postEnvelope(envelope) {
|
|
|
53
58
|
res = await fetch(url, {
|
|
54
59
|
method: 'POST',
|
|
55
60
|
headers: { 'content-type': 'application/json' },
|
|
56
|
-
body: JSON.stringify({ ...envelope,
|
|
61
|
+
body: JSON.stringify({ ...envelope, ingest_token: ingestToken }),
|
|
57
62
|
})
|
|
58
63
|
} catch (err) {
|
|
59
64
|
console.error(
|
|
@@ -66,7 +71,7 @@ async function postEnvelope(envelope) {
|
|
|
66
71
|
const ms = Date.now() - started
|
|
67
72
|
console.log(TAG + ' op=fetch dispatchId=' + envelope.dispatchId + ' status=' + res.status + ' ms=' + ms)
|
|
68
73
|
|
|
69
|
-
if (res.status === 401) return { ok: false, reason: 'auth', detail: '
|
|
74
|
+
if (res.status === 401) return { ok: false, reason: 'auth', detail: 'token-rejected' }
|
|
70
75
|
if (res.status >= 500) return { ok: false, reason: 'server', detail: 'http-' + res.status }
|
|
71
76
|
if (!res.ok) {
|
|
72
77
|
let body = ''
|
|
@@ -51,8 +51,11 @@
|
|
|
51
51
|
const reason = (reply && reply.reason) || 'worker-unreachable'
|
|
52
52
|
const detail = (reply && reply.detail) || ''
|
|
53
53
|
console.error(TAG_ERROR + ' reason=' + reason + ' detail=' + detail)
|
|
54
|
+
// Task 2208 — the ingest token is missing or was refused. There is no
|
|
55
|
+
// sign-in to perform: the operator asks the SiteDesk agent for the token and
|
|
56
|
+
// pastes it on the options page.
|
|
54
57
|
if (reason === 'auth') {
|
|
55
|
-
setState(pill, 'auth', '
|
|
58
|
+
setState(pill, 'auth', 'Paste SiteDesk token')
|
|
56
59
|
pill.onclick = function () { chrome.runtime.openOptionsPage() }
|
|
57
60
|
return
|
|
58
61
|
}
|
|
@@ -53,8 +53,11 @@
|
|
|
53
53
|
const reason = (reply && reply.reason) || 'worker-unreachable'
|
|
54
54
|
const detail = (reply && reply.detail) || ''
|
|
55
55
|
console.error(TAG_ERROR + ' reason=' + reason + ' detail=' + detail)
|
|
56
|
+
// Task 2208 — the ingest token is missing or was refused. There is no
|
|
57
|
+
// sign-in to perform: the operator asks the SiteDesk agent for the token and
|
|
58
|
+
// pastes it on the options page.
|
|
56
59
|
if (reason === 'auth') {
|
|
57
|
-
setState(pill, 'auth', '
|
|
60
|
+
setState(pill, 'auth', 'Paste SiteDesk token')
|
|
58
61
|
pill.onclick = function () { chrome.runtime.openOptionsPage() }
|
|
59
62
|
return
|
|
60
63
|
}
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
<h1>SiteDesk LinkedIn Ingest</h1>
|
|
20
|
-
<p>Point the extension at your SiteDesk admin host and paste your
|
|
20
|
+
<p>Point the extension at your SiteDesk admin host and paste your ingest token. Ask your SiteDesk agent for the token and it will give you one. The pill on LinkedIn will then post one-click captures to your admin.</p>
|
|
21
21
|
<p>On Save, Chrome asks you to allow this extension to talk to that host. The capture pill cannot post without it, so declining leaves the extension unconfigured.</p>
|
|
22
22
|
|
|
23
23
|
<label for="admin-host">Admin host</label>
|
|
24
24
|
<input id="admin-host" type="url" placeholder="https://your-tunnel.example.com" />
|
|
25
25
|
|
|
26
|
-
<label for="
|
|
27
|
-
<input id="
|
|
26
|
+
<label for="ingest-token">Ingest token</label>
|
|
27
|
+
<input id="ingest-token" type="password" placeholder="paste the token your SiteDesk agent gives you" />
|
|
28
28
|
|
|
29
29
|
<button id="save">Save</button>
|
|
30
30
|
<div id="status" class="status"></div>
|
|
@@ -6,9 +6,16 @@
|
|
|
6
6
|
// request that Chrome preflights and the admin route never answers. The
|
|
7
7
|
// runtime grant requested here is what makes that fetch permission-exempt.
|
|
8
8
|
// Without it every capture dies in the browser and the server sees nothing.
|
|
9
|
+
//
|
|
10
|
+
// Task 2208 — the credential is the account's durable ingest token, obtained by
|
|
11
|
+
// asking the SiteDesk agent, which calls the linkedin-ingest-token admin tool. It is
|
|
12
|
+
// NOT the admin browser's session_key: that lived in an in-memory map with a 24h
|
|
13
|
+
// TTL, every restart wiped it and every new chat session rotated it, and no
|
|
14
|
+
// cookie ever carried it, so the previous instruction to copy it from a cookie
|
|
15
|
+
// named something that does not exist.
|
|
9
16
|
|
|
10
17
|
const $host = document.getElementById('admin-host')
|
|
11
|
-
const $
|
|
18
|
+
const $token = document.getElementById('ingest-token')
|
|
12
19
|
const $btn = document.getElementById('save')
|
|
13
20
|
const $status = document.getElementById('status')
|
|
14
21
|
|
|
@@ -28,26 +35,27 @@ function originPattern(adminHost) {
|
|
|
28
35
|
// console; this page says what actually went wrong in plain words.
|
|
29
36
|
const PROBE_COPY = {
|
|
30
37
|
unreachable: 'that host did not answer',
|
|
31
|
-
auth: 'that host rejected the
|
|
38
|
+
auth: 'that host rejected the ingest token',
|
|
32
39
|
server: 'that host answered with an unexpected status',
|
|
33
40
|
}
|
|
34
41
|
|
|
35
|
-
// Config-time probe. The body carries none of the five envelope
|
|
36
|
-
// the route answers 400 {error:'schema', reason:'envelope', missing:
|
|
37
|
-
// five]} — a signature no real capture can produce, because both content
|
|
38
|
-
// scripts always set all five. Nothing is dispatched and nothing is written.
|
|
39
|
-
|
|
42
|
+
// Config-time probe. The body carries the token but none of the five envelope
|
|
43
|
+
// fields, so the route answers 400 {error:'schema', reason:'envelope', missing:
|
|
44
|
+
// [all five]} — a signature no real capture can produce, because both content
|
|
45
|
+
// scripts always set all five. Nothing is dispatched and nothing is written. A
|
|
46
|
+
// 401 here means the token itself was refused.
|
|
47
|
+
async function probe(adminHost, ingestToken) {
|
|
40
48
|
let res
|
|
41
49
|
try {
|
|
42
50
|
res = await fetch(adminHost + '/api/admin/linkedin-ingest', {
|
|
43
51
|
method: 'POST',
|
|
44
52
|
headers: { 'content-type': 'application/json' },
|
|
45
|
-
body: JSON.stringify({
|
|
53
|
+
body: JSON.stringify({ ingest_token: ingestToken }),
|
|
46
54
|
})
|
|
47
55
|
} catch (err) {
|
|
48
56
|
return { ok: false, reason: 'unreachable', detail: err && err.message ? err.message : String(err) }
|
|
49
57
|
}
|
|
50
|
-
if (res.status === 401) return { ok: false, reason: 'auth', detail: '
|
|
58
|
+
if (res.status === 401) return { ok: false, reason: 'auth', detail: 'token-rejected' }
|
|
51
59
|
let body = null
|
|
52
60
|
try { body = await res.json() } catch { /* non-JSON body */ }
|
|
53
61
|
if (res.status === 400 && body && body.error === 'schema') return { ok: true }
|
|
@@ -55,17 +63,17 @@ async function probe(adminHost, sessionKey) {
|
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
async function load() {
|
|
58
|
-
const stored = await chrome.storage.local.get(['adminHost', '
|
|
66
|
+
const stored = await chrome.storage.local.get(['adminHost', 'ingestToken'])
|
|
59
67
|
if (typeof stored.adminHost === 'string') $host.value = stored.adminHost
|
|
60
|
-
if (typeof stored.
|
|
68
|
+
if (typeof stored.ingestToken === 'string') $token.value = stored.ingestToken
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
async function save() {
|
|
64
72
|
const adminHost = $host.value.trim().replace(/\/+$/, '')
|
|
65
|
-
const
|
|
73
|
+
const ingestToken = $token.value.trim()
|
|
66
74
|
if (!adminHost) return setStatus('Admin host is required.', true)
|
|
67
75
|
if (!/^https?:\/\//.test(adminHost)) return setStatus('Admin host must start with http(s)://.', true)
|
|
68
|
-
if (!
|
|
76
|
+
if (!ingestToken) return setStatus('Ingest token is required. Ask your SiteDesk agent for it.', true)
|
|
69
77
|
|
|
70
78
|
let origin
|
|
71
79
|
try {
|
|
@@ -93,10 +101,10 @@ async function save() {
|
|
|
93
101
|
)
|
|
94
102
|
}
|
|
95
103
|
|
|
96
|
-
const reachable = await probe(adminHost,
|
|
97
|
-
await chrome.storage.local.set({ adminHost: adminHost,
|
|
104
|
+
const reachable = await probe(adminHost, ingestToken)
|
|
105
|
+
await chrome.storage.local.set({ adminHost: adminHost, ingestToken: ingestToken })
|
|
98
106
|
if (reachable.ok) {
|
|
99
|
-
return setStatus('Saved. The admin host is reachable and accepted the
|
|
107
|
+
return setStatus('Saved. The admin host is reachable and accepted the ingest token.', false)
|
|
100
108
|
}
|
|
101
109
|
setStatus('Saved, but ' + PROBE_COPY[reachable.reason] + ' (' + reachable.detail + ')', true)
|
|
102
110
|
}
|
package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/suspension-census.test.js
CHANGED
|
@@ -32,14 +32,14 @@ describe("auditSuspensionCensus", () => {
|
|
|
32
32
|
it("emits a line for an account with no routines at all, so silence is never healthy", async () => {
|
|
33
33
|
await auditSuspensionCensus(driverReturning([]), [ACCT]);
|
|
34
34
|
expect(censusLines()).toEqual([
|
|
35
|
-
"[schedule-audit] op=suspension-census acct=aaaaaaaa routines=0 dispatchable=0 suspended=0 due=0 cancelled=0 completed=0 other=0",
|
|
35
|
+
"[schedule-audit] op=suspension-census acct=aaaaaaaa routines=0 dispatchable=0 suspended=0 due=0 cancelled=0 completed=0 other=0 unattributed=0",
|
|
36
36
|
]);
|
|
37
37
|
});
|
|
38
38
|
it("reports each status and leaves other at zero when they account for every row", async () => {
|
|
39
39
|
await auditSuspensionCensus(driverReturning([
|
|
40
40
|
{ accountId: ACCT, routines: 10, dispatchable: 4, suspended: 3, due: 2, cancelled: 1 },
|
|
41
41
|
]), [ACCT]);
|
|
42
|
-
expect(censusLines()[0]).toBe("[schedule-audit] op=suspension-census acct=aaaaaaaa routines=10 dispatchable=4 suspended=3 due=2 cancelled=1 completed=0 other=0");
|
|
42
|
+
expect(censusLines()[0]).toBe("[schedule-audit] op=suspension-census acct=aaaaaaaa routines=10 dispatchable=4 suspended=3 due=2 cancelled=1 completed=0 other=0 unattributed=0");
|
|
43
43
|
});
|
|
44
44
|
// The standing check. dispatchable + suspended + due + cancelled + other =
|
|
45
45
|
// routines holds by construction, so a non-zero `other` is the only signal
|
|
@@ -79,6 +79,49 @@ describe("auditSuspensionCensus", () => {
|
|
|
79
79
|
]), [ACCT]);
|
|
80
80
|
expect(censusLines()[0]).toContain("completed=1 other=0");
|
|
81
81
|
});
|
|
82
|
+
// Task 2209 — the detail-modal history panel can only show a reason that was
|
|
83
|
+
// written. A suspend path that appended no note leaves the panel blank with
|
|
84
|
+
// nothing to say why, and no log line exists for a note that was never
|
|
85
|
+
// written, so this count is the only signal. These cases stub the driver, so
|
|
86
|
+
// they prove the field plumbing and the emitted line, not the Cypher
|
|
87
|
+
// predicate; that is the publish-gated device check in Task 2209.
|
|
88
|
+
it("counts a suspended row whose notes never record the suspension", async () => {
|
|
89
|
+
await auditSuspensionCensus(driverReturning([
|
|
90
|
+
{ accountId: ACCT, routines: 2, dispatchable: 1, suspended: 1, due: 0, cancelled: 0, completed: 0, unattributed: 1 },
|
|
91
|
+
]), [ACCT]);
|
|
92
|
+
expect(censusLines()[0]).toContain("other=0 unattributed=1");
|
|
93
|
+
});
|
|
94
|
+
it("reports unattributed at zero rather than omitting the field, so a healthy account and a dead audit do not read alike", async () => {
|
|
95
|
+
await auditSuspensionCensus(driverReturning([
|
|
96
|
+
{ accountId: ACCT, routines: 2, dispatchable: 1, suspended: 1, due: 0, cancelled: 0, completed: 0, unattributed: 0 },
|
|
97
|
+
]), [ACCT]);
|
|
98
|
+
expect(censusLines()[0]).toContain("unattributed=0");
|
|
99
|
+
});
|
|
100
|
+
it("carries unattributed=0 for an account the query returned no row for", async () => {
|
|
101
|
+
await auditSuspensionCensus(driverReturning([]), [ACCT]);
|
|
102
|
+
expect(censusLines()[0]).toContain("unattributed=0");
|
|
103
|
+
});
|
|
104
|
+
// `other` reconciles status buckets against the row count; `unattributed`
|
|
105
|
+
// reconciles a suspended row against whether anything recorded why. Folding
|
|
106
|
+
// one into the other would make a missing note look like an unknown status.
|
|
107
|
+
it("keeps unattributed out of the other arithmetic", async () => {
|
|
108
|
+
await auditSuspensionCensus(driverReturning([
|
|
109
|
+
{ accountId: ACCT, routines: 3, dispatchable: 1, suspended: 2, due: 0, cancelled: 0, completed: 0, unattributed: 2 },
|
|
110
|
+
]), [ACCT]);
|
|
111
|
+
expect(censusLines()[0]).toContain("other=0 unattributed=2");
|
|
112
|
+
});
|
|
113
|
+
it("unwraps a neo4j integer for unattributed too", async () => {
|
|
114
|
+
await auditSuspensionCensus(driverReturning([
|
|
115
|
+
{
|
|
116
|
+
accountId: ACCT,
|
|
117
|
+
routines: { toNumber: () => 1 }, dispatchable: { toNumber: () => 0 },
|
|
118
|
+
suspended: { toNumber: () => 1 }, due: { toNumber: () => 0 },
|
|
119
|
+
cancelled: { toNumber: () => 0 }, completed: { toNumber: () => 0 },
|
|
120
|
+
unattributed: { toNumber: () => 1 },
|
|
121
|
+
},
|
|
122
|
+
]), [ACCT]);
|
|
123
|
+
expect(censusLines()[0]).toContain("unattributed=1");
|
|
124
|
+
});
|
|
82
125
|
it("never throws, so a census failure cannot take the sweep down", async () => {
|
|
83
126
|
const driver = {
|
|
84
127
|
session: () => ({
|
package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/suspension-census.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"suspension-census.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/suspension-census.test.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,gFAAgF;AAChF,+EAA+E;AAC/E,8EAA8E;AAC9E,oBAAoB;AACpB,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,MAAM,IAAI,GAAG,sCAAsC,CAAC;AAEpD,SAAS,eAAe,CAAC,IAA+B;IACtD,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;YACd,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aACzD,CAAC,CAAC;YACH,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC;SAC7B,CAAC;KACH,CAAC;AACJ,CAAC;AAED,IAAI,MAAmC,CAAC;AACxC,SAAS,WAAW;IAClB,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK;SACrB,GAAG,CAAC,CAAC,CAAY,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACnC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,UAAU,CAAC,GAAG,EAAE;IACd,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC;AACH,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,CAAC,WAAW,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;QAChG,MAAM,qBAAqB,CAAC,eAAe,CAAC,EAAE,CAAU,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC;YAC5B,
|
|
1
|
+
{"version":3,"file":"suspension-census.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/suspension-census.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-turn-dispatch.d.ts","sourceRoot":"","sources":["../../src/scripts/agent-turn-dispatch.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"agent-turn-dispatch.d.ts","sourceRoot":"","sources":["../../src/scripts/agent-turn-dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAmB3C,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,YAAY,CAaf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAY1F;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAInD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EAId,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO,CAAC,IAAI,CAAC,CA+Gf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EAAE,EACzB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EAAE,EACzB,YAAY,GAAE,SAAS,MAAM,EAAwB,GACpD,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDpG;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwChG;AAgCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDvG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8CtG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC,CA2Ef;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EAAE,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAiCf"}
|
|
@@ -670,7 +670,11 @@ export async function auditSuspensionCensus(driver, localAccountIds) {
|
|
|
670
670
|
sum(CASE WHEN e.eventStatus = 'suspended' THEN 1 ELSE 0 END) AS suspended,
|
|
671
671
|
sum(CASE WHEN e.eventStatus = 'due' THEN 1 ELSE 0 END) AS due,
|
|
672
672
|
sum(CASE WHEN e.eventStatus = 'cancelled' THEN 1 ELSE 0 END) AS cancelled,
|
|
673
|
-
sum(CASE WHEN e.eventStatus = 'completed' THEN 1 ELSE 0 END) AS completed
|
|
673
|
+
sum(CASE WHEN e.eventStatus = 'completed' THEN 1 ELSE 0 END) AS completed,
|
|
674
|
+
sum(CASE WHEN e.eventStatus = 'suspended'
|
|
675
|
+
AND ( (e.notes IS NULL AND e.routineTemplate IS NULL)
|
|
676
|
+
OR (e.notes IS NOT NULL AND NOT e.notes CONTAINS 'Suspended') )
|
|
677
|
+
THEN 1 ELSE 0 END) AS unattributed`, { localAccountIds });
|
|
674
678
|
const num = (raw) => typeof raw === "number"
|
|
675
679
|
? raw
|
|
676
680
|
: raw && typeof raw.toNumber === "function"
|
|
@@ -685,6 +689,7 @@ export async function auditSuspensionCensus(driver, localAccountIds) {
|
|
|
685
689
|
due: num(rec.get("due")),
|
|
686
690
|
cancelled: num(rec.get("cancelled")),
|
|
687
691
|
completed: num(rec.get("completed")),
|
|
692
|
+
unattributed: num(rec.get("unattributed")),
|
|
688
693
|
});
|
|
689
694
|
}
|
|
690
695
|
// Driven by localAccountIds, not by the result rows: an account with no
|
|
@@ -693,11 +698,19 @@ export async function auditSuspensionCensus(driver, localAccountIds) {
|
|
|
693
698
|
for (const accountId of localAccountIds) {
|
|
694
699
|
const c = byAccount.get(accountId) ?? {
|
|
695
700
|
routines: 0, dispatchable: 0, suspended: 0, due: 0, cancelled: 0, completed: 0,
|
|
701
|
+
unattributed: 0,
|
|
696
702
|
};
|
|
697
703
|
const other = c.routines - c.dispatchable - c.suspended - c.due - c.cancelled - c.completed;
|
|
704
|
+
// Task 2209 — `unattributed` is appended after `other` and deliberately
|
|
705
|
+
// outside its arithmetic: `other` reconciles status buckets against the
|
|
706
|
+
// row count, while this reconciles a suspended row against whether
|
|
707
|
+
// anything recorded why it stopped. The detail modal can only show a
|
|
708
|
+
// reason that was written, and a suspend path that appended no note emits
|
|
709
|
+
// no event of its own, so this count is the only control that reveals it.
|
|
698
710
|
console.error(`[schedule-audit] op=suspension-census acct=${accountId.slice(0, 8)} ` +
|
|
699
711
|
`routines=${c.routines} dispatchable=${c.dispatchable} suspended=${c.suspended} ` +
|
|
700
|
-
`due=${c.due} cancelled=${c.cancelled} completed=${c.completed} other=${other}`
|
|
712
|
+
`due=${c.due} cancelled=${c.cancelled} completed=${c.completed} other=${other} ` +
|
|
713
|
+
`unattributed=${c.unattributed}`);
|
|
701
714
|
}
|
|
702
715
|
}
|
|
703
716
|
catch (err) {
|