@rubytech/create-maxy-code 0.1.591 → 0.1.593
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/routine-templates/dist/index.d.ts +2 -2
- package/payload/platform/lib/routine-templates/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/dist/index.js +2 -9
- package/payload/platform/lib/routine-templates/dist/index.js.map +1 -1
- package/payload/platform/lib/routine-templates/dist/roster.d.ts +1 -11
- package/payload/platform/lib/routine-templates/dist/roster.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/dist/roster.js +11 -15
- package/payload/platform/lib/routine-templates/dist/roster.js.map +1 -1
- package/payload/platform/lib/routine-templates/src/__tests__/roster.test.ts +0 -0
- package/payload/platform/lib/routine-templates/src/__tests__/seed.test.ts +8 -3
- package/payload/platform/lib/routine-templates/src/index.ts +1 -8
- package/payload/platform/lib/routine-templates/src/roster.ts +10 -14
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +7 -3
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +10 -0
- package/payload/platform/plugins/docs/references/internals.md +4 -2
- package/payload/platform/plugins/docs/references/telegram-guide.md +2 -0
- package/payload/platform/plugins/scheduling/PLUGIN.md +6 -6
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +4 -12
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js +85 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js +55 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts +10 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +42 -6
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts +22 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js +73 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +93 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +2 -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 +45 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +19 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js +27 -280
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +315 -208
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +1 -31
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +15 -95
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +5 -36
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +83 -51
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +152 -105
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
- package/payload/platform/plugins/telegram/PLUGIN.md +12 -5
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/ask-tool.test.js +31 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/ask-tool.test.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/card-tool.test.js +30 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/card-tool.test.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/media-fetch-tool.test.js +24 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/media-fetch-tool.test.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/media-send-tool.test.js +31 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/media-send-tool.test.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.d.ts +2 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.js +55 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.d.ts +2 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.js +89 -0
- package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js +13 -42
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.d.ts +80 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.js +96 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/ask.d.ts +5 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/ask.d.ts.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/ask.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/card.d.ts +5 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/card.d.ts.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/card.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/media-fetch.d.ts +5 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/media-fetch.d.ts.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/media-fetch.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/media-send.d.ts +5 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/media-send.d.ts.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/media-send.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/thread.d.ts +5 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/thread.d.ts.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/thread.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +37 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +178 -13
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.d.ts +13 -5
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.js +23 -9
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.d.ts +7 -4
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.js +5 -3
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-store.d.ts +15 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-store.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-store.js +16 -7
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-store.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-plugin-mcp.d.ts +28 -0
- package/payload/platform/services/claude-session-manager/dist/telegram-plugin-mcp.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/telegram-plugin-mcp.js +53 -0
- package/payload/platform/services/claude-session-manager/dist/telegram-plugin-mcp.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts +9 -5
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js +12 -6
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +7 -3
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +5 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts +14 -2
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.js +34 -3
- package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
- package/payload/server/server.js +74 -9
package/package.json
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* unrelated, which is worse than no citation.
|
|
32
32
|
*/
|
|
33
33
|
import { type RoutineTemplate } from "./roster.js";
|
|
34
|
-
export { ROUTINE_ROSTER, ROUTINE_ROSTER_KEYS, ROUTINE_TEMPLATE_VERSION, isWatermarkedCheck, gateNeedsCommit,
|
|
34
|
+
export { ROUTINE_ROSTER, ROUTINE_ROSTER_KEYS, ROUTINE_TEMPLATE_VERSION, isWatermarkedCheck, gateNeedsCommit, } from "./roster.js";
|
|
35
35
|
export type { RoutineTemplate, RoutineGate, RoutineGateCheck } from "./roster.js";
|
|
36
36
|
/** The minimal Neo4j session surface the seed needs. Both the admin plugin's
|
|
37
37
|
* `getSession()` and a driver session from `seed-cli` satisfy it; the tests
|
|
@@ -150,7 +150,7 @@ export declare function resolveOwnerTimezone(session: SeedSessionLike, accountId
|
|
|
150
150
|
* the commit token is substituted from the same `row.gateChecks` the gate is
|
|
151
151
|
* built from, so the precondition and the turn's own commit call cannot
|
|
152
152
|
* disagree about what this routine checks. */
|
|
153
|
-
export declare const MERGE_CYPHER = "\nUNWIND $rows AS row\nOPTIONAL MATCH (pre:Event {accountId: $accountId, routineTemplate: row.key})\nWITH row,\n pre IS NOT NULL AS existed,\n coalesce(pre.routineTemplateVersion, 0) AS priorVersion,\n pre.operatorEdited IS NOT NULL AS edited\nWITH row, existed, priorVersion, edited,\n (existed AND NOT edited AND priorVersion < $version) AS refreshing\nMERGE (e:Event {accountId: $accountId, routineTemplate: row.key})\n ON CREATE SET e.eventId = randomUUID(),\n e.name = row.name,\n e.description = row.description,\n e.agentPrompt = row.prompt,\n e.recurrence = row.recurrence,\n e.routineTemplateVersion = $version,\n e.eventStatus = 'suspended',\n e.nextRun = null,\n e.agentChannel = null,\n e.agentDestination = null,\n e.actionPlugin = null,\n e.actionTool = null,\n e.actionArgs = null,\n e.sourcePlugin = null,\n e.timezone = $timezone,\n e.createdBySource = 'installer',\n e.createdByAgent = 'system',\n e.createdByTool = 'routine-roster-seed',\n e.createdAt = $now,\n e.updatedAt = $now\n ON MATCH SET e.agentPrompt = CASE WHEN refreshing THEN row.prompt ELSE e.agentPrompt END,\n e.name = CASE WHEN refreshing THEN row.name ELSE e.name END,\n e.description = CASE WHEN refreshing THEN row.description ELSE e.description END,\n e.routineTemplateVersion = CASE WHEN refreshing THEN $version ELSE e.routineTemplateVersion END,\n e.updatedAt = CASE WHEN refreshing THEN $now ELSE e.updatedAt END\nWITH row, e, existed, priorVersion, edited, (NOT existed OR refreshing) AS writing\nSET e.gatePlugin = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling' END) ELSE e.gatePlugin END,\n e.gateTool = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling-gate' END) ELSE e.gateTool END,\n e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{\"eventId\":\"' + e.eventId + '\",\"checks\":' + row.gateChecks + '}' END) ELSE e.gateArgs END
|
|
153
|
+
export declare const MERGE_CYPHER = "\nUNWIND $rows AS row\nOPTIONAL MATCH (pre:Event {accountId: $accountId, routineTemplate: row.key})\nWITH row,\n pre IS NOT NULL AS existed,\n coalesce(pre.routineTemplateVersion, 0) AS priorVersion,\n pre.operatorEdited IS NOT NULL AS edited\nWITH row, existed, priorVersion, edited,\n (existed AND NOT edited AND priorVersion < $version) AS refreshing\nMERGE (e:Event {accountId: $accountId, routineTemplate: row.key})\n ON CREATE SET e.eventId = randomUUID(),\n e.name = row.name,\n e.description = row.description,\n e.agentPrompt = row.prompt,\n e.recurrence = row.recurrence,\n e.routineTemplateVersion = $version,\n e.eventStatus = 'suspended',\n e.nextRun = null,\n e.agentChannel = null,\n e.agentDestination = null,\n e.actionPlugin = null,\n e.actionTool = null,\n e.actionArgs = null,\n e.sourcePlugin = null,\n e.timezone = $timezone,\n e.createdBySource = 'installer',\n e.createdByAgent = 'system',\n e.createdByTool = 'routine-roster-seed',\n e.createdAt = $now,\n e.updatedAt = $now\n ON MATCH SET e.agentPrompt = CASE WHEN refreshing THEN row.prompt ELSE e.agentPrompt END,\n e.name = CASE WHEN refreshing THEN row.name ELSE e.name END,\n e.description = CASE WHEN refreshing THEN row.description ELSE e.description END,\n e.routineTemplateVersion = CASE WHEN refreshing THEN $version ELSE e.routineTemplateVersion END,\n e.updatedAt = CASE WHEN refreshing THEN $now ELSE e.updatedAt END\nWITH row, e, existed, priorVersion, edited, (NOT existed OR refreshing) AS writing\nSET e.gatePlugin = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling' END) ELSE e.gatePlugin END,\n e.gateTool = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling-gate' END) ELSE e.gateTool END,\n e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{\"eventId\":\"' + e.eventId + '\",\"checks\":' + row.gateChecks + '}' END) ELSE e.gateArgs END\nRETURN row.key AS key,\n e.eventId AS eventId,\n CASE WHEN NOT existed THEN 'create'\n WHEN priorVersion >= $version THEN 'unchanged'\n WHEN edited THEN 'skip-operator-edited'\n ELSE 'refresh-version' END AS action";
|
|
154
154
|
/** The post-condition read. Counts every roster row the account actually holds,
|
|
155
155
|
* independently of what the MERGE above believes it wrote. */
|
|
156
156
|
export declare const VERIFY_CYPHER = "\nMATCH (e:Event {accountId: $accountId})\nWHERE e.routineTemplate IS NOT NULL\nRETURN count(e) AS actual,\n sum(CASE WHEN e.eventStatus = 'suspended' THEN 1 ELSE 0 END) AS suspended,\n sum(CASE WHEN e.nextRun IS NULL THEN 1 ELSE 0 END) AS nextRunNull,\n sum(CASE WHEN e.description IS NULL THEN 1 ELSE 0 END) AS descNull";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAA4C,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAQ7F,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.VERIFY_CYPHER = exports.MERGE_CYPHER = exports.
|
|
3
|
+
exports.VERIFY_CYPHER = exports.MERGE_CYPHER = exports.gateNeedsCommit = exports.isWatermarkedCheck = exports.ROUTINE_TEMPLATE_VERSION = exports.ROUTINE_ROSTER_KEYS = exports.ROUTINE_ROSTER = void 0;
|
|
4
4
|
exports.acctTag = acctTag;
|
|
5
5
|
exports.resolveOwnerTimezone = resolveOwnerTimezone;
|
|
6
6
|
exports.seedRoutineRoster = seedRoutineRoster;
|
|
@@ -49,10 +49,6 @@ Object.defineProperty(exports, "ROUTINE_ROSTER_KEYS", { enumerable: true, get: f
|
|
|
49
49
|
Object.defineProperty(exports, "ROUTINE_TEMPLATE_VERSION", { enumerable: true, get: function () { return roster_js_2.ROUTINE_TEMPLATE_VERSION; } });
|
|
50
50
|
Object.defineProperty(exports, "isWatermarkedCheck", { enumerable: true, get: function () { return roster_js_2.isWatermarkedCheck; } });
|
|
51
51
|
Object.defineProperty(exports, "gateNeedsCommit", { enumerable: true, get: function () { return roster_js_2.gateNeedsCommit; } });
|
|
52
|
-
// Task 2634 — the scheduling plugin's write-time guard accepts a prompt that
|
|
53
|
-
// carries this token, so the token has to be reachable from the package's own
|
|
54
|
-
// entry point rather than only from the roster the seed reads.
|
|
55
|
-
Object.defineProperty(exports, "GATE_COMMIT_TOKEN", { enumerable: true, get: function () { return roster_js_2.GATE_COMMIT_TOKEN; } });
|
|
56
52
|
/** Neo4j returns integers as its own `Integer` type over bolt and as plain
|
|
57
53
|
* numbers through a test fake. Normalise both without importing the driver. */
|
|
58
54
|
function toInt(raw) {
|
|
@@ -167,10 +163,7 @@ MERGE (e:Event {accountId: $accountId, routineTemplate: row.key})
|
|
|
167
163
|
WITH row, e, existed, priorVersion, edited, (NOT existed OR refreshing) AS writing
|
|
168
164
|
SET e.gatePlugin = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling' END) ELSE e.gatePlugin END,
|
|
169
165
|
e.gateTool = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling-gate' END) ELSE e.gateTool END,
|
|
170
|
-
e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + '}' END) ELSE e.gateArgs END
|
|
171
|
-
e.agentPrompt = CASE WHEN writing AND row.gateChecks IS NOT NULL
|
|
172
|
-
THEN replace(e.agentPrompt, '<<gateCommit>>', '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + ',"commit":true}')
|
|
173
|
-
ELSE e.agentPrompt END
|
|
166
|
+
e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + '}' END) ELSE e.gateArgs END
|
|
174
167
|
RETURN row.key AS key,
|
|
175
168
|
e.eventId AS eventId,
|
|
176
169
|
CASE WHEN NOT existed THEN 'create'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* routine's prompt only when the stored `routineTemplateVersion` is BELOW this
|
|
35
35
|
* and no operator has edited the row, so an unbumped edit ships to new installs
|
|
36
36
|
* and never reaches existing ones — bump it in the same commit as the edit. */
|
|
37
|
-
export declare const ROUTINE_TEMPLATE_VERSION =
|
|
37
|
+
export declare const ROUTINE_TEMPLATE_VERSION = 4;
|
|
38
38
|
/**
|
|
39
39
|
* Task 2379 — the check shapes a shipped template may name.
|
|
40
40
|
*
|
|
@@ -76,16 +76,6 @@ export type RoutineGateCheck = RoutineMailCheck | RoutineD1Check | RoutineWhatsa
|
|
|
76
76
|
export interface RoutineGate {
|
|
77
77
|
readonly checks: readonly RoutineGateCheck[];
|
|
78
78
|
}
|
|
79
|
-
/** Substituted by the seed with the full `scheduling-gate` argument object,
|
|
80
|
-
* including the row's own event id.
|
|
81
|
-
*
|
|
82
|
-
* A template cannot write that id: it is minted by the MERGE. Nor can the turn
|
|
83
|
-
* supply it, because the only place a scheduled turn sees its own event is the
|
|
84
|
-
* provenance preamble, which carries the first eight characters. The watermark
|
|
85
|
-
* file is named from the whole id, so a turn committing against the prefix
|
|
86
|
-
* would write a file the next gate never reads and the routine would report
|
|
87
|
-
* work for ever. */
|
|
88
|
-
export declare const GATE_COMMIT_TOKEN = "<<gateCommit>>";
|
|
89
79
|
/** True when the check compares against a stored position rather than reading a
|
|
90
80
|
* current one.
|
|
91
81
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;gFAGgF;AAChF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AACD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;CACtC;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AACD;iDACiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AACD,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,CAAC;AAEzB;iEACiE;AACjE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC9C;
|
|
1
|
+
{"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;gFAGgF;AAChF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AACD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;CACtC;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AACD;iDACiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AACD,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,CAAC;AAEzB;iEACiE;AACjE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC9C;AAWD;;;;;;;;;;;4DAW4D;AAC5D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAGnE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAE1D;AAED,MAAM,WAAW,eAAe;IAC9B;;mEAE+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;6EAGyE;IACzE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;wEACoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;2CAIuC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAC5B;;;+DAG2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;2BAO2B;AAC3B,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAI/D;AAgKD;;;;;;;;iFAQiF;AACjF,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAsHpD,CAAC;AAEF;;6DAE6D;AAC7D,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAqC,CAAC"}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* shipping a prompt that reaches for a tool no install serves.
|
|
33
33
|
*/
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.ROUTINE_ROSTER_KEYS = exports.ROUTINE_ROSTER = exports.
|
|
35
|
+
exports.ROUTINE_ROSTER_KEYS = exports.ROUTINE_ROSTER = exports.ROUTINE_TEMPLATE_VERSION = void 0;
|
|
36
36
|
exports.isWatermarkedCheck = isWatermarkedCheck;
|
|
37
37
|
exports.gateNeedsCommit = gateNeedsCommit;
|
|
38
38
|
exports.isClassified = isClassified;
|
|
@@ -40,17 +40,15 @@ exports.isClassified = isClassified;
|
|
|
40
40
|
* routine's prompt only when the stored `routineTemplateVersion` is BELOW this
|
|
41
41
|
* and no operator has edited the row, so an unbumped edit ships to new installs
|
|
42
42
|
* and never reaches existing ones — bump it in the same commit as the edit. */
|
|
43
|
-
exports.ROUTINE_TEMPLATE_VERSION =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
* work for ever. */
|
|
53
|
-
exports.GATE_COMMIT_TOKEN = "<<gateCommit>>";
|
|
43
|
+
exports.ROUTINE_TEMPLATE_VERSION = 4;
|
|
44
|
+
// Task 2663 — `GATE_COMMIT_TOKEN` is deleted. It stood in for a
|
|
45
|
+
// `scheduling-gate` call the routine's own turn made to advance its watermark,
|
|
46
|
+
// and the whole reason it had to be a token was that a template cannot write the
|
|
47
|
+
// event id the MERGE mints, while a turn only ever sees the first eight
|
|
48
|
+
// characters of it. That hazard is gone with the commit: the platform advances
|
|
49
|
+
// the mark itself, from the dispatcher, which holds the whole id by
|
|
50
|
+
// construction. A prompt that still contains the literal token is harmless prose
|
|
51
|
+
// naming a tool argument that no longer exists.
|
|
54
52
|
/** True when the check compares against a stored position rather than reading a
|
|
55
53
|
* current one.
|
|
56
54
|
*
|
|
@@ -151,9 +149,7 @@ An appointment on the provider calendar with no counterpart in the graph is invi
|
|
|
151
149
|
|
|
152
150
|
If the account has a busy-time sync configured, run schedule-connector-busy-sync so availability reflects what was just reconciled.
|
|
153
151
|
|
|
154
|
-
Reply only when something was actually changed, naming what and why. A clean reconcile ends the turn without replying, every time. This routine runs often, so a message on every clean run trains the operator to ignore it
|
|
155
|
-
|
|
156
|
-
When the run has finished and nothing failed, call scheduling-gate with <<gateCommit>> so the next run does not re-examine what you have just reconciled. Do not call it after a run that failed or that you stopped early: the work would be marked as handled without anyone having seen it.`;
|
|
152
|
+
Reply only when something was actually changed, naming what and why. A clean reconcile ends the turn without replying, every time. This routine runs often, so a message on every clean run trains the operator to ignore it.`;
|
|
157
153
|
const CONTACT_RECONCILE = `Reconcile the people the business actually deals with against the people it has recorded.
|
|
158
154
|
|
|
159
155
|
Call capabilities-here first. If neither a mail plugin nor the contacts plugin is enabled, end the turn without replying.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roster.js","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;;;
|
|
1
|
+
{"version":3,"file":"roster.js","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
|
@@ -384,9 +384,14 @@ describe("gate seeding", () => {
|
|
|
384
384
|
}
|
|
385
385
|
});
|
|
386
386
|
|
|
387
|
-
it("
|
|
388
|
-
|
|
389
|
-
|
|
387
|
+
it("writes no commit into any prompt (Task 2663)", () => {
|
|
388
|
+
// The seed used to expand `<<gateCommit>>` into a full argument object so the
|
|
389
|
+
// turn could advance its own watermark. The platform does that now, from the
|
|
390
|
+
// dispatcher, so the seed touching `agentPrompt` at all would only reinstate
|
|
391
|
+
// the writer this task removed.
|
|
392
|
+
expect(gateBlock()).not.toContain("gateCommit");
|
|
393
|
+
expect(gateBlock()).not.toContain('"commit":true');
|
|
394
|
+
expect(gateBlock()).not.toContain("e.agentPrompt");
|
|
390
395
|
});
|
|
391
396
|
|
|
392
397
|
it("passes serialised checks for a gated row and null for a gateless one", async () => {
|
|
@@ -44,10 +44,6 @@ export {
|
|
|
44
44
|
ROUTINE_TEMPLATE_VERSION,
|
|
45
45
|
isWatermarkedCheck,
|
|
46
46
|
gateNeedsCommit,
|
|
47
|
-
// Task 2634 — the scheduling plugin's write-time guard accepts a prompt that
|
|
48
|
-
// carries this token, so the token has to be reachable from the package's own
|
|
49
|
-
// entry point rather than only from the roster the seed reads.
|
|
50
|
-
GATE_COMMIT_TOKEN,
|
|
51
47
|
} from "./roster.js";
|
|
52
48
|
export type { RoutineTemplate, RoutineGate, RoutineGateCheck } from "./roster.js";
|
|
53
49
|
|
|
@@ -234,10 +230,7 @@ MERGE (e:Event {accountId: $accountId, routineTemplate: row.key})
|
|
|
234
230
|
WITH row, e, existed, priorVersion, edited, (NOT existed OR refreshing) AS writing
|
|
235
231
|
SET e.gatePlugin = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling' END) ELSE e.gatePlugin END,
|
|
236
232
|
e.gateTool = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling-gate' END) ELSE e.gateTool END,
|
|
237
|
-
e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + '}' END) ELSE e.gateArgs END
|
|
238
|
-
e.agentPrompt = CASE WHEN writing AND row.gateChecks IS NOT NULL
|
|
239
|
-
THEN replace(e.agentPrompt, '<<gateCommit>>', '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + ',"commit":true}')
|
|
240
|
-
ELSE e.agentPrompt END
|
|
233
|
+
e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + '}' END) ELSE e.gateArgs END
|
|
241
234
|
RETURN row.key AS key,
|
|
242
235
|
e.eventId AS eventId,
|
|
243
236
|
CASE WHEN NOT existed THEN 'create'
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* routine's prompt only when the stored `routineTemplateVersion` is BELOW this
|
|
36
36
|
* and no operator has edited the row, so an unbumped edit ships to new installs
|
|
37
37
|
* and never reaches existing ones — bump it in the same commit as the edit. */
|
|
38
|
-
export const ROUTINE_TEMPLATE_VERSION =
|
|
38
|
+
export const ROUTINE_TEMPLATE_VERSION = 4;
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Task 2379 — the check shapes a shipped template may name.
|
|
@@ -85,16 +85,14 @@ export interface RoutineGate {
|
|
|
85
85
|
readonly checks: readonly RoutineGateCheck[];
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
* work for ever. */
|
|
97
|
-
export const GATE_COMMIT_TOKEN = "<<gateCommit>>";
|
|
88
|
+
// Task 2663 — `GATE_COMMIT_TOKEN` is deleted. It stood in for a
|
|
89
|
+
// `scheduling-gate` call the routine's own turn made to advance its watermark,
|
|
90
|
+
// and the whole reason it had to be a token was that a template cannot write the
|
|
91
|
+
// event id the MERGE mints, while a turn only ever sees the first eight
|
|
92
|
+
// characters of it. That hazard is gone with the commit: the platform advances
|
|
93
|
+
// the mark itself, from the dispatcher, which holds the whole id by
|
|
94
|
+
// construction. A prompt that still contains the literal token is harmless prose
|
|
95
|
+
// naming a tool argument that no longer exists.
|
|
98
96
|
|
|
99
97
|
/** True when the check compares against a stored position rather than reading a
|
|
100
98
|
* current one.
|
|
@@ -233,9 +231,7 @@ An appointment on the provider calendar with no counterpart in the graph is invi
|
|
|
233
231
|
|
|
234
232
|
If the account has a busy-time sync configured, run schedule-connector-busy-sync so availability reflects what was just reconciled.
|
|
235
233
|
|
|
236
|
-
Reply only when something was actually changed, naming what and why. A clean reconcile ends the turn without replying, every time. This routine runs often, so a message on every clean run trains the operator to ignore it
|
|
237
|
-
|
|
238
|
-
When the run has finished and nothing failed, call scheduling-gate with <<gateCommit>> so the next run does not re-examine what you have just reconciled. Do not call it after a run that failed or that you stopped early: the work would be marked as handled without anyone having seen it.`;
|
|
234
|
+
Reply only when something was actually changed, naming what and why. A clean reconcile ends the turn without replying, every time. This routine runs often, so a message on every clean run trains the operator to ignore it.`;
|
|
239
235
|
|
|
240
236
|
const CONTACT_RECONCILE = `Reconcile the people the business actually deals with against the people it has recorded.
|
|
241
237
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what Maxy 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:fb655268fc14f30d5f01bea4a96c8b69a330d1651cc54ced5ba07850209426c8
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -2969,6 +2969,8 @@ Ask Maxy: "What messages has the bot received?" or "Show recent Telegram activit
|
|
|
2969
2969
|
|
|
2970
2970
|
**Messages not arriving:** Make sure the bot hasn't been blocked. Try sending `/start` to the bot directly.
|
|
2971
2971
|
|
|
2972
|
+
**A scheduled routine never reaches you on Telegram:** Your numeric ID being on more than one account's admin list is fine. The routine goes out on the bot belonging to the account that owns the routine. It is refused only when **two bots on that same account** both list you, because nothing in the routine says which of the two should carry it. Take yourself off one of them, or point the routine at an ID that only one bot lists.
|
|
2973
|
+
|
|
2972
2974
|
## Sending from the dashboard
|
|
2973
2975
|
|
|
2974
2976
|
Open a Telegram conversation in the dashboard and you can type a reply straight
|
|
@@ -6309,9 +6311,11 @@ The final step in the retrieval pipeline is injecting retrieved content into the
|
|
|
6309
6311
|
|
|
6310
6312
|
### Channel spawn routing by role
|
|
6311
6313
|
|
|
6312
|
-
The manager exposes three named spawn routes: `/rc-spawn` (a live `claude --remote-control` PTY — the operator sidebar, the channel admin,
|
|
6314
|
+
The manager exposes three named spawn routes: `/rc-spawn` (a live `claude --remote-control` PTY — the operator sidebar, the channel admin, the one-shot admin jobs, and every public Telegram bot), `/public-spawn` (the renamed `/spawn` — `spawnClaudeSession`, whose public surface is empty), and the `rc-daemon` it drives. No route named `/spawn` remains; a manager boot line `[spawn-routes] live=[rc-spawn,public-spawn]` asserts this.
|
|
6315
|
+
|
|
6316
|
+
**What a public spawn holds.** On WhatsApp and webchat, nothing. On Telegram, four message tools and nothing else: `telegram-card`, `telegram-ask`, `telegram-media-send` and `telegram-media-fetch`, granted on `/rc-spawn` when the spawn carries a bot and chat to pin them to. The bot and the chat come from the spawn, never from the turn, so a visitor's message cannot steer a send into another person's conversation or act as another bot on the account.
|
|
6313
6317
|
|
|
6314
|
-
**A public spawn may not name a specialist.** The
|
|
6318
|
+
**A public spawn may not name a specialist.** The ringfence is built from four levers, and two of them — the `--allowed-tools` push and the resolved permission mode — branch on whether the spawn is a specialist rather than on whether it is public, so a specialist named on a public spawn would skip the allowlist entirely and resolve the caller's mode instead of the fail-closed `dontAsk`. Only the per-spawn `permissions.deny` and `--strict-mcp-config` bind on the public role alone. Neither production issuer sends the pairing: the channel bridge is the only caller whose role can be public and it carries no specialist field, while the cookie-auth session wrapper is admin-only. So the pairing is refused rather than reshaped — `/public-spawn` answers `400 specialist-not-permitted-on-public`, and `spawnClaudeSession` refuses it again with `reason=public-specialist-refused` at the single chokepoint every spawn route passes through. Refusing rather than narrowing the levers is deliberate: a narrowed lever would leave a specialist running silently on a one-tool surface. Every spawn that reaches `spawnClaudeSession` — which is every `/public-spawn`, that route being its only caller — logs the three deciding inputs together as `[spawn-lockdown] role=<role> specialist=<name|none> permissionMode=<mode>`. A refusal at either layer logs `op=public-specialist-refused` instead, told apart by `site=`.
|
|
6315
6319
|
|
|
6316
6320
|
The channel PTY-bridge (`ensureEntry`) routes each inbound by role: an **admin** WhatsApp/Telegram inbound spawns on `/rc-spawn` (keyed by a deterministic per-sender sessionId so the thread resumes across restarts) and drives every turn via `/<id>/input`; a **non-admin** inbound spawns on `/public-spawn`. Each dispatch logs `[<channel>-adaptor] route role=<role> target=<rc-spawn|public-spawn> senderId=…`. LinkedIn ingest and the public session-end review also run on `/rc-spawn`, carrying their prompt as `initialMessage` with `closeAfterTurn` so the PTY stops after one assistant turn.
|
|
6317
6321
|
|
|
@@ -9,6 +9,16 @@ 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-08-11 (0.1.593)
|
|
13
|
+
|
|
14
|
+
- A public Telegram bot can now use buttons, media and the rest of the channel. It held no tool at all, so every answer it gave was plain text.
|
|
15
|
+
- A scheduled Telegram routine is no longer refused for an ambiguity its own account already settles: it was being turned away over which bot to use when only one was possible.
|
|
16
|
+
- Two faults in the record of how far a check has read, both of which lost the position without saying so. A damaged file silently reset every position and the next accepted wake wrote over it, so the evidence disappeared with the fault; and a file holding a list rather than a set of entries passed the validity check and was then emptied on the next advance.
|
|
17
|
+
|
|
18
|
+
## 2026-08-10 (0.1.592)
|
|
19
|
+
|
|
20
|
+
- A routine that has nothing to do now stops waking the assistant. The record of how far a check had already read was written by the assistant itself, so if it finished a turn without noting that it had looked, the routine woke again on the next tick and kept doing so. The platform now moves that marker itself once a wake is accepted, and a standing check reports a marker that has stopped moving.
|
|
21
|
+
|
|
12
22
|
## 2026-08-10 (0.1.591)
|
|
13
23
|
|
|
14
24
|
- A routine that watches Telegram can now be pointed at one bot. Before, it watched every bot on the account, so a routine watching your booking bot also woke up for every message to any other bot beside it, did the work, and threw it away. Naming a bot that does not exist is now reported as a fault rather than quietly treated as "nothing to do".
|
|
@@ -357,9 +357,11 @@ The final step in the retrieval pipeline is injecting retrieved content into the
|
|
|
357
357
|
|
|
358
358
|
### Channel spawn routing by role
|
|
359
359
|
|
|
360
|
-
The manager exposes three named spawn routes: `/rc-spawn` (a live `claude --remote-control` PTY — the operator sidebar, the channel admin,
|
|
360
|
+
The manager exposes three named spawn routes: `/rc-spawn` (a live `claude --remote-control` PTY — the operator sidebar, the channel admin, the one-shot admin jobs, and every public Telegram bot), `/public-spawn` (the renamed `/spawn` — `spawnClaudeSession`, whose public surface is empty), and the `rc-daemon` it drives. No route named `/spawn` remains; a manager boot line `[spawn-routes] live=[rc-spawn,public-spawn]` asserts this.
|
|
361
361
|
|
|
362
|
-
**
|
|
362
|
+
**What a public spawn holds.** On WhatsApp and webchat, nothing. On Telegram, four message tools and nothing else: `telegram-card`, `telegram-ask`, `telegram-media-send` and `telegram-media-fetch`, granted on `/rc-spawn` when the spawn carries a bot and chat to pin them to. The bot and the chat come from the spawn, never from the turn, so a visitor's message cannot steer a send into another person's conversation or act as another bot on the account.
|
|
363
|
+
|
|
364
|
+
**A public spawn may not name a specialist.** The ringfence is built from four levers, and two of them — the `--allowed-tools` push and the resolved permission mode — branch on whether the spawn is a specialist rather than on whether it is public, so a specialist named on a public spawn would skip the allowlist entirely and resolve the caller's mode instead of the fail-closed `dontAsk`. Only the per-spawn `permissions.deny` and `--strict-mcp-config` bind on the public role alone. Neither production issuer sends the pairing: the channel bridge is the only caller whose role can be public and it carries no specialist field, while the cookie-auth session wrapper is admin-only. So the pairing is refused rather than reshaped — `/public-spawn` answers `400 specialist-not-permitted-on-public`, and `spawnClaudeSession` refuses it again with `reason=public-specialist-refused` at the single chokepoint every spawn route passes through. Refusing rather than narrowing the levers is deliberate: a narrowed lever would leave a specialist running silently on a one-tool surface. Every spawn that reaches `spawnClaudeSession` — which is every `/public-spawn`, that route being its only caller — logs the three deciding inputs together as `[spawn-lockdown] role=<role> specialist=<name|none> permissionMode=<mode>`. A refusal at either layer logs `op=public-specialist-refused` instead, told apart by `site=`.
|
|
363
365
|
|
|
364
366
|
The channel PTY-bridge (`ensureEntry`) routes each inbound by role: an **admin** WhatsApp/Telegram inbound spawns on `/rc-spawn` (keyed by a deterministic per-sender sessionId so the thread resumes across restarts) and drives every turn via `/<id>/input`; a **non-admin** inbound spawns on `/public-spawn`. Each dispatch logs `[<channel>-adaptor] route role=<role> target=<rc-spawn|public-spawn> senderId=…`. LinkedIn ingest and the public session-end review also run on `/rc-spawn`, carrying their prompt as `initialMessage` with `closeAfterTurn` so the PTY stops after one assistant turn.
|
|
365
367
|
|
|
@@ -146,6 +146,8 @@ Ask {{productName}}: "What messages has the bot received?" or "Show recent Teleg
|
|
|
146
146
|
|
|
147
147
|
**Messages not arriving:** Make sure the bot hasn't been blocked. Try sending `/start` to the bot directly.
|
|
148
148
|
|
|
149
|
+
**A scheduled routine never reaches you on Telegram:** Your numeric ID being on more than one account's admin list is fine. The routine goes out on the bot belonging to the account that owns the routine. It is refused only when **two bots on that same account** both list you, because nothing in the routine says which of the two should carry it. Take yourself off one of them, or point the routine at an ID that only one bot lists.
|
|
150
|
+
|
|
149
151
|
## Sending from the dashboard
|
|
150
152
|
|
|
151
153
|
Open a Telegram conversation in the dashboard and you can type a reply straight
|
|
@@ -330,7 +330,7 @@ Written as one model turn instead — "check whether it is signed yet and, if it
|
|
|
330
330
|
|
|
331
331
|
**Gate check vocabulary.** A **`mail`** check answers whether a UID strictly above the stored watermark exists in the folder, optionally narrowed by `subjectPrefixes`. It is not "is there mail" — an empty answer on a full mailbox is the normal quiet state. The IMAP range `UID <n+1>:*` still yields the folder's last message when `n` is at or above the highest assigned UID (RFC 3501 §6.4.8), so the probe drops anything at or below the watermark before deciding; `[scheduling-gate] op=mail-probe … returned=<n> aboveWatermark=<n>` reports both counts, and `returned` exceeding `aboveWatermark` by exactly one is the steady state. A UIDVALIDITY change reports work, because the stored UID then names a different message. The watermark is keyed `<mailbox>|<folder>` with the folder lower-cased, because `INBOX` is case-insensitive by RFC 3501 §5.1: a binding that writes `"folder": "inbox"` and one that writes `"INBOX"` address one entry, so changing the case of an existing binding does not reset the position. The mailbox segment keeps its case, because a local part is case-sensitive. Keys already stored in mixed case fold on read, highest `uid` winning, and `[scheduling-gate] op=watermark-fold … kept=<key> droppedUid=<n>` names what the repair discarded.
|
|
332
332
|
|
|
333
|
-
A **`telegram`** check answers whether any of the account's Telegram conversations holds an inbound message whose `createdAt` is strictly above the stored one. Inbound is `origin === 'inbound'`, so an agent reply or an operator-typed message never counts as work, and update rows (a transcription, an edit, a deletion) never do either — they patch a message that already arrived. The position is the store's own ISO `createdAt`, not Telegram's `telegramDate`: that field is absent from every row written before it was introduced, so a check reading it would report work for ever on a conversation of older rows. `inbound` is the only scope, because Telegram is a webhook and has no connection for a `status` twin to read, and a scope other than `inbound` is refused when the gate is written. An account with no inbound row at all reports no work and no position, so it
|
|
333
|
+
A **`telegram`** check answers whether any of the account's Telegram conversations holds an inbound message whose `createdAt` is strictly above the stored one. Inbound is `origin === 'inbound'`, so an agent reply or an operator-typed message never counts as work, and update rows (a transcription, an edit, a deletion) never do either — they patch a message that already arrived. The position is the store's own ISO `createdAt`, not Telegram's `telegramDate`: that field is absent from every row written before it was introduced, so a check reading it would report work for ever on a conversation of older rows. `inbound` is the only scope, because Telegram is a webhook and has no connection for a `status` twin to read, and a scope other than `inbound` is refused when the gate is written. An account with no inbound row at all reports no work and no position, so it contributes no key to `observed` and nothing advances for it rather than advancing onto nothing.
|
|
334
334
|
|
|
335
335
|
**Name `botId` to watch one bot.** Without it the check answers for every bot on the account, so a routine watching a booking bot also wakes for a relay bot beside it, and the turn then filters away work it was woken for. `botId` is the bot's numeric id as it appears in a conversation's `<botId>:<senderId>` key, never a bot token: a token is a credential and would land in the event's stored gate arguments and in every log line that prints them. An id the account does not hold is **refused by the probe and counts as work**, never as quiet — a gate that can never fire is the failure that loses a booking, and it would leave no error anywhere. Each scope keeps its own position, so narrowing an existing gate to one bot starts that bot fresh rather than inheriting a mark taken across all of them.
|
|
336
336
|
|
|
@@ -338,15 +338,15 @@ A **`telegram`** check answers whether any of the account's Telegram conversatio
|
|
|
338
338
|
|
|
339
339
|
**A check type outside that vocabulary is refused when the gate is written**, on create and on update, logging `[schedule-authoring] op=gate-refused … reason=unknown-check-type checks=<csv>`. Nothing inspected the type before this guard existed: such a gate stored cleanly, then threw inside the tool on every fire, and the dispatcher's fail-open spent a full model turn each time while `schedule-list` and `/routines` both read "gated". A row bound earlier now reports `[scheduling-gate] op=check-error kind=<type> treatedAs=has-work` instead of throwing out of the tool with no line at all.
|
|
340
340
|
|
|
341
|
-
**The write proves the gate.** Every refusal above judges the gate's shape, and a gate naming a database that is not registered, a mailbox whose host does not resolve, or an account whose socket is down is well-formed and passes all of them. So the write runs the gate once
|
|
341
|
+
**The write proves the gate.** Every refusal above judges the gate's shape, and a gate naming a database that is not registered, a mailbox whose host does not resolve, or an account whose socket is down is well-formed and passes all of them. So the write runs the gate once and refuses it when any check throws, quoting the source's own message — the `HTTP 403`, the `getaddrinfo EAI_AGAIN`, the `fetch failed`. `hasWork` is not judged: both answers are correct at bind time, and refusing on `true` would refuse every gate bound while work is pending. A source that breaks *after* a proven bind still wakes the model, unchanged, because fail-open at dispatch is deliberate. Acceptance leaves `[schedule-authoring] op=gate-accepted eventId=… route=probed checks=…` naming every kind the gate carries, and refusal leaves `op=gate-refused eventId=… reason=check-unreachable checks=…` naming only the kinds that failed. The probe carries no timeout, matching the fire.
|
|
342
342
|
|
|
343
|
-
**
|
|
343
|
+
**The platform advances the watermark, never the model.** `mail`, `calendar`, `telegram`, and `whatsapp` in `inbound` scope compare against a stored position. The dispatcher advances that position itself, immediately after the inject route accepts the wake it decided on, using the positions the gate returned in `observed`. A refused wake (`httpStatus` not 200) and a fail-open advance nothing, so work the model never received stays above the mark and the next fire reports it again. `d1` and `whatsapp` in `status` scope hold no position and nothing advances for them; because `d1` holds none, its statement must count only the rows that arrived since the previous fire — a running total or `SELECT COALESCE(MAX(id),0)` can never reach zero, so the gate passes on every fire and saves nothing.
|
|
344
344
|
|
|
345
|
-
|
|
345
|
+
Nothing is asked of the routine's prompt. There is no `commit` parameter, no write-time refusal for a gate carrying a watermarked check, and a prompt naming the tool does nothing. An earlier design made the agent's own turn the only writer of the mark, and a model that forgot the call, or made it against the eight-character prefix of its event id, left the routine waking every minute against a source that had not moved.
|
|
346
346
|
|
|
347
|
-
|
|
347
|
+
The position written is the one the GATE read, carried back in the result rather than re-probed at advance time. A message arriving between the gate call and the advance therefore stays ABOVE the mark and the next fire reports it.
|
|
348
348
|
|
|
349
|
-
|
|
349
|
+
Three lines record it. `[schedule-gate] op=mark-advanced eventId=… advanced=… positions=…` per accepted wake, `op=mark-not-advanced eventId=… reason=no-observation|watermark-unreadable|write-failed` when nothing moved, and the standing `[schedule-audit] op=gate-mark-stalled acct=… count=… eventIds=[…]`, which names any gated event with three or more accepted wakes since its mark last moved. That last one is the check for the failure that emits nothing at all: a promote that runs, writes nothing, and leaves every surface reading normally. `op=gate-watermark-age` measures the same mark against the clock and so reads a weekly routine as stale; this one measures it against the routine's own wakes. A watermark file that exists and is not a watermark object is named by `[scheduling-gate] op=watermark-unreadable eventId=… reason=…` on every read of it, and is never overwritten, so its positions survive for an operator to look at; a missing file stays silent, because that is a first fire. `reason=` names the shape found: a body holding a JSON array reads `an array, not a watermark object`, because an array is an object to `typeof` and so passed the guard, was promoted into, and was then written back by `JSON.stringify` with every promoted position dropped.
|
|
350
350
|
|
|
351
351
|
**Recurring only.** A one-time agent event is never gated — its row is already `due` by the time the dispatcher sees it, so a skip there would drop the routine for good — and it is therefore outside the refusal. `schedule-update` takes no waiver either: an existing routine keeps what it has until it is edited.
|
|
352
352
|
|
|
@@ -376,10 +376,9 @@ eagerTool(server, "schedule-update", "Update an event's properties or append a n
|
|
|
376
376
|
// ---------------------------------------------------------------------------
|
|
377
377
|
// scheduling-gate (Task 2378)
|
|
378
378
|
// ---------------------------------------------------------------------------
|
|
379
|
-
eagerTool(server, "scheduling-gate", "Precondition check for a scheduled routine: answers whether any of the named sources has new work, without running a turn. The dispatcher calls this headlessly before firing a gated routine and reads structuredContent.hasWork.
|
|
379
|
+
eagerTool(server, "scheduling-gate", "Precondition check for a scheduled routine: answers whether any of the named sources has new work, without running a turn. The dispatcher calls this headlessly before firing a gated routine and reads structuredContent.hasWork. It writes nothing. The platform advances the watermarks itself, after the wake it decided on was accepted, so a routine's own turn never has to record what it handled and never can get it wrong.", {
|
|
380
380
|
eventId: z.string().describe("The gated routine's event ID. Names the watermark file, so it must match the binding."),
|
|
381
|
-
checks: z.array(z.record(z.unknown())).describe("Checks to run. mail {type,mailbox,folder?,subjectPrefixes?} · d1 {type,database,sql} · whatsapp {type,scope:'inbound'|'status'} · calendar {type,connector} · telegram {type,scope:'inbound',botId?}. Any other type, and any field not listed here, is refused when the gate is written. Name botId to watch ONE bot: without it a telegram check answers for every bot on the account, so a routine watching a booking bot also wakes for a relay bot beside it. A botId the account does not hold is refused by the probe and counts as work, never as quiet. hasWork is true when ANY check is true. A d1 statement must count only the rows that arrived since the previous fire: this check holds no stored position and
|
|
382
|
-
commit: z.boolean().optional().describe("Advance every watermark named in checks to the position the gate call recorded before this turn started, not to what the sources hold now — 'now' is the end of your turn and already includes anything that arrived while it ran. Only the routine's own turn sets this, at the end of a successful run. A commit with no gate call before it advances nothing, which leaves the work above the watermark for the next fire."),
|
|
381
|
+
checks: z.array(z.record(z.unknown())).describe("Checks to run. mail {type,mailbox,folder?,subjectPrefixes?} · d1 {type,database,sql} · whatsapp {type,scope:'inbound'|'status'} · calendar {type,connector} · telegram {type,scope:'inbound',botId?}. Any other type, and any field not listed here, is refused when the gate is written. Name botId to watch ONE bot: without it a telegram check answers for every bot on the account, so a routine watching a booking bot also wakes for a relay bot beside it. A botId the account does not hold is refused by the probe and counts as work, never as quiet. hasWork is true when ANY check is true. A d1 statement must count only the rows that arrived since the previous fire: this check holds no stored position and nothing advances for it, so a statement whose count cannot reach zero — a running total, or MAX(id) — makes the gate pass on every fire for ever."),
|
|
383
382
|
}, async (params) => {
|
|
384
383
|
if (!accountId)
|
|
385
384
|
return refuseNoAccount("scheduling-gate");
|
|
@@ -394,7 +393,7 @@ eagerTool(server, "scheduling-gate", "Precondition check for a scheduled routine
|
|
|
394
393
|
};
|
|
395
394
|
}
|
|
396
395
|
try {
|
|
397
|
-
const result = await runSchedulingGate({ eventId: params.eventId, checks: params.checks
|
|
396
|
+
const result = await runSchedulingGate({ eventId: params.eventId, checks: params.checks }, accountId, platformRoot);
|
|
398
397
|
// structuredContent is what the dispatcher reads; the text is for a human
|
|
399
398
|
// or an agent reading the transcript and is never parsed for control flow.
|
|
400
399
|
// No outputSchema is declared: the MCP server validates structuredContent
|
|
@@ -404,14 +403,7 @@ eagerTool(server, "scheduling-gate", "Precondition check for a scheduled routine
|
|
|
404
403
|
content: [
|
|
405
404
|
{
|
|
406
405
|
type: "text",
|
|
407
|
-
|
|
408
|
-
// agent read `advanced: []` from a commit over four d1 checks and
|
|
409
|
-
// inferred a broken watermark, when the true reason was that a d1
|
|
410
|
-
// check holds no position at all.
|
|
411
|
-
text: result.advanced
|
|
412
|
-
? `hasWork=${result.hasWork} reasons=[${result.reasons.join(", ")}] ` +
|
|
413
|
-
`advanced=[${result.advanced.join(", ")}] skipped=[${(result.skipped ?? []).join(", ")}]`
|
|
414
|
-
: `hasWork=${result.hasWork} reasons=[${result.reasons.join(", ")}]`,
|
|
406
|
+
text: `hasWork=${result.hasWork} reasons=[${result.reasons.join(", ")}]`,
|
|
415
407
|
},
|
|
416
408
|
],
|
|
417
409
|
structuredContent: result,
|