@rubytech/create-maxy 1.0.450 → 1.0.451

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy",
3
- "version": "1.0.450",
3
+ "version": "1.0.451",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy": "./dist/index.js"
@@ -9398,8 +9398,9 @@ async function safeSaveCreds(authDir, saveCreds) {
9398
9398
  }
9399
9399
  try {
9400
9400
  await Promise.resolve(saveCreds());
9401
+ console.error(`${TAG2} creds saved successfully to ${authDir}`);
9401
9402
  } catch (err) {
9402
- console.error(`${TAG2} failed saving creds: ${String(err)}`);
9403
+ console.error(`${TAG2} failed saving creds to ${authDir}: ${String(err)}`);
9403
9404
  }
9404
9405
  }
9405
9406
  function enqueueSaveCreds(authDir, saveCreds) {
@@ -9413,44 +9414,63 @@ async function createWaSocket(opts) {
9413
9414
  maybeRestoreCredsFromBackup(authDir);
9414
9415
  const { state, saveCreds } = await useMultiFileAuthState(authDir);
9415
9416
  const { version: version2 } = await fetchLatestBaileysVersion();
9416
- const pinoStub = {
9417
- level: "silent",
9418
- child: () => pinoStub,
9419
- trace: () => {
9420
- },
9421
- debug: () => {
9422
- },
9423
- info: () => {
9424
- },
9425
- warn: () => {
9426
- },
9427
- error: () => {
9428
- },
9429
- fatal: () => {
9430
- }
9431
- };
9417
+ const BAILEYS_TAG = "[whatsapp:baileys]";
9418
+ function makeBaileysLogger() {
9419
+ const logger = {
9420
+ level: "warn",
9421
+ child: () => makeBaileysLogger(),
9422
+ trace: () => {
9423
+ },
9424
+ debug: () => {
9425
+ },
9426
+ info: () => {
9427
+ },
9428
+ warn: (...args) => console.error(BAILEYS_TAG, "WARN", ...args),
9429
+ error: (...args) => console.error(BAILEYS_TAG, "ERROR", ...args),
9430
+ fatal: (...args) => console.error(BAILEYS_TAG, "FATAL", ...args)
9431
+ };
9432
+ return logger;
9433
+ }
9434
+ const baileysLogger = makeBaileysLogger();
9432
9435
  const sock = makeWASocket({
9433
9436
  auth: {
9434
9437
  creds: state.creds,
9435
- keys: makeCacheableSignalKeyStore(state.keys, pinoStub)
9438
+ keys: makeCacheableSignalKeyStore(state.keys, baileysLogger)
9436
9439
  },
9437
9440
  version: version2,
9438
- logger: pinoStub,
9441
+ logger: baileysLogger,
9439
9442
  printQRInTerminal: false,
9440
9443
  browser: Browsers.macOS("Chrome"),
9441
9444
  syncFullHistory: false,
9442
9445
  markOnlineOnConnect: false
9443
9446
  });
9444
- sock.ev.on("creds.update", () => enqueueSaveCreds(authDir, saveCreds));
9447
+ sock.ev.on("creds.update", () => {
9448
+ console.error(`${TAG2} creds.update received \u2014 saving to ${authDir}`);
9449
+ enqueueSaveCreds(authDir, saveCreds);
9450
+ });
9451
+ let qrSequence = 0;
9445
9452
  sock.ev.on("connection.update", (update) => {
9446
9453
  try {
9454
+ const parts = [];
9455
+ if (update.connection) parts.push(`connection=${update.connection}`);
9456
+ if (update.qr) parts.push(`qr=#${++qrSequence}`);
9457
+ if (update.isNewLogin !== void 0) parts.push(`isNewLogin=${update.isNewLogin}`);
9458
+ if (update.receivedPendingNotifications !== void 0) parts.push(`pendingNotifications=${update.receivedPendingNotifications}`);
9459
+ if (update.connection === "close" && update.lastDisconnect) {
9460
+ const status = getStatusCode(update.lastDisconnect.error);
9461
+ parts.push(`disconnectStatus=${status ?? "unknown"}`);
9462
+ parts.push(`disconnectReason=${formatError(update.lastDisconnect.error)}`);
9463
+ }
9464
+ if (!silent && parts.length > 0) {
9465
+ console.error(`${TAG2} connection.update ${parts.join(" ")}`);
9466
+ }
9447
9467
  if (update.qr && onQr) {
9448
9468
  onQr(update.qr);
9449
9469
  }
9450
9470
  if (update.connection === "close") {
9451
9471
  const status = getStatusCode(update.lastDisconnect?.error);
9452
9472
  if (status === DisconnectReason.loggedOut && !silent) {
9453
- console.error(`${TAG2} session logged out \u2014 re-link required`);
9473
+ console.error(`${TAG2} session logged out (401) \u2014 re-link required`);
9454
9474
  }
9455
9475
  }
9456
9476
  if (update.connection === "open" && !silent) {
@@ -9580,16 +9600,21 @@ async function startLogin(opts) {
9580
9600
  );
9581
9601
  let sock;
9582
9602
  let pendingQr = null;
9603
+ let loginQrCount = 0;
9583
9604
  try {
9584
9605
  sock = await createWaSocket({
9585
9606
  authDir,
9586
9607
  onQr: (qr2) => {
9587
- if (pendingQr) return;
9608
+ loginQrCount++;
9609
+ if (pendingQr) {
9610
+ console.error(`${TAG3} QR rotation #${loginQrCount} received for account=${accountId} \u2014 not forwarded (initial QR already captured)`);
9611
+ return;
9612
+ }
9588
9613
  pendingQr = qr2;
9589
9614
  const current = activeLogins.get(accountId);
9590
9615
  if (current && !current.qr) current.qr = qr2;
9591
9616
  clearTimeout(qrTimer);
9592
- console.error(`${TAG3} QR received for account=${accountId}`);
9617
+ console.error(`${TAG3} QR #${loginQrCount} received for account=${accountId} \u2014 forwarding to caller`);
9593
9618
  resolveQr?.(qr2);
9594
9619
  }
9595
9620
  });
@@ -30,9 +30,13 @@ if [ ! -f "$DURABLE_STATE" ]; then
30
30
  fi
31
31
 
32
32
  # Staleness + completion check — reject durable state that is stale (>6h, missing
33
- # timestamp) OR already complete (all gates true). Without this, a stale or
34
- # completed durable file would be recovered on every new session, injecting a
35
- # misleading "resume creation" message.
33
+ # timestamp) OR already complete (all gates true AND all gated files exist on
34
+ # disk). Without this, a stale or completed durable file would be recovered on
35
+ # every new session, injecting a misleading "resume creation" message.
36
+ #
37
+ # "All gates true" alone is NOT completion — it means user approval is done but
38
+ # file writes may still be pending. Deleting state at that point causes the
39
+ # remaining writes to fail with "invoke the public-agent-manager skill first."
36
40
  DURABLE_VALID=$(python3 -c "
37
41
  import json, sys
38
42
  from datetime import datetime, timezone
@@ -49,10 +53,22 @@ try:
49
53
  if age_hours > 6 or age_hours < 0:
50
54
  print('stale')
51
55
  sys.exit(0)
52
- # All gates true means creation completed in a prior session don't recover
56
+ # All gates true AND all files on disk = truly complete. All gates true
57
+ # alone means the user approved everything but writes may still be pending.
58
+ # Must match the PostToolUse completion check in agent-creation-post.sh.
53
59
  gates = state.get('gates', {})
54
60
  if isinstance(gates, dict) and set(gates.keys()) == {'soul', 'knowledge', 'config'} and all(v is True for v in gates.values()):
55
- print('complete')
61
+ slug = state.get('slug', '')
62
+ if slug:
63
+ import os
64
+ agent_dir = os.path.join('$ACCOUNT_DIR', 'agents', slug)
65
+ gated_files = ['SOUL.md', 'KNOWLEDGE.md', 'config.json']
66
+ if all(os.path.isfile(os.path.join(agent_dir, f)) for f in gated_files):
67
+ print('complete')
68
+ else:
69
+ print('valid')
70
+ else:
71
+ print('valid')
56
72
  else:
57
73
  print('valid')
58
74
  except Exception:
@@ -13,7 +13,8 @@
13
13
  # - Allow Bash writes after gates pass
14
14
  # - Allow all gated writes when all gates pass
15
15
  # - Clean up state immediately when all files exist on disk (PostToolUse)
16
- # - Detect and clean up completed state on session start (all gates true)
16
+ # - Recover all-gates-true state on session start when files not yet written
17
+ # - Detect and clean up truly completed state on session start (all gates true + files on disk)
17
18
  # - Ignore non-document-editor/form components
18
19
  # - Ignore _componentDone for admin agent
19
20
  # - Handle gate advancement idempotently
@@ -721,10 +722,11 @@ fi
721
722
  rm -f "$STATE_FILE"
722
723
 
723
724
  # ---------------------------------------------------------------------------
724
- # Test 30: Session-start does NOT recover completed state (all gates true)
725
+ # Test 30: Session-start RECOVERS all-gates-true state when files are missing
725
726
  # ---------------------------------------------------------------------------
726
- echo "Test 30: Session-start does NOT recover completed state (all gates true)"
727
+ echo "Test 30: Session-start recovers all-gates-true state when files are missing"
727
728
  rm -f "$STATE_FILE"
729
+ rm -f "$ACCOUNT_DIR/agents/test-agent/SOUL.md" "$ACCOUNT_DIR/agents/test-agent/KNOWLEDGE.md" "$ACCOUNT_DIR/agents/test-agent/config.json" 2>/dev/null || true
728
730
  DURABLE_FILE="$ACCOUNT_DIR/.claude/agent-create-state.json"
729
731
 
730
732
  python3 -c "
@@ -741,16 +743,47 @@ with open('$DURABLE_FILE', 'w') as f:
741
743
 
742
744
  bash "$SCRIPT_DIR/session-start.sh" "$ACCOUNT_DIR" admin 2>/dev/null || true
743
745
 
744
- if [ ! -f "$STATE_FILE" ]; then
745
- if [ ! -f "$DURABLE_FILE" ]; then
746
- pass "Completed state (all gates true) not recovered, both files deleted"
747
- else
748
- fail "Completed state not recovered but durable file not deleted"
749
- fi
746
+ if [ -f "$STATE_FILE" ] && [ -f "$DURABLE_FILE" ]; then
747
+ pass "All-gates-true state recovered (files not yet written — writes still pending)"
748
+ else
749
+ fail "All-gates-true state should be recovered when gated files are missing from disk"
750
+ fi
751
+
752
+ rm -f "$STATE_FILE"
753
+
754
+ # ---------------------------------------------------------------------------
755
+ # Test 30a: Session-start does NOT recover truly completed state (all gates true + all files on disk)
756
+ # ---------------------------------------------------------------------------
757
+ echo "Test 30a: Session-start does NOT recover truly completed state"
758
+
759
+ # Create all gated files on disk
760
+ touch "$ACCOUNT_DIR/agents/test-agent/SOUL.md"
761
+ touch "$ACCOUNT_DIR/agents/test-agent/KNOWLEDGE.md"
762
+ touch "$ACCOUNT_DIR/agents/test-agent/config.json"
763
+
764
+ python3 -c "
765
+ import json
766
+ from datetime import datetime, timezone
767
+ state = {
768
+ 'slug': 'test-agent',
769
+ 'started': datetime.now(timezone.utc).isoformat(),
770
+ 'gates': {'soul': True, 'knowledge': True, 'config': True}
771
+ }
772
+ with open('$DURABLE_FILE', 'w') as f:
773
+ json.dump(state, f)
774
+ "
775
+
776
+ bash "$SCRIPT_DIR/session-start.sh" "$ACCOUNT_DIR" admin 2>/dev/null || true
777
+
778
+ if [ ! -f "$STATE_FILE" ] && [ ! -f "$DURABLE_FILE" ]; then
779
+ pass "Truly completed state (all gates true + all files on disk) deleted"
750
780
  else
751
- fail "Completed state (all gates true) should NOT be recovered to volatile"
781
+ fail "Truly completed state should be deleted both gates passed and files written"
752
782
  fi
753
783
 
784
+ # Clean up gated files for subsequent tests
785
+ rm -f "$ACCOUNT_DIR/agents/test-agent/SOUL.md" "$ACCOUNT_DIR/agents/test-agent/KNOWLEDGE.md" "$ACCOUNT_DIR/agents/test-agent/config.json"
786
+
754
787
  # ---------------------------------------------------------------------------
755
788
  # Test 31: PostToolUse cleans up state after last gated file is written
756
789
  # ---------------------------------------------------------------------------
@@ -94,7 +94,7 @@ SOUL.md is strictly personality. When the user provides content for SOUL.md, rou
94
94
  - **Engagement strategy, qualification flows, component usage** → handled by selected plugins
95
95
  - **Boundaries, tool rules, procedural instructions** → IDENTITY.md
96
96
 
97
- SOUL.md answers "what does this agent feel like to talk to?" — tone, warmth, formality, humour, greeting personality. SOUL.md must not restate constraints from IDENTITY.md. When user-provided content could belong to either file, apply this test: "does this restrict what the agent does?" → IDENTITY.md. "Does this describe how the agent sounds?" → SOUL.md. If content does both (e.g. "always respond politely"), route to SOUL — the constraint is a consequence of tone, not an operational boundary. Present SOUL.md via `document-editor` for the user to review and approve. Content must use ASCII-safe characters only hyphens not em dashes, straight quotes not curly quotes (see contextual-ui for the full encoding constraint).
97
+ SOUL.md answers "what does this agent feel like to talk to?" — tone, warmth, formality, humour, greeting personality. SOUL.md must not restate constraints from IDENTITY.md. When user-provided content could belong to either file, apply this test: "does this restrict what the agent does?" → IDENTITY.md. "Does this describe how the agent sounds?" → SOUL.md. If content does both (e.g. "always respond politely"), route to SOUL — the constraint is a consequence of tone, not an operational boundary. Present SOUL.md via `document-editor` for the user to review and approve. Follow the document-editor encoding constraint in IDENTITY.md when generating content.
98
98
 
99
99
  ## KNOWLEDGE.md Population
100
100
 
@@ -127,6 +127,8 @@ The user can also launch the browser independently from the header menu. Both pa
127
127
 
128
128
  When the user asks to view, review, attach, or download a file or document, render it via `render-component` with `name: "document-editor"` and `data: { title, content }`. This gives a render-review-edit-download flow — the user sees the content inline, can edit it, and can download it as a `.md` file directly from the component. Do not use `memory-write`, `memory-ingest`, or other tools to deliver file content to the user. Synthesised content (summaries, reports, drafts) follows the same path — render via `document-editor` so the user can review and download.
129
129
 
130
+ The document-editor's markdown parser fails silently on these specific typographical characters: em dashes (U+2014), en dashes (U+2013), curly double quotes (U+201C, U+201D), curly single quotes (U+2018, U+2019), and horizontal ellipsis (U+2026). Replace them with their plain equivalents — hyphens, straight quotes, three periods. Currency symbols (£, €), accented characters, and other Unicode are unaffected — use them normally.
131
+
130
132
  ## Plugins and Skills
131
133
 
132
134
  Your behaviour is defined by your loaded plugins. Follow them. The `<plugin-manifest>` lists every active plugin's skills and references with their file paths. To load any skill or reference, call `plugin-read` with the plugin's directory name and the file path from the manifest. The manifest is authoritative for plugin discovery and skill loading.
@@ -1,21 +1,3 @@
1
1
  # Learnings
2
2
 
3
3
  Accumulated tool-call patterns. Each entry records a mistake and the correct approach. Consult before calling unfamiliar tools.
4
-
5
- ---
6
-
7
- ### Deferred tool schemas must be loaded before use
8
-
9
- MCP tools have deferred schemas — parameter names, types, and required fields are not in context until fetched. Calling an MCP tool without loading its schema produces wrong parameter names, wrong types, and missing required fields. Always call `ToolSearch` for a tool before its first use in a session. This applies to every `mcp__*` tool — memory, tasks, scheduling, contacts, admin, cloudflare, telegram, documents.
10
-
11
- ### memory-update requires Neo4j element IDs
12
-
13
- The `memory-update` tool identifies nodes by their Neo4j element ID — an integer returned in `memory-search` results (the `elementId` field). Do not pass UUIDs, attachment IDs, or string identifiers. If you do not have the element ID, run `memory-search` first to retrieve it.
14
-
15
- ### memory-ingest complex parameters must be arrays
16
-
17
- The `memory-ingest` tool's `sections` and `keywords` parameters are arrays, not strings. `sections` is an array of objects; `keywords` is an array of strings. Passing a string where an array is expected produces a schema validation error. Load the tool schema via `ToolSearch` to confirm the expected types before calling.
18
-
19
- ### document-editor content must be ASCII-safe
20
-
21
- The `document-editor` markdown parser silently fails on Unicode typographical characters — em dashes (—), en dashes (–), curly quotes (" " ' '), and ellipsis (…). When these appear in the `content` field, the editor renders empty and the user sees a blank document. Use ASCII alternatives: hyphens (-), straight quotes (" '), and three periods (...). This applies to all `document-editor` content including SOUL.md, KNOWLEDGE.md, and any other document presented for review.