@rubytech/create-maxy-code 0.1.548 → 0.1.549
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 +2 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +8 -6
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +5 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +7 -5
- package/payload/platform/plugins/scheduling/PLUGIN.md +6 -0
- package/payload/platform/scripts/check-routine-roster-doc.mjs +127 -0
- package/payload/server/server.js +7 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rubytech/create-maxy-code",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.549",
|
|
4
4
|
"description": "Install Maxy — AI for Productive People",
|
|
5
5
|
"bin": {
|
|
6
6
|
"create-maxy-code": "./dist/index.js"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"build": "tsc",
|
|
14
14
|
"bundle": "node scripts/bundle.js",
|
|
15
15
|
"test": "npm run build && node --test 'dist/__tests__/*.test.js'",
|
|
16
|
-
"prepublishOnly": "bash ../../platform/scripts/verify-skill-tool-surface.sh && node ../../platform/scripts/check-plugin-tools-mcp-consistency.mjs && node ../../platform/scripts/check-risk-class.mjs && node ../../platform/scripts/check-specialist-tool-surface.mjs && node ../../platform/scripts/check-agent-contract.mjs && node ../../platform/scripts/check-routing-prose-bash.mjs && node ../../platform/scripts/check-no-task-id-leaks.mjs && node ../../platform/scripts/check-no-esm-require.mjs && node ../../platform/scripts/check-no-raw-mcp-registrations.mjs && node ../../platform/scripts/check-skill-load-coverage.mjs && node ../../platform/scripts/check-architecture-skill-no-drift.mjs && node ../../platform/ui/scripts/check-brand-fonts.mjs && node ../../platform/ui/scripts/check-route-wiring.mjs && node ../../platform/ui/scripts/check-edge-admin-routes.mjs && npm run build && node --test 'dist/__tests__/*.test.js' && chmod +x dist/index.js && npm run bundle && bash ../../platform/scripts/smoke-boot-services.sh && node ../../platform/ui/scripts/check-bundle-node-imports.mjs --dir=./payload/server/public/assets"
|
|
16
|
+
"prepublishOnly": "bash ../../platform/scripts/verify-skill-tool-surface.sh && node ../../platform/scripts/check-plugin-tools-mcp-consistency.mjs && node ../../platform/scripts/check-risk-class.mjs && node ../../platform/scripts/check-specialist-tool-surface.mjs && node ../../platform/scripts/check-agent-contract.mjs && node ../../platform/scripts/check-routing-prose-bash.mjs && node ../../platform/scripts/check-no-task-id-leaks.mjs && node ../../platform/scripts/check-no-esm-require.mjs && node ../../platform/scripts/check-no-raw-mcp-registrations.mjs && node ../../platform/scripts/check-skill-load-coverage.mjs && node ../../platform/scripts/check-routine-roster-doc.mjs && node ../../platform/scripts/check-architecture-skill-no-drift.mjs && node ../../platform/ui/scripts/check-brand-fonts.mjs && node ../../platform/ui/scripts/check-route-wiring.mjs && node ../../platform/ui/scripts/check-edge-admin-routes.mjs && npm run build && node --test 'dist/__tests__/*.test.js' && chmod +x dist/index.js && npm run bundle && bash ../../platform/scripts/smoke-boot-services.sh && node ../../platform/ui/scripts/check-bundle-node-imports.mjs --dir=./payload/server/public/assets"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"dist",
|
|
@@ -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:67fd64d3983bd1c788d6945201c05ee4afeb63fd02fb033123b63e364e915430
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -3664,13 +3664,15 @@ one, over the same automation set the routes list. The roster seed's own
|
|
|
3664
3664
|
`descNull` counter is its narrow twin, scoped to seeded rows and so blind to
|
|
3665
3665
|
exactly the operator-created ones most likely to carry no caption.
|
|
3666
3666
|
|
|
3667
|
-
**The shipped roster.** Every account starts with
|
|
3667
|
+
**The shipped roster.** Every account starts with thirteen routines —
|
|
3668
3668
|
`start-of-day`, `inbound-check`, `end-of-day`, `appointment-reminder`,
|
|
3669
3669
|
`commitment-chase`, `calendar-reconcile`, `contact-reconcile`, `crm-reconcile`,
|
|
3670
|
-
`finance-reconcile`, `channel-link-check`, `
|
|
3671
|
-
`
|
|
3672
|
-
|
|
3673
|
-
|
|
3670
|
+
`finance-reconcile`, `weekly-digest`, `channel-link-check`, `graph-health`,
|
|
3671
|
+
`filesystem-health`, in `/routines` display order. `ROUTINE_ROSTER_KEYS.length`
|
|
3672
|
+
is authoritative for the count and this list follows it. They are seeded
|
|
3673
|
+
`eventStatus:'suspended'` with `nextRun` NULL and no channel or destination, so
|
|
3674
|
+
`/routines` is a catalogue to enable rather than a blank page. The list query
|
|
3675
|
+
applies no status filter and `AUTOMATION_WHERE`
|
|
3674
3676
|
admits them on `recurrence IS NOT NULL`, so they render with no change here.
|
|
3675
3677
|
They cannot fire: every dispatch query in `check-due-events.ts` selects
|
|
3676
3678
|
`eventStatus = 'scheduled'`, and the recurring one additionally requires
|
|
@@ -9,6 +9,11 @@ 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.549)
|
|
13
|
+
|
|
14
|
+
- Telegram now answers on the address it tells you to use, fixing messages that never arrived after yesterday's per-account change.
|
|
15
|
+
- The list of built-in routines in the docs is now checked against the routines that actually ship, so it cannot quietly fall out of date.
|
|
16
|
+
|
|
12
17
|
## 2026-08-02 (0.1.548)
|
|
13
18
|
|
|
14
19
|
- 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.
|
|
@@ -279,13 +279,15 @@ one, over the same automation set the routes list. The roster seed's own
|
|
|
279
279
|
`descNull` counter is its narrow twin, scoped to seeded rows and so blind to
|
|
280
280
|
exactly the operator-created ones most likely to carry no caption.
|
|
281
281
|
|
|
282
|
-
**The shipped roster.** Every account starts with
|
|
282
|
+
**The shipped roster.** Every account starts with thirteen routines —
|
|
283
283
|
`start-of-day`, `inbound-check`, `end-of-day`, `appointment-reminder`,
|
|
284
284
|
`commitment-chase`, `calendar-reconcile`, `contact-reconcile`, `crm-reconcile`,
|
|
285
|
-
`finance-reconcile`, `channel-link-check`, `
|
|
286
|
-
`
|
|
287
|
-
|
|
288
|
-
|
|
285
|
+
`finance-reconcile`, `weekly-digest`, `channel-link-check`, `graph-health`,
|
|
286
|
+
`filesystem-health`, in `/routines` display order. `ROUTINE_ROSTER_KEYS.length`
|
|
287
|
+
is authoritative for the count and this list follows it. They are seeded
|
|
288
|
+
`eventStatus:'suspended'` with `nextRun` NULL and no channel or destination, so
|
|
289
|
+
`/routines` is a catalogue to enable rather than a blank page. The list query
|
|
290
|
+
applies no status filter and `AUTOMATION_WHERE`
|
|
289
291
|
admits them on `recurrence IS NOT NULL`, so they render with no change here.
|
|
290
292
|
They cannot fire: every dispatch query in `check-due-events.ts` selects
|
|
291
293
|
`eventStatus = 'scheduled'`, and the recurring one additionally requires
|
|
@@ -210,6 +210,12 @@ Use standard 5-field cron syntax: `minute hour day-of-month month day-of-week`.
|
|
|
210
210
|
|
|
211
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
212
|
|
|
213
|
+
## What the search vector holds
|
|
214
|
+
|
|
215
|
+
A routine is findable by graph search through a vector built from its name and its description. `schedule-update` rebuilds that vector whenever a call changes either field, and it builds the text from the ROW, not from the call: an update that supplies only a description takes the name from the stored row, and one that supplies only a name takes the description. Building it from the call alone re-embedded a caption edit as `Event: — <description>`, leaving the routine findable by its caption but not its title. The admin Routines page rebuilds the same text the same way.
|
|
216
|
+
|
|
217
|
+
One line reports every rebuild, including a healthy one, so its absence cannot be read as a code path that stopped running: `[schedule-update] op=embed-recomputed eventId=<id> titled=<yes|no> nameSource=<param|stored|absent> chars=<n> wrote=<yes|no>`. `titled` is the assertion, since the vector itself cannot be read back to tell whether the title went into it. `nameSource` makes a `titled=no` actionable by separating a routine that genuinely has no name (`absent`) from a fallback that failed. `chars` is the length of the embedded text, the one figure that shows the input shrinking across successive edits. `wrote` is what keeps `titled` honest: the embedder returns nothing on any failure and the vector clause is then skipped, so `titled=yes wrote=no` means the text was correct but the row kept the vector it already had. The line is emitted after the write lands, so an id that turns out to be a meeting never produces one.
|
|
218
|
+
|
|
213
219
|
## Skip next
|
|
214
220
|
|
|
215
221
|
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.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// check-routine-roster-doc.mjs — pre-commit gate (Task 2367).
|
|
3
|
+
//
|
|
4
|
+
// `platform/plugins/docs/references/admin-ui.md` carries one paragraph naming
|
|
5
|
+
// the routines every account is seeded with. That paragraph is mirrored into
|
|
6
|
+
// the generated platform-architecture SKILL.md and ships to every account, so
|
|
7
|
+
// a routine added to ROUTINE_ROSTER and not to the paragraph is not an internal
|
|
8
|
+
// docs nit: an agent asked what routines ship answers the stale number and
|
|
9
|
+
// cannot name the ones it omits. That is exactly what happened between Task
|
|
10
|
+
// 2214 (which took the roster from eleven to thirteen) and Task 2367.
|
|
11
|
+
//
|
|
12
|
+
// Three assertions, all against the same paragraph:
|
|
13
|
+
//
|
|
14
|
+
// 1. Every roster key appears in it as a backticked token. Checked by exact
|
|
15
|
+
// substring per key, so it holds whatever a future key looks like. This is
|
|
16
|
+
// the drift that actually happened.
|
|
17
|
+
// 2. Every backticked key-SHAPED token in it is a roster key. A routine
|
|
18
|
+
// deleted from roster.ts leaves a key in the prose that names nothing, and
|
|
19
|
+
// assertion 1 cannot see that. Key-shaped means lowercase words joined by
|
|
20
|
+
// at least one hyphen, which is what every roster key has looked like
|
|
21
|
+
// since Task 2130. The cost of this rule is that an unrelated hyphenated
|
|
22
|
+
// term added to this paragraph fails the gate; the failure names the rule,
|
|
23
|
+
// so the fix is to move the term or correct the key. A hyphenless key
|
|
24
|
+
// would fall outside this scan but is still fully covered by assertion 1.
|
|
25
|
+
// 3. The number-word for the roster length appears immediately before
|
|
26
|
+
// "routines". The count and the list state one fact twice, and gating
|
|
27
|
+
// only the list leaves half the defect free to recur. This is not an
|
|
28
|
+
// English parser: it maps the length through a fixed table and asserts a
|
|
29
|
+
// literal. A length with no word in the table is a hard failure naming
|
|
30
|
+
// the missing word, so the gate is fail-closed on its own blind spot.
|
|
31
|
+
//
|
|
32
|
+
// The roster is read as SOURCE TEXT, so this runs in a fresh worktree with no
|
|
33
|
+
// install and no build. Precedent: readRiskClasses() in
|
|
34
|
+
// platform/scripts/lib/canonical-tool-names.mjs parses tool-surface.ts the
|
|
35
|
+
// same way.
|
|
36
|
+
//
|
|
37
|
+
// Ordering note: this gate runs BEFORE check-architecture-skill-no-drift.mjs in
|
|
38
|
+
// .husky/pre-commit. A wrong edit to the paragraph fails both, and the drift
|
|
39
|
+
// gate's message ("SKILL.md was out of sync") names the symptom rather than the
|
|
40
|
+
// cause. Under `set -e` the first failure is the one the author reads.
|
|
41
|
+
|
|
42
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
43
|
+
import { resolve, dirname, relative } from 'node:path';
|
|
44
|
+
import { fileURLToPath } from 'node:url';
|
|
45
|
+
|
|
46
|
+
const SELF = fileURLToPath(import.meta.url);
|
|
47
|
+
const MAXY_CODE_ROOT = resolve(dirname(SELF), '..', '..');
|
|
48
|
+
|
|
49
|
+
const ROSTER_TS = resolve(MAXY_CODE_ROOT, 'platform/lib/routine-templates/src/roster.ts');
|
|
50
|
+
const DOC = resolve(MAXY_CODE_ROOT, 'platform/plugins/docs/references/admin-ui.md');
|
|
51
|
+
|
|
52
|
+
const PARAGRAPH_MARKER = '**The shipped roster.**';
|
|
53
|
+
|
|
54
|
+
// Indexed by count. Extend when the roster outgrows it; a length past the end
|
|
55
|
+
// is a hard failure below rather than a silent pass.
|
|
56
|
+
const NUMBER_WORDS = [
|
|
57
|
+
'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
|
|
58
|
+
'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen',
|
|
59
|
+
'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty',
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// Assertion 2's scan only. Anchored inside backticks and requiring a hyphen, so
|
|
63
|
+
// `nextRun` (uppercase), `/routines` (slash) and `check-due-events.ts` (dot)
|
|
64
|
+
// are all excluded.
|
|
65
|
+
const KEY_SHAPE = /`([a-z0-9]+(?:-[a-z0-9]+)+)`/g;
|
|
66
|
+
|
|
67
|
+
const rel = (p) => relative(MAXY_CODE_ROOT, p);
|
|
68
|
+
|
|
69
|
+
for (const p of [ROSTER_TS, DOC]) {
|
|
70
|
+
if (!existsSync(p)) {
|
|
71
|
+
console.error(`[roster-doc] FAIL missing file: ${rel(p)}`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// The roster's key list, in roster order. The interface declaration
|
|
77
|
+
// (`readonly key: string;`) carries no quotes and does not match.
|
|
78
|
+
const rosterKeys = [...readFileSync(ROSTER_TS, 'utf8').matchAll(/^\s*key:\s*"([^"]+)",/gm)]
|
|
79
|
+
.map((m) => m[1]);
|
|
80
|
+
|
|
81
|
+
if (rosterKeys.length === 0) {
|
|
82
|
+
console.error(`[roster-doc] FAIL parsed zero keys from ${rel(ROSTER_TS)} — the entry shape changed`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const doc = readFileSync(DOC, 'utf8');
|
|
87
|
+
const start = doc.indexOf(PARAGRAPH_MARKER);
|
|
88
|
+
if (start === -1) {
|
|
89
|
+
console.error(`[roster-doc] FAIL ${rel(DOC)} has no paragraph starting "${PARAGRAPH_MARKER}"`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const end = doc.indexOf('\n\n', start);
|
|
93
|
+
const paragraph = end === -1 ? doc.slice(start) : doc.slice(start, end);
|
|
94
|
+
|
|
95
|
+
// 1 — every roster key present, by exact backticked substring.
|
|
96
|
+
const present = rosterKeys.filter((k) => paragraph.includes(`\`${k}\``));
|
|
97
|
+
const missing = rosterKeys.filter((k) => !paragraph.includes(`\`${k}\``));
|
|
98
|
+
|
|
99
|
+
// 2 — every key-shaped token present is a roster key.
|
|
100
|
+
const rosterKeySet = new Set(rosterKeys);
|
|
101
|
+
const shaped = new Set([...paragraph.matchAll(KEY_SHAPE)].map((m) => m[1]));
|
|
102
|
+
const stale = [...shaped].filter((k) => !rosterKeySet.has(k));
|
|
103
|
+
|
|
104
|
+
const problems = [];
|
|
105
|
+
if (missing.length) problems.push(` MISSING from the paragraph: ${missing.join(', ')}`);
|
|
106
|
+
if (stale.length) problems.push(` STALE in the paragraph (no such roster key): ${stale.join(', ')}`);
|
|
107
|
+
|
|
108
|
+
// 3 — the count word.
|
|
109
|
+
const expectedWord = NUMBER_WORDS[rosterKeys.length];
|
|
110
|
+
if (expectedWord === undefined) {
|
|
111
|
+
problems.push(
|
|
112
|
+
` no number word for ${rosterKeys.length} — add it to NUMBER_WORDS in ${rel(SELF)}`,
|
|
113
|
+
);
|
|
114
|
+
} else if (!paragraph.includes(`${expectedWord} routines`)) {
|
|
115
|
+
const found = NUMBER_WORDS.find((w) => paragraph.includes(`${w} routines`));
|
|
116
|
+
problems.push(
|
|
117
|
+
` count word: expected "${expectedWord} routines", found ${found ? `"${found} routines"` : 'no number word'}`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (problems.length) {
|
|
122
|
+
console.error(`[roster-doc] FAIL prose=${present.length} roster=${rosterKeys.length}`);
|
|
123
|
+
for (const l of problems) console.error(l);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
console.log(`[roster-doc] ok prose=${present.length} roster=${rosterKeys.length}`);
|
package/payload/server/server.js
CHANGED
|
@@ -13057,6 +13057,12 @@ app10.post("/", async (c) => {
|
|
|
13057
13057
|
});
|
|
13058
13058
|
var telegram_default = app10;
|
|
13059
13059
|
|
|
13060
|
+
// server/telegram-mount.ts
|
|
13061
|
+
function mountTelegramRoutes(app77, telegramRoutes) {
|
|
13062
|
+
app77.route("/api/telegram", telegramRoutes);
|
|
13063
|
+
app77.route("/api/telegram/", telegramRoutes);
|
|
13064
|
+
}
|
|
13065
|
+
|
|
13060
13066
|
// server/routes/quickbooks.ts
|
|
13061
13067
|
import { join as join30 } from "path";
|
|
13062
13068
|
import { existsSync as existsSync22, readFileSync as readFileSync24, writeFileSync as writeFileSync9, mkdirSync as mkdirSync4, rmSync as rmSync3, renameSync as renameSync5 } from "fs";
|
|
@@ -32861,7 +32867,7 @@ app76.route("/api/webchat", createWebchatRoutes({
|
|
|
32861
32867
|
resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
|
|
32862
32868
|
}));
|
|
32863
32869
|
app76.route("/api/webchat/greeting", webchat_greeting_default);
|
|
32864
|
-
app76
|
|
32870
|
+
mountTelegramRoutes(app76, telegram_default);
|
|
32865
32871
|
app76.route("/api/quickbooks", quickbooks_default);
|
|
32866
32872
|
app76.route("/api/onboarding", onboarding_default);
|
|
32867
32873
|
app76.route("/api/admin", admin_default);
|