@rubytech/create-maxy-code 0.1.547 → 0.1.548
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +14 -0
- package/package.json +1 -1
- package/payload/platform/lib/routine-templates/dist/index.d.ts +22 -16
- package/payload/platform/lib/routine-templates/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/dist/index.js +15 -10
- package/payload/platform/lib/routine-templates/dist/index.js.map +1 -1
- package/payload/platform/lib/routine-templates/dist/roster.d.ts +3 -3
- package/payload/platform/lib/routine-templates/dist/roster.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/src/__tests__/seed.test.ts +15 -11
- package/payload/platform/lib/routine-templates/src/index.ts +23 -17
- package/payload/platform/lib/routine-templates/src/roster.ts +3 -3
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +41 -9
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +40 -8
- package/payload/platform/plugins/scheduling/PLUGIN.md +6 -0
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +6 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.js +54 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/update-summary.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.d.ts +17 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.js +43 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/update-summary.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.js +87 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/converge-routine-description.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.js +123 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/description-coverage.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +36 -0
- 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 +89 -0
- 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 +13 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.d.ts +35 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.js +56 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.js +80 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-summary.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts +2 -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 +19 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
- package/payload/platform/plugins/telegram/PLUGIN.md +2 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js +47 -47
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.d.ts +16 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.js +50 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/secret-path.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.d.ts +8 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.js +12 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/webhook-url.js.map +1 -0
- package/payload/platform/plugins/telegram/references/setup-guide.md +2 -0
- package/payload/platform/plugins/telegram/skills/configure/SKILL.md +6 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +8 -3
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +10 -3
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/server.js +1 -1
- package/payload/platform/services/telegram-channel/dist/server.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/turn-follow.js +33 -1
- package/payload/platform/services/telegram-channel/dist/turn-follow.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +8 -3
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +10 -3
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.js +33 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +28 -4
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +30 -7
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +13 -5
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +2 -0
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.js +14 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.js +34 -1
- package/payload/platform/services/whatsapp-channel/dist/turn-follow.js.map +1 -1
- package/payload/server/{chunk-MHNHG3GL.js → chunk-G6ULACHG.js} +1 -1
- package/payload/server/{chunk-Q33KT7YJ.js → chunk-JOVREC6E.js} +117 -1
- package/payload/server/{chunk-WGMIUXXG.js → chunk-SKYZG6OT.js} +11 -0
- package/payload/server/{manager-W32LVPCT.js → manager-2VEJKVEO.js} +2 -2
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/public/assets/routines-OGFXwTFO.js +2 -0
- package/payload/server/public/assets/routines-OGFXwTFO.js.br +0 -0
- package/payload/server/public/assets/routines-OGFXwTFO.js.gz +0 -0
- package/payload/server/public/routines.html +1 -1
- package/payload/server/server.js +278 -169
- package/payload/server/public/assets/routines-Ds0yz7_C.js +0 -2
- package/payload/server/public/assets/routines-Ds0yz7_C.js.br +0 -0
- package/payload/server/public/assets/routines-Ds0yz7_C.js.gz +0 -0
package/dist/index.js
CHANGED
|
@@ -3405,6 +3405,20 @@ function setupAccount() {
|
|
|
3405
3405
|
env: { ...neo4jEnv, PLATFORM_ROOT: join(INSTALL_DIR, "platform") },
|
|
3406
3406
|
});
|
|
3407
3407
|
}
|
|
3408
|
+
// Task 2361 — collapse the two routine description properties onto
|
|
3409
|
+
// `:Event.description`, preferring whichever value the operator or the agent
|
|
3410
|
+
// wrote. Runs after the seed for the same reasons the convergence above does:
|
|
3411
|
+
// the schema exists by then, and the same Neo4j env is already built. Scoped to
|
|
3412
|
+
// this install's accounts via PLATFORM_ROOT, so a co-resident brand sharing one
|
|
3413
|
+
// Neo4j is untouched. Idempotent: a converged install matches nothing and
|
|
3414
|
+
// prints converged=0.
|
|
3415
|
+
const convergeRoutineDescription = join(INSTALL_DIR, "platform/plugins/scheduling/mcp/dist/scripts/converge-routine-description.js");
|
|
3416
|
+
if (existsSync(convergeRoutineDescription)) {
|
|
3417
|
+
shell("node", [convergeRoutineDescription], {
|
|
3418
|
+
cwd: INSTALL_DIR,
|
|
3419
|
+
env: { ...neo4jEnv, PLATFORM_ROOT: join(INSTALL_DIR, "platform") },
|
|
3420
|
+
});
|
|
3421
|
+
}
|
|
3408
3422
|
// Task 165 — register every bundled specialist subagent at
|
|
3409
3423
|
// $CLAUDE_CONFIG_DIR/agents/<name>.md. Claude Code's `--agent <name>`
|
|
3410
3424
|
// discovery only resolves under this path; without these symlinks,
|
package/package.json
CHANGED
|
@@ -70,13 +70,14 @@ export interface RoutineVerifyCounts {
|
|
|
70
70
|
actual: number;
|
|
71
71
|
suspended: number;
|
|
72
72
|
nextRunNull: number;
|
|
73
|
-
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
73
|
+
/** Roster rows holding no description. Zero is the healthy value on every
|
|
74
|
+
* account, not only a fresh one: `VERIFY_CYPHER` matches `routineTemplate IS
|
|
75
|
+
* NOT NULL`, so operator-created routines are outside its scope and cannot
|
|
76
|
+
* contribute. Anything above zero while `expected === actual` is a MERGE that
|
|
77
|
+
* wrote no description on create, or a row whose key left the roster before
|
|
78
|
+
* the convergence ran — the one failure here that emits no error and does not
|
|
79
|
+
* reproduce. `[schedule-audit] op=description-coverage` is the wider twin,
|
|
80
|
+
* over every automation row rather than the roster alone. */
|
|
80
81
|
descNull: number;
|
|
81
82
|
}
|
|
82
83
|
export interface RoutineSeedReport {
|
|
@@ -124,17 +125,22 @@ export declare function resolveOwnerTimezone(session: SeedSessionLike, accountId
|
|
|
124
125
|
* destination, or reset a retimed cron. Only the prompt, the name and the
|
|
125
126
|
* version move, and only when the row is behind and unedited.
|
|
126
127
|
*
|
|
127
|
-
* `
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
|
|
128
|
+
* `description` (Task 2361) is guarded exactly as the prompt and the name are,
|
|
129
|
+
* and that is a change of shape from Task 2214, which introduced it. It used to
|
|
130
|
+
* be written on every match, on the grounds that it was roster-owned and the
|
|
131
|
+
* routines PATCH refused it, so no operator edit existed for the seed to
|
|
132
|
+
* clobber, and that gating it would leave every operator-edited row
|
|
133
|
+
* description-less permanently because `skip-operator-edited` takes neither
|
|
134
|
+
* branch. Both halves of that argument are gone. The routines PATCH now accepts
|
|
135
|
+
* `description` and stamps `operatorEdited`, so an unconditional write would
|
|
136
|
+
* destroy the operator's own caption on the next version bump; and the
|
|
137
|
+
* scheduling plugin's one-shot `converge-routine-description` has already given
|
|
138
|
+
* every pre-existing row a description, so no row is left holding only a
|
|
139
|
+
* title. */
|
|
140
|
+
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\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";
|
|
135
141
|
/** The post-condition read. Counts every roster row the account actually holds,
|
|
136
142
|
* independently of what the MERGE above believes it wrote. */
|
|
137
|
-
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.
|
|
143
|
+
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";
|
|
138
144
|
export interface SeedRoutineRosterArgs {
|
|
139
145
|
session: SeedSessionLike;
|
|
140
146
|
accountId: string;
|
|
@@ -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;AAE7F,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5F,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;2EAG2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAClH;AAED;;;;;;;4EAO4E;AAC5E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,iBAAiB,GAAG,sBAAsB,GAAG,WAAW,CAAC;AAErG,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED;;;;;;0EAM0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB
|
|
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;AAE7F,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5F,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;2EAG2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAClH;AAED;;;;;;;4EAO4E;AAC5E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,iBAAiB,GAAG,sBAAsB,GAAG,WAAW,CAAC;AAErG,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED;;;;;;0EAM0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;kEAO8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,eAAe,GAAG,QAAQ,CAAC;IAC3C,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAYD;4DAC4D;AAC5D,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,eAAe,GAAG,QAAQ,CAAA;CAAE,CAAC,CAa1E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;aAyBa;AACb,eAAO,MAAM,YAAY,8+DAwCwB,CAAC;AAElD;+DAC+D;AAC/D,eAAO,MAAM,aAAa,wVAMgD,CAAC;AAE3E,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,MAAM,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACpC,+DAA+D;IAC/D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B;sEACkE;IAClE,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgF/F"}
|
|
@@ -92,13 +92,18 @@ async function resolveOwnerTimezone(session, accountId) {
|
|
|
92
92
|
* destination, or reset a retimed cron. Only the prompt, the name and the
|
|
93
93
|
* version move, and only when the row is behind and unedited.
|
|
94
94
|
*
|
|
95
|
-
* `
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
95
|
+
* `description` (Task 2361) is guarded exactly as the prompt and the name are,
|
|
96
|
+
* and that is a change of shape from Task 2214, which introduced it. It used to
|
|
97
|
+
* be written on every match, on the grounds that it was roster-owned and the
|
|
98
|
+
* routines PATCH refused it, so no operator edit existed for the seed to
|
|
99
|
+
* clobber, and that gating it would leave every operator-edited row
|
|
100
|
+
* description-less permanently because `skip-operator-edited` takes neither
|
|
101
|
+
* branch. Both halves of that argument are gone. The routines PATCH now accepts
|
|
102
|
+
* `description` and stamps `operatorEdited`, so an unconditional write would
|
|
103
|
+
* destroy the operator's own caption on the next version bump; and the
|
|
104
|
+
* scheduling plugin's one-shot `converge-routine-description` has already given
|
|
105
|
+
* every pre-existing row a description, so no row is left holding only a
|
|
106
|
+
* title. */
|
|
102
107
|
exports.MERGE_CYPHER = `
|
|
103
108
|
UNWIND $rows AS row
|
|
104
109
|
OPTIONAL MATCH (pre:Event {accountId: $accountId, routineTemplate: row.key})
|
|
@@ -111,7 +116,7 @@ WITH row, existed, priorVersion, edited,
|
|
|
111
116
|
MERGE (e:Event {accountId: $accountId, routineTemplate: row.key})
|
|
112
117
|
ON CREATE SET e.eventId = randomUUID(),
|
|
113
118
|
e.name = row.name,
|
|
114
|
-
e.
|
|
119
|
+
e.description = row.description,
|
|
115
120
|
e.agentPrompt = row.prompt,
|
|
116
121
|
e.recurrence = row.recurrence,
|
|
117
122
|
e.routineTemplateVersion = $version,
|
|
@@ -131,7 +136,7 @@ MERGE (e:Event {accountId: $accountId, routineTemplate: row.key})
|
|
|
131
136
|
e.updatedAt = $now
|
|
132
137
|
ON MATCH SET e.agentPrompt = CASE WHEN refreshing THEN row.prompt ELSE e.agentPrompt END,
|
|
133
138
|
e.name = CASE WHEN refreshing THEN row.name ELSE e.name END,
|
|
134
|
-
e.
|
|
139
|
+
e.description = CASE WHEN refreshing THEN row.description ELSE e.description END,
|
|
135
140
|
e.routineTemplateVersion = CASE WHEN refreshing THEN $version ELSE e.routineTemplateVersion END,
|
|
136
141
|
e.updatedAt = CASE WHEN refreshing THEN $now ELSE e.updatedAt END
|
|
137
142
|
RETURN row.key AS key,
|
|
@@ -148,7 +153,7 @@ WHERE e.routineTemplate IS NOT NULL
|
|
|
148
153
|
RETURN count(e) AS actual,
|
|
149
154
|
sum(CASE WHEN e.eventStatus = 'suspended' THEN 1 ELSE 0 END) AS suspended,
|
|
150
155
|
sum(CASE WHEN e.nextRun IS NULL THEN 1 ELSE 0 END) AS nextRunNull,
|
|
151
|
-
sum(CASE WHEN e.
|
|
156
|
+
sum(CASE WHEN e.description IS NULL THEN 1 ELSE 0 END) AS descNull`;
|
|
152
157
|
/**
|
|
153
158
|
* Seed (or re-seed) the roster for one account and report what happened.
|
|
154
159
|
*
|
|
@@ -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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"}
|
|
@@ -43,9 +43,9 @@ export interface RoutineTemplate {
|
|
|
43
43
|
/** The title shown on `/routines`. */
|
|
44
44
|
readonly name: string;
|
|
45
45
|
/** One sentence under the title on the card: what this does and what it will
|
|
46
|
-
* not do.
|
|
47
|
-
*
|
|
48
|
-
*
|
|
46
|
+
* not do. Seeded onto `e.description`, which the operator can then edit from
|
|
47
|
+
* the routines page. The seed rewrites it only on a version refresh of an
|
|
48
|
+
* unedited row, so an operator's own wording survives every upgrade. */
|
|
49
49
|
readonly description: string;
|
|
50
50
|
/** The proposed cron. Written ON CREATE only, never refreshed, so an operator
|
|
51
51
|
* who retimes a routine keeps their expression across upgrades. */
|
|
@@ -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,MAAM,WAAW,eAAe;IAC9B;;mEAE+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;
|
|
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,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;CACzB;AAgKD;;;;;;;;iFAQiF;AACjF,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAyGpD,CAAC;AAEF;;6DAE6D;AAC7D,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAqC,CAAC"}
|
|
@@ -84,7 +84,7 @@ describe("MERGE statement shape", () => {
|
|
|
84
84
|
for (const required of [
|
|
85
85
|
"eventId",
|
|
86
86
|
"name",
|
|
87
|
-
"
|
|
87
|
+
"description",
|
|
88
88
|
"agentPrompt",
|
|
89
89
|
"recurrence",
|
|
90
90
|
"routineTemplateVersion",
|
|
@@ -121,20 +121,24 @@ describe("MERGE statement shape", () => {
|
|
|
121
121
|
|
|
122
122
|
it("ON MATCH touches ONLY the prompt, name, description, version and updatedAt", () => {
|
|
123
123
|
expect(new Set(propertiesSetIn("ON MATCH SET"))).toEqual(
|
|
124
|
-
new Set(["agentPrompt", "name", "
|
|
124
|
+
new Set(["agentPrompt", "name", "description", "routineTemplateVersion", "updatedAt"]),
|
|
125
125
|
);
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
-
it("ON MATCH writes the description
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
//
|
|
128
|
+
it("ON MATCH writes the description only when refreshing, exactly as the prompt and name are", () => {
|
|
129
|
+
// The 2214 shape wrote it on every match, because gating it would have left
|
|
130
|
+
// every operator-edited row description-less for ever: skip-operator-edited
|
|
131
|
+
// takes neither branch. Task 2361's one-shot convergence removes that
|
|
132
|
+
// argument by giving every pre-existing row a description before the first
|
|
133
|
+
// guarded MERGE runs, and from here the description is operator-writable, so
|
|
134
|
+
// an unconditional write would clobber the operator's own text on every
|
|
135
|
+
// upgrade.
|
|
134
136
|
const start = MERGE_CYPHER.indexOf("ON MATCH SET");
|
|
135
137
|
const body = MERGE_CYPHER.slice(start, MERGE_CYPHER.indexOf("RETURN"));
|
|
136
|
-
expect(body).toContain(
|
|
137
|
-
|
|
138
|
+
expect(body).toContain(
|
|
139
|
+
"e.description = CASE WHEN refreshing THEN row.description ELSE e.description END",
|
|
140
|
+
);
|
|
141
|
+
expect(body).not.toContain("e.routineDescription");
|
|
138
142
|
});
|
|
139
143
|
|
|
140
144
|
it("verify counts the descriptions the graph actually holds", () => {
|
|
@@ -142,7 +146,7 @@ describe("MERGE statement shape", () => {
|
|
|
142
146
|
// MERGE succeeds, every action reads `refresh-version`, and the property
|
|
143
147
|
// is simply absent. `expected` and `actual` agree in that state.
|
|
144
148
|
expect(VERIFY_CYPHER).toContain(
|
|
145
|
-
"sum(CASE WHEN e.
|
|
149
|
+
"sum(CASE WHEN e.description IS NULL THEN 1 ELSE 0 END) AS descNull",
|
|
146
150
|
);
|
|
147
151
|
});
|
|
148
152
|
|
|
@@ -71,13 +71,14 @@ export interface RoutineVerifyCounts {
|
|
|
71
71
|
actual: number;
|
|
72
72
|
suspended: number;
|
|
73
73
|
nextRunNull: number;
|
|
74
|
-
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
74
|
+
/** Roster rows holding no description. Zero is the healthy value on every
|
|
75
|
+
* account, not only a fresh one: `VERIFY_CYPHER` matches `routineTemplate IS
|
|
76
|
+
* NOT NULL`, so operator-created routines are outside its scope and cannot
|
|
77
|
+
* contribute. Anything above zero while `expected === actual` is a MERGE that
|
|
78
|
+
* wrote no description on create, or a row whose key left the roster before
|
|
79
|
+
* the convergence ran — the one failure here that emits no error and does not
|
|
80
|
+
* reproduce. `[schedule-audit] op=description-coverage` is the wider twin,
|
|
81
|
+
* over every automation row rather than the roster alone. */
|
|
81
82
|
descNull: number;
|
|
82
83
|
}
|
|
83
84
|
|
|
@@ -154,13 +155,18 @@ export async function resolveOwnerTimezone(
|
|
|
154
155
|
* destination, or reset a retimed cron. Only the prompt, the name and the
|
|
155
156
|
* version move, and only when the row is behind and unedited.
|
|
156
157
|
*
|
|
157
|
-
* `
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
158
|
+
* `description` (Task 2361) is guarded exactly as the prompt and the name are,
|
|
159
|
+
* and that is a change of shape from Task 2214, which introduced it. It used to
|
|
160
|
+
* be written on every match, on the grounds that it was roster-owned and the
|
|
161
|
+
* routines PATCH refused it, so no operator edit existed for the seed to
|
|
162
|
+
* clobber, and that gating it would leave every operator-edited row
|
|
163
|
+
* description-less permanently because `skip-operator-edited` takes neither
|
|
164
|
+
* branch. Both halves of that argument are gone. The routines PATCH now accepts
|
|
165
|
+
* `description` and stamps `operatorEdited`, so an unconditional write would
|
|
166
|
+
* destroy the operator's own caption on the next version bump; and the
|
|
167
|
+
* scheduling plugin's one-shot `converge-routine-description` has already given
|
|
168
|
+
* every pre-existing row a description, so no row is left holding only a
|
|
169
|
+
* title. */
|
|
164
170
|
export const MERGE_CYPHER = `
|
|
165
171
|
UNWIND $rows AS row
|
|
166
172
|
OPTIONAL MATCH (pre:Event {accountId: $accountId, routineTemplate: row.key})
|
|
@@ -173,7 +179,7 @@ WITH row, existed, priorVersion, edited,
|
|
|
173
179
|
MERGE (e:Event {accountId: $accountId, routineTemplate: row.key})
|
|
174
180
|
ON CREATE SET e.eventId = randomUUID(),
|
|
175
181
|
e.name = row.name,
|
|
176
|
-
e.
|
|
182
|
+
e.description = row.description,
|
|
177
183
|
e.agentPrompt = row.prompt,
|
|
178
184
|
e.recurrence = row.recurrence,
|
|
179
185
|
e.routineTemplateVersion = $version,
|
|
@@ -193,7 +199,7 @@ MERGE (e:Event {accountId: $accountId, routineTemplate: row.key})
|
|
|
193
199
|
e.updatedAt = $now
|
|
194
200
|
ON MATCH SET e.agentPrompt = CASE WHEN refreshing THEN row.prompt ELSE e.agentPrompt END,
|
|
195
201
|
e.name = CASE WHEN refreshing THEN row.name ELSE e.name END,
|
|
196
|
-
e.
|
|
202
|
+
e.description = CASE WHEN refreshing THEN row.description ELSE e.description END,
|
|
197
203
|
e.routineTemplateVersion = CASE WHEN refreshing THEN $version ELSE e.routineTemplateVersion END,
|
|
198
204
|
e.updatedAt = CASE WHEN refreshing THEN $now ELSE e.updatedAt END
|
|
199
205
|
RETURN row.key AS key,
|
|
@@ -211,7 +217,7 @@ WHERE e.routineTemplate IS NOT NULL
|
|
|
211
217
|
RETURN count(e) AS actual,
|
|
212
218
|
sum(CASE WHEN e.eventStatus = 'suspended' THEN 1 ELSE 0 END) AS suspended,
|
|
213
219
|
sum(CASE WHEN e.nextRun IS NULL THEN 1 ELSE 0 END) AS nextRunNull,
|
|
214
|
-
sum(CASE WHEN e.
|
|
220
|
+
sum(CASE WHEN e.description IS NULL THEN 1 ELSE 0 END) AS descNull`;
|
|
215
221
|
|
|
216
222
|
export interface SeedRoutineRosterArgs {
|
|
217
223
|
session: SeedSessionLike;
|
|
@@ -45,9 +45,9 @@ export interface RoutineTemplate {
|
|
|
45
45
|
/** The title shown on `/routines`. */
|
|
46
46
|
readonly name: string;
|
|
47
47
|
/** One sentence under the title on the card: what this does and what it will
|
|
48
|
-
* not do.
|
|
49
|
-
*
|
|
50
|
-
*
|
|
48
|
+
* not do. Seeded onto `e.description`, which the operator can then edit from
|
|
49
|
+
* the routines page. The seed rewrites it only on a version refresh of an
|
|
50
|
+
* unedited row, so an operator's own wording survives every upgrade. */
|
|
51
51
|
readonly description: string;
|
|
52
52
|
/** The proposed cron. Written ON CREATE only, never refreshed, so an operator
|
|
53
53
|
* who retimes a routine keeps their expression across upgrades. */
|
|
@@ -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:db7c14326a115e7d05b687b72bef0ba3892f1614ee46484e0e90414bf2c16f27
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -3484,13 +3484,27 @@ The Routines surface (`/routines`) is the admin view of the account's
|
|
|
3484
3484
|
automation `:Event` nodes — the device's scheduled agent turns and tool
|
|
3485
3485
|
dispatches, which the Calendar surface deliberately excludes (`calendar.ts`
|
|
3486
3486
|
unions only appointment events, `actionPlugin IS NULL`). It renders one card per
|
|
3487
|
-
routine (title,
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3487
|
+
routine (title, its one-line description where it has one, human-readable
|
|
3488
|
+
schedule, next run, channel/destination or tool, status); a card opens a detail
|
|
3489
|
+
modal modeled on the calendar `EventDetailModal`. A shipped routine is seeded with
|
|
3490
|
+
a description and the operator can rewrite it from the modal; a routine nobody has
|
|
3491
|
+
captioned renders with no line and no placeholder. Editing it stamps the row
|
|
3492
|
+
operator-owned, so the next roster refresh leaves the operator's wording alone,
|
|
3493
|
+
and recomputes the row's search vector, which is built from the name and the
|
|
3494
|
+
description. A description is never dispatched: `agentPrompt` is the only text a
|
|
3495
|
+
fire sends.
|
|
3496
|
+
The read-only view shows two prose blocks, each under its own heading, in the
|
|
3497
|
+
order **Description** then **Instruction sent to the agent**. Both use the same
|
|
3498
|
+
header-above-prose shape, so neither reads as a different kind of thing from the
|
|
3499
|
+
other. Before this the modal showed one unheaded block, so the caption and the
|
|
3500
|
+
multi-KB prompt that actually fires were indistinguishable. The instruction
|
|
3501
|
+
heading never reads the bare word "Instruction", in either mode: that collides
|
|
3502
|
+
with the `## Instruction` block the platform appends to every dispatched channel
|
|
3503
|
+
turn, and an agent read the two as the same field. The Description block renders
|
|
3504
|
+
on every kind of routine, including a tool-action routine and a bare trigger,
|
|
3505
|
+
because both already show it on the card; the instruction block belongs to an
|
|
3506
|
+
agent routine, the only kind that has one. The modal edits the description, the
|
|
3507
|
+
prose instruction (`agentPrompt`), the dispatch binding
|
|
3494
3508
|
(`agentChannel` and `agentDestination`, chosen from a server-supplied roster
|
|
3495
3509
|
rather than typed), and the schedule via a friendly builder (frequency
|
|
3496
3510
|
daily/weekly/monthly, day-of-week, day-of-month, time) that falls back to a
|
|
@@ -3551,7 +3565,7 @@ The route (`server/routes/admin/routines.ts`) is account-scoped like `calendar.t
|
|
|
3551
3565
|
| `GET /api/admin/routines/:eventId` | One routine, same automation+account guard. |
|
|
3552
3566
|
| `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. |
|
|
3553
3567
|
| `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. |
|
|
3554
|
-
| `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`). |
|
|
3568
|
+
| `PATCH /api/admin/routines/:eventId` | Edits `agentPrompt`, `description`, `recurrence`, and the `agentChannel`/`agentDestination` pair. A `description` write stamps `operatorEdited` and recomputes the row's `embedding` from `Event: <name>` plus the new text, reading the name from the row rather than the request body; the embedder returning nothing leaves the previous vector in place and the save still succeeds. A whitespace-only `description` is stored as null, so "no caption" is one state in the graph. 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`). |
|
|
3555
3569
|
| `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. |
|
|
3556
3570
|
| `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. |
|
|
3557
3571
|
| `POST /api/admin/routines/:eventId/resume` | Returns a suspended routine to `'scheduled'`. 404s if it is not suspended, 409s if it cannot be resumed. |
|
|
@@ -3632,6 +3646,24 @@ would say so. `completed` gets its own bucket even though no code path writes it
|
|
|
3632
3646
|
today, because it remains part of the shipped enum and one row carrying it would
|
|
3633
3647
|
otherwise pin `other` above zero forever and kill the alarm.
|
|
3634
3648
|
|
|
3649
|
+
`[schedule-audit] op=description-coverage acct=<8> routines=<n>
|
|
3650
|
+
withDescription=<n> withInstruction=<n> toolActions=<n>` is the pair behind the
|
|
3651
|
+
two prose blocks the modal shows. A routine carrying an instruction and no
|
|
3652
|
+
description is a card whose title is all the operator gets; one carrying a
|
|
3653
|
+
description and no instruction is worse, because it looks explained, fires on
|
|
3654
|
+
schedule and sends nothing. Neither state writes an event of its own, so only a
|
|
3655
|
+
periodic count reveals them, and the counts sit on one line beside the total
|
|
3656
|
+
because any one of them alone answers the wrong question. `toolActions` is on the
|
|
3657
|
+
line because `withInstruction` is otherwise comparable to nothing: a tool-action
|
|
3658
|
+
routine has no instruction and is not silent, it runs a tool, so an account
|
|
3659
|
+
holding one would sit at `routines > withInstruction` for ever and the alarm
|
|
3660
|
+
would be dead from that point on. The genuinely silent count is `routines -
|
|
3661
|
+
toolActions - withInstruction`, the same reconciliation `other` performs in the
|
|
3662
|
+
suspension census. Emitted per account on every sweep tick including a healthy
|
|
3663
|
+
one, over the same automation set the routes list. The roster seed's own
|
|
3664
|
+
`descNull` counter is its narrow twin, scoped to seeded rows and so blind to
|
|
3665
|
+
exactly the operator-created ones most likely to carry no caption.
|
|
3666
|
+
|
|
3635
3667
|
**The shipped roster.** Every account starts with eleven routines —
|
|
3636
3668
|
`start-of-day`, `inbound-check`, `end-of-day`, `appointment-reminder`,
|
|
3637
3669
|
`commitment-chase`, `calendar-reconcile`, `contact-reconcile`, `crm-reconcile`,
|
|
@@ -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-08-02 (0.1.548)
|
|
13
|
+
|
|
14
|
+
- Telegram now works per account: each bot has its own address and secret, a scheduled message goes to the right account, and a check reports any bot that is set up but never delivers.
|
|
15
|
+
- Every WhatsApp reply and document send now names the account it belongs to, and a send whose account does not match its conversation is refused.
|
|
16
|
+
- Each turn now records how much the assistant actually had to work with, so a turn that came back thin can be told apart from one that failed.
|
|
17
|
+
|
|
12
18
|
## 2026-08-02 (0.1.547)
|
|
13
19
|
|
|
14
20
|
- A routine's past runs now read as cards showing status, channel and the message actually sent, with a refresh and a way back in. Runs with no captured output are flagged.
|
|
@@ -99,13 +99,27 @@ The Routines surface (`/routines`) is the admin view of the account's
|
|
|
99
99
|
automation `:Event` nodes — the device's scheduled agent turns and tool
|
|
100
100
|
dispatches, which the Calendar surface deliberately excludes (`calendar.ts`
|
|
101
101
|
unions only appointment events, `actionPlugin IS NULL`). It renders one card per
|
|
102
|
-
routine (title,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
102
|
+
routine (title, its one-line description where it has one, human-readable
|
|
103
|
+
schedule, next run, channel/destination or tool, status); a card opens a detail
|
|
104
|
+
modal modeled on the calendar `EventDetailModal`. A shipped routine is seeded with
|
|
105
|
+
a description and the operator can rewrite it from the modal; a routine nobody has
|
|
106
|
+
captioned renders with no line and no placeholder. Editing it stamps the row
|
|
107
|
+
operator-owned, so the next roster refresh leaves the operator's wording alone,
|
|
108
|
+
and recomputes the row's search vector, which is built from the name and the
|
|
109
|
+
description. A description is never dispatched: `agentPrompt` is the only text a
|
|
110
|
+
fire sends.
|
|
111
|
+
The read-only view shows two prose blocks, each under its own heading, in the
|
|
112
|
+
order **Description** then **Instruction sent to the agent**. Both use the same
|
|
113
|
+
header-above-prose shape, so neither reads as a different kind of thing from the
|
|
114
|
+
other. Before this the modal showed one unheaded block, so the caption and the
|
|
115
|
+
multi-KB prompt that actually fires were indistinguishable. The instruction
|
|
116
|
+
heading never reads the bare word "Instruction", in either mode: that collides
|
|
117
|
+
with the `## Instruction` block the platform appends to every dispatched channel
|
|
118
|
+
turn, and an agent read the two as the same field. The Description block renders
|
|
119
|
+
on every kind of routine, including a tool-action routine and a bare trigger,
|
|
120
|
+
because both already show it on the card; the instruction block belongs to an
|
|
121
|
+
agent routine, the only kind that has one. The modal edits the description, the
|
|
122
|
+
prose instruction (`agentPrompt`), the dispatch binding
|
|
109
123
|
(`agentChannel` and `agentDestination`, chosen from a server-supplied roster
|
|
110
124
|
rather than typed), and the schedule via a friendly builder (frequency
|
|
111
125
|
daily/weekly/monthly, day-of-week, day-of-month, time) that falls back to a
|
|
@@ -166,7 +180,7 @@ The route (`server/routes/admin/routines.ts`) is account-scoped like `calendar.t
|
|
|
166
180
|
| `GET /api/admin/routines/:eventId` | One routine, same automation+account guard. |
|
|
167
181
|
| `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. |
|
|
168
182
|
| `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. |
|
|
169
|
-
| `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`). |
|
|
183
|
+
| `PATCH /api/admin/routines/:eventId` | Edits `agentPrompt`, `description`, `recurrence`, and the `agentChannel`/`agentDestination` pair. A `description` write stamps `operatorEdited` and recomputes the row's `embedding` from `Event: <name>` plus the new text, reading the name from the row rather than the request body; the embedder returning nothing leaves the previous vector in place and the save still succeeds. A whitespace-only `description` is stored as null, so "no caption" is one state in the graph. 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`). |
|
|
170
184
|
| `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. |
|
|
171
185
|
| `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. |
|
|
172
186
|
| `POST /api/admin/routines/:eventId/resume` | Returns a suspended routine to `'scheduled'`. 404s if it is not suspended, 409s if it cannot be resumed. |
|
|
@@ -247,6 +261,24 @@ would say so. `completed` gets its own bucket even though no code path writes it
|
|
|
247
261
|
today, because it remains part of the shipped enum and one row carrying it would
|
|
248
262
|
otherwise pin `other` above zero forever and kill the alarm.
|
|
249
263
|
|
|
264
|
+
`[schedule-audit] op=description-coverage acct=<8> routines=<n>
|
|
265
|
+
withDescription=<n> withInstruction=<n> toolActions=<n>` is the pair behind the
|
|
266
|
+
two prose blocks the modal shows. A routine carrying an instruction and no
|
|
267
|
+
description is a card whose title is all the operator gets; one carrying a
|
|
268
|
+
description and no instruction is worse, because it looks explained, fires on
|
|
269
|
+
schedule and sends nothing. Neither state writes an event of its own, so only a
|
|
270
|
+
periodic count reveals them, and the counts sit on one line beside the total
|
|
271
|
+
because any one of them alone answers the wrong question. `toolActions` is on the
|
|
272
|
+
line because `withInstruction` is otherwise comparable to nothing: a tool-action
|
|
273
|
+
routine has no instruction and is not silent, it runs a tool, so an account
|
|
274
|
+
holding one would sit at `routines > withInstruction` for ever and the alarm
|
|
275
|
+
would be dead from that point on. The genuinely silent count is `routines -
|
|
276
|
+
toolActions - withInstruction`, the same reconciliation `other` performs in the
|
|
277
|
+
suspension census. Emitted per account on every sweep tick including a healthy
|
|
278
|
+
one, over the same automation set the routes list. The roster seed's own
|
|
279
|
+
`descNull` counter is its narrow twin, scoped to seeded rows and so blind to
|
|
280
|
+
exactly the operator-created ones most likely to carry no caption.
|
|
281
|
+
|
|
250
282
|
**The shipped roster.** Every account starts with eleven routines —
|
|
251
283
|
`start-of-day`, `inbound-check`, `end-of-day`, `appointment-reminder`,
|
|
252
284
|
`commitment-chase`, `calendar-reconcile`, `contact-reconcile`, `crm-reconcile`,
|
|
@@ -204,6 +204,12 @@ Use standard 5-field cron syntax: `minute hour day-of-month month day-of-week`.
|
|
|
204
204
|
| `0 0 1 * *` | First of each month at midnight |
|
|
205
205
|
| `*/30 * * * *` | Every 30 minutes |
|
|
206
206
|
|
|
207
|
+
## What an update confirms
|
|
208
|
+
|
|
209
|
+
`schedule-update` returns the properties it wrote: `Event updated: <id> — fields: description, recurrence`. Companions count — changing `recurrence` also writes `nextRun`, changing `eventStatus` also writes `suspendedInBulk`, and setting an `agentDispatch` also clears `actionPlugin`, `actionTool` and `actionArgs`. Four properties are never named: `updatedAt` and `operatorEdited` are stamps, `embedding` is a derived search vector, and `notes` is reported as `note appended` instead, and only when the caller supplied one that was not empty.
|
|
210
|
+
|
|
211
|
+
When `agentPrompt` is not among the fields, the line ends `(the instruction sent to the agent was not changed)`. That clause is the answer to "did my prompt rewrite land" — a confirmation without it means the dispatch prompt was written. Editing a meeting opens `Meeting updated:` and names the caller's own field names, not the stored `title`/`startsAt`/`endsAt`.
|
|
212
|
+
|
|
207
213
|
## Skip next
|
|
208
214
|
|
|
209
215
|
For recurring events, `schedule-update` with `skipNext: true` advances `nextRun` by one cycle without triggering. Use when the user says "skip tomorrow's briefing" or similar.
|
|
@@ -7,6 +7,7 @@ import { scheduleList } from "./tools/schedule-list.js";
|
|
|
7
7
|
import { scheduleGet } from "./tools/schedule-get.js";
|
|
8
8
|
import { scheduleRuns } from "./tools/schedule-runs.js";
|
|
9
9
|
import { scheduleUpdate, EVENT_STATUSES } from "./tools/schedule-update.js";
|
|
10
|
+
import { describeUpdate } from "./lib/update-summary.js";
|
|
10
11
|
import { scheduleCancel } from "./tools/schedule-cancel.js";
|
|
11
12
|
import { scheduleExportIcs } from "./tools/schedule-export-ics.js";
|
|
12
13
|
import { scheduleImportIcs } from "./tools/schedule-import-ics.js";
|
|
@@ -328,11 +329,14 @@ eagerTool(server, "schedule-update", "Update an event's properties or append a n
|
|
|
328
329
|
if (!accountId)
|
|
329
330
|
return refuseNoAccount("schedule-update");
|
|
330
331
|
try {
|
|
331
|
-
await scheduleUpdate({ ...params, accountId });
|
|
332
|
+
const written = await scheduleUpdate({ ...params, accountId });
|
|
332
333
|
if (params.skipNext) {
|
|
333
334
|
return { content: [{ type: "text", text: `Skipped next occurrence of event: ${params.eventId}` }] };
|
|
334
335
|
}
|
|
335
|
-
|
|
336
|
+
// Task 2362 — name the properties written. The flat `Event updated: <id>` this replaced read
|
|
337
|
+
// identically for a description edit and for a dispatch-prompt rewrite, and an agent read it
|
|
338
|
+
// as proof its own successful rewrite had not landed.
|
|
339
|
+
return { content: [{ type: "text", text: describeUpdate(params.eventId, written) }] };
|
|
336
340
|
}
|
|
337
341
|
catch (err) {
|
|
338
342
|
return {
|