@rubytech/create-maxy 1.0.885 → 1.0.886

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.885",
3
+ "version": "1.0.886",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy": "./dist/index.js"
@@ -498,9 +498,16 @@ OPTIONS {
498
498
  CREATE CONSTRAINT message_id_unique IF NOT EXISTS
499
499
  FOR (m:Message) REQUIRE m.messageId IS UNIQUE;
500
500
 
501
+ // Task 1007 — Message.sessionKey is the canonical conversation pointer.
502
+ // The legacy m.conversationId index stays until follow-up Task 1011 (final
503
+ // cutover, after the full code-rename slice lands and no path reads
504
+ // m.conversationId).
501
505
  CREATE INDEX message_conversation IF NOT EXISTS
502
506
  FOR (m:Message) ON (m.conversationId);
503
507
 
508
+ CREATE INDEX message_session_key IF NOT EXISTS
509
+ FOR (m:Message) ON (m.sessionKey);
510
+
504
511
  CREATE VECTOR INDEX message_embedding IF NOT EXISTS
505
512
  FOR (m:Message) ON (m.embedding)
506
513
  OPTIONS {
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ // Task 1007 build-time gate: prevents NEW files from gaining a `conversationId` /
3
+ // `sessionId` reference while the 146-file rename slice is in progress.
4
+ //
5
+ // The legacy identifiers are being collapsed into the single canonical
6
+ // `sessionKey`. This sprint shipped the schema-side load-bearing pieces
7
+ // (backfill, new index, boot-time adherence probe) plus the core lib rename.
8
+ // The mechanical tail (routes, MCP plugin parameters, UI props, WhatsApp,
9
+ // tests, specialist templates) is split across follow-up tasks 1009 and 1010.
10
+ //
11
+ // During the transition window, every file currently containing the legacy
12
+ // identifiers is named in `conversation-id-allowlist.txt`. Each follow-up
13
+ // rename PR removes file paths from the allowlist as those files are migrated.
14
+ // This gate fails if:
15
+ // (a) a file NOT in the allowlist contains any of the four legacy tokens, or
16
+ // (b) the allowlist references a path that no longer exists (stale entry).
17
+ //
18
+ // Once tasks 1009 and 1010 land, the allowlist is empty; the gate then enforces
19
+ // the task's outcome contract (zero hits anywhere outside .tasks/archive/).
20
+
21
+ import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs'
22
+ import { dirname, join, relative, basename } from 'node:path'
23
+ import { fileURLToPath } from 'node:url'
24
+
25
+ const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url))
26
+ const REPO_ROOT = join(SCRIPT_DIR, '..', '..')
27
+ const ALLOWLIST_PATH = join(SCRIPT_DIR, 'conversation-id-allowlist.txt')
28
+
29
+ const SCAN_ROOTS = [
30
+ join(REPO_ROOT, 'platform'),
31
+ join(REPO_ROOT, 'packages'),
32
+ join(REPO_ROOT, 'brands'),
33
+ join(REPO_ROOT, '.docs'),
34
+ join(REPO_ROOT, '.claude', 'skills'),
35
+ ]
36
+
37
+ const ALLOWED_EXTS = new Set([
38
+ '.sh', '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
39
+ '.md', '.cypher', '.json',
40
+ ])
41
+ const SKIP_DIR_NAMES = new Set([
42
+ 'node_modules', 'dist', 'build', '.next', 'payload',
43
+ ])
44
+ const SKIP_PATH_FRAGMENTS = ['.tasks/archive/']
45
+
46
+ // Whole-word matches only — avoids hits inside longer identifiers like
47
+ // `agentSessionId` (Claude Agent SDK per-process session, intentionally kept)
48
+ // and `conversationIdentity` (ConversationArchive hash key, unrelated).
49
+ const LEGACY_TOKEN_RE = /\b(?:conversationId|sessionId|CONVERSATION_ID|SESSION_ID)\b/
50
+
51
+ // Comment-line skip — matches the convention in check-no-task-id-leaks.mjs.
52
+ // Comments that *describe* the legacy field (inside the migration code itself,
53
+ // or inline docstrings explaining the rename) are not new executing code
54
+ // introducing the token, so they don't trip the gate.
55
+ function isCommentLine(line) {
56
+ const trimmed = line.replace(/^\s+/, '')
57
+ if (trimmed.startsWith('#')) return true
58
+ if (trimmed.startsWith('//')) return true
59
+ if (trimmed.startsWith('/*')) return true
60
+ if (trimmed.startsWith('*')) return true
61
+ if (trimmed.startsWith('{/*')) return true
62
+ return false
63
+ }
64
+
65
+ function loadAllowlist() {
66
+ if (!existsSync(ALLOWLIST_PATH)) return new Set()
67
+ const text = readFileSync(ALLOWLIST_PATH, 'utf-8')
68
+ return new Set(
69
+ text.split('\n')
70
+ .map(l => l.trim())
71
+ .filter(l => l && !l.startsWith('#'))
72
+ )
73
+ }
74
+
75
+ function shouldScanFile(filePath) {
76
+ const name = basename(filePath)
77
+ const ext = name.includes('.') ? '.' + name.split('.').pop() : ''
78
+ if (!ALLOWED_EXTS.has(ext)) return false
79
+ const rel = relative(REPO_ROOT, filePath)
80
+ for (const frag of SKIP_PATH_FRAGMENTS) {
81
+ if (rel.includes(frag)) return false
82
+ }
83
+ return true
84
+ }
85
+
86
+ function* walk(root) {
87
+ let entries
88
+ try { entries = readdirSync(root) } catch { return }
89
+ for (const name of entries) {
90
+ if (SKIP_DIR_NAMES.has(name)) continue
91
+ const full = join(root, name)
92
+ let st
93
+ try { st = statSync(full) } catch { continue }
94
+ if (st.isDirectory()) {
95
+ yield* walk(full)
96
+ } else if (st.isFile()) {
97
+ yield full
98
+ }
99
+ }
100
+ }
101
+
102
+ const allowlist = loadAllowlist()
103
+ const newLeaks = []
104
+ const hitFiles = new Set()
105
+
106
+ for (const root of SCAN_ROOTS) {
107
+ if (!existsSync(root)) continue
108
+ for (const file of walk(root)) {
109
+ if (!shouldScanFile(file)) continue
110
+ let content
111
+ try { content = readFileSync(file, 'utf-8') } catch { continue }
112
+ if (!LEGACY_TOKEN_RE.test(content)) continue
113
+ const rel = relative(REPO_ROOT, file)
114
+ const lines = content.split('\n')
115
+ // For non-allowlisted files: only flag hits in non-comment lines. For
116
+ // allowlisted files: any hit counts (so the allowlist accurately tracks
117
+ // the surface still using the legacy name, comments and code alike).
118
+ if (allowlist.has(rel)) {
119
+ hitFiles.add(rel)
120
+ continue
121
+ }
122
+ let firstLine = 0, firstText = ''
123
+ for (let i = 0; i < lines.length; i++) {
124
+ if (!LEGACY_TOKEN_RE.test(lines[i])) continue
125
+ if (isCommentLine(lines[i])) continue
126
+ firstLine = i + 1
127
+ firstText = lines[i].trim().slice(0, 120)
128
+ break
129
+ }
130
+ if (firstLine > 0) {
131
+ newLeaks.push({ file: rel, line: firstLine, content: firstText })
132
+ }
133
+ }
134
+ }
135
+
136
+ // Stale allowlist entries: files in the allowlist that no longer have a hit
137
+ // (renamed already, or no longer exist) — remove them.
138
+ const staleAllowlistEntries = [...allowlist].filter(p => !hitFiles.has(p))
139
+
140
+ let failed = false
141
+
142
+ if (newLeaks.length > 0) {
143
+ failed = true
144
+ console.error(`check-no-conversation-id-leaks: ${newLeaks.length} NEW file(s) introduced legacy identifier(s):`)
145
+ for (const leak of newLeaks) {
146
+ console.error(` ${leak.file}:${leak.line}: ${leak.content}`)
147
+ }
148
+ console.error('')
149
+ console.error('The single canonical identifier is `sessionKey`. New code must use it.')
150
+ console.error('Legacy tokens: conversationId, sessionId, CONVERSATION_ID, SESSION_ID.')
151
+ console.error('Follow-up tasks 1009 + 1010 are migrating existing files off the allowlist.')
152
+ }
153
+
154
+ if (staleAllowlistEntries.length > 0) {
155
+ failed = true
156
+ console.error('')
157
+ console.error(`check-no-conversation-id-leaks: ${staleAllowlistEntries.length} stale allowlist entry(ies) — remove from platform/scripts/conversation-id-allowlist.txt:`)
158
+ for (const entry of staleAllowlistEntries) {
159
+ console.error(` ${entry}`)
160
+ }
161
+ }
162
+
163
+ if (failed) process.exit(1)
164
+
165
+ console.error(`check-no-conversation-id-leaks: ok (${allowlist.size} files in transition allowlist; 0 new leaks)`)
@@ -0,0 +1,151 @@
1
+ .docs/agents.md
2
+ .docs/conversation-archive.md
3
+ .docs/deployment.md
4
+ .docs/mcp-servers.md
5
+ .docs/neo4j.md
6
+ .docs/observability.md
7
+ .docs/platform.md
8
+ .docs/web-chat.md
9
+ .docs/whatsapp.md
10
+ platform/lib/graph-mcp/src/index.ts
11
+ platform/lib/graph-trash/src/index.ts
12
+ platform/lib/graph-write/src/__tests__/audit.test.ts
13
+ platform/lib/graph-write/src/audit.ts
14
+ platform/neo4j/schema.cypher
15
+ platform/plugins/admin/PLUGIN.md
16
+ platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh
17
+ platform/plugins/admin/mcp/src/index.ts
18
+ platform/plugins/admin/skills/onboarding/SKILL.md
19
+ platform/plugins/admin/skills/stream-log-review/SKILL.md
20
+ platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md
21
+ platform/plugins/business-assistant/references/profiling.md
22
+ platform/plugins/contacts/mcp/src/index.ts
23
+ platform/plugins/contacts/mcp/src/tools/contact-erase.ts
24
+ platform/plugins/contacts/mcp/src/tools/contact-export.ts
25
+ platform/plugins/contacts/mcp/src/tools/group-create.ts
26
+ platform/plugins/contacts/mcp/src/tools/group-manage.ts
27
+ platform/plugins/docs/references/admin-session.md
28
+ platform/plugins/docs/references/contacts-guide.md
29
+ platform/plugins/docs/references/internals.md
30
+ platform/plugins/docs/references/platform.md
31
+ platform/plugins/docs/references/plugins-guide.md
32
+ platform/plugins/docs/references/troubleshooting.md
33
+ platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md
34
+ platform/plugins/linkedin-import/skills/linkedin-import/references/connections.md
35
+ platform/plugins/memory/bin/conversation-archive-ingest.mjs
36
+ platform/plugins/memory/bin/conversation-archive-ingest.sh
37
+ platform/plugins/memory/mcp/scripts/boot-smoke.sh
38
+ platform/plugins/memory/mcp/scripts/graph/fixture.cypher
39
+ platform/plugins/memory/mcp/src/index.ts
40
+ platform/plugins/memory/mcp/src/lib/graph-prune.ts
41
+ platform/plugins/memory/mcp/src/tools/conversation-archive-derive-insights.ts
42
+ platform/plugins/memory/mcp/src/tools/conversation-archive-enrich-rejection.ts
43
+ platform/plugins/memory/mcp/src/tools/conversation-memory-expunge.ts
44
+ platform/plugins/memory/mcp/src/tools/memory-archive-write.ts
45
+ platform/plugins/memory/mcp/src/tools/memory-find-candidates.ts
46
+ platform/plugins/memory/mcp/src/tools/memory-ingest.ts
47
+ platform/plugins/memory/mcp/src/tools/profile-update.ts
48
+ platform/plugins/memory/references/graph-primitives.md
49
+ platform/plugins/memory/references/schema-base.md
50
+ platform/plugins/memory/skills/conversation-archive/SKILL.md
51
+ platform/plugins/memory/skills/conversational-memory/SKILL.md
52
+ platform/plugins/memory/skills/document-ingest/SKILL.md
53
+ platform/plugins/scheduling/mcp/src/index.ts
54
+ platform/plugins/tasks/.mcp.json
55
+ platform/plugins/tasks/mcp/src/index.ts
56
+ platform/plugins/tasks/mcp/src/tools/project-create.ts
57
+ platform/plugins/tasks/mcp/src/tools/session-list.ts
58
+ platform/plugins/waitlist/mcp/src/index.ts
59
+ platform/plugins/waitlist/mcp/src/tools/__tests__/waitlist-persist.test.ts
60
+ platform/plugins/waitlist/mcp/src/tools/waitlist-heal.ts
61
+ platform/plugins/waitlist/mcp/src/tools/waitlist-list.ts
62
+ platform/plugins/waitlist/mcp/src/tools/waitlist-persist.ts
63
+ platform/plugins/waitlist/mcp/src/tools/waitlist-scan.ts
64
+ platform/plugins/waitlist/mcp/src/tools/waitlist-setup.ts
65
+ platform/plugins/whatsapp/PLUGIN.md
66
+ platform/plugins/whatsapp/mcp/src/index.ts
67
+ platform/plugins/workflows/mcp/src/index.ts
68
+ platform/scripts/__tests__/admin-persist-audit.test.ts
69
+ platform/scripts/admin-conversation-recover.mjs
70
+ platform/scripts/admin-persist-audit.ts
71
+ platform/scripts/check-no-conversation-id-leaks.mjs
72
+ platform/scripts/check-sdk-oauth.mjs
73
+ platform/scripts/component-knowledgedoc-backfill.ts
74
+ platform/scripts/seed-neo4j.sh
75
+ platform/templates/agents/admin/IDENTITY.md
76
+ platform/templates/specialists/agents/database-operator.md
77
+ platform/ui/__tests__/form-spawn-tailer.test.ts
78
+ platform/ui/app/AdminModals.tsx
79
+ platform/ui/app/ChatActionsMenu.tsx
80
+ platform/ui/app/ChatFooter.tsx
81
+ platform/ui/app/ConversationRowActions.tsx
82
+ platform/ui/app/Sidebar.tsx
83
+ platform/ui/app/__tests__/buildSessionLogsUrl.test.ts
84
+ platform/ui/app/admin/components/CloudflareSetupForm.tsx
85
+ platform/ui/app/graph/__tests__/display-helpers.test.ts
86
+ platform/ui/app/graph/__tests__/zoom-tier-colour-stability.test.ts
87
+ platform/ui/app/graph/display-helpers.ts
88
+ platform/ui/app/lib/__tests__/admin-conversation-create.test.ts
89
+ platform/ui/app/lib/__tests__/admin-persist-observability.test.ts
90
+ platform/ui/app/lib/__tests__/claude-agent-loop-stop.test.ts
91
+ platform/ui/app/lib/__tests__/conversation-deferred-persistence.test.ts
92
+ platform/ui/app/lib/__tests__/ensure-conversation-handled-by.test.ts
93
+ platform/ui/app/lib/__tests__/graph-trash-conversation-cascade.test.ts
94
+ platform/ui/app/lib/__tests__/jsonl-replay.test.ts
95
+ platform/ui/app/lib/__tests__/load-user-profile-sparse.test.ts
96
+ platform/ui/app/lib/__tests__/neo4j-store-autolabel.test.ts
97
+ platform/ui/app/lib/__tests__/neo4j-store-persist-message.test.ts
98
+ platform/ui/app/lib/admin-sse-registry.ts
99
+ platform/ui/app/lib/attachments.ts
100
+ platform/ui/app/lib/claude-agent/admin-agent.ts
101
+ platform/ui/app/lib/claude-agent/compaction.ts
102
+ platform/ui/app/lib/claude-agent/dispatcher.ts
103
+ platform/ui/app/lib/claude-agent/jsonl-replay.ts
104
+ platform/ui/app/lib/claude-agent/logging.ts
105
+ platform/ui/app/lib/claude-agent/memory-context.ts
106
+ platform/ui/app/lib/claude-agent/public-agent.ts
107
+ platform/ui/app/lib/claude-agent/session-store.ts
108
+ platform/ui/app/lib/claude-agent/spawn-env.ts
109
+ platform/ui/app/lib/claude-agent/stream-parser.ts
110
+ platform/ui/app/lib/client-event.ts
111
+ platform/ui/app/lib/cloudflare-setup-types.ts
112
+ platform/ui/app/lib/cloudflare-task-tracker.ts
113
+ platform/ui/app/lib/logs-read-resolve.ts
114
+ platform/ui/app/lib/neo4j-store.ts
115
+ platform/ui/app/lib/paths.ts
116
+ platform/ui/app/lib/useConversationRename.ts
117
+ platform/ui/app/lib/useLogsPopover.ts
118
+ platform/ui/app/lib/vnc.ts
119
+ platform/ui/app/lib/whatsapp/__tests__/ensure-conversation.test.ts
120
+ platform/ui/app/lib/whatsapp/__tests__/persist-message.test.ts
121
+ platform/ui/app/lib/whatsapp/ensure-conversation.ts
122
+ platform/ui/app/lib/whatsapp/manager.ts
123
+ platform/ui/app/lib/whatsapp/persist-message.ts
124
+ platform/ui/app/page.tsx
125
+ platform/ui/app/public/MessageList.tsx
126
+ platform/ui/app/public/page.tsx
127
+ platform/ui/app/public/types.ts
128
+ platform/ui/app/public/useSession.ts
129
+ platform/ui/app/useAdminAuth.ts
130
+ platform/ui/app/useAdminChat.ts
131
+ platform/ui/server/index.ts
132
+ platform/ui/server/routes/__tests__/whatsapp-conversation-graph-state.test.ts
133
+ platform/ui/server/routes/_helpers.ts
134
+ platform/ui/server/routes/admin/__tests__/browser-iframe-route.test.ts
135
+ platform/ui/server/routes/admin/__tests__/chat-stream-log-path.test.ts
136
+ platform/ui/server/routes/admin/__tests__/cloudflare-tunnels-zero.test.ts
137
+ platform/ui/server/routes/admin/__tests__/graph-search.test.ts
138
+ platform/ui/server/routes/admin/__tests__/graph-subgraph.test.ts
139
+ platform/ui/server/routes/admin/__tests__/logs.test.ts
140
+ platform/ui/server/routes/admin/__tests__/sessions.test.ts
141
+ platform/ui/server/routes/admin/browser-iframe.ts
142
+ platform/ui/server/routes/admin/chat-failure.ts
143
+ platform/ui/server/routes/admin/chat.ts
144
+ platform/ui/server/routes/admin/cloudflare.ts
145
+ platform/ui/server/routes/admin/graph-subgraph.ts
146
+ platform/ui/server/routes/admin/logs.ts
147
+ platform/ui/server/routes/admin/session.ts
148
+ platform/ui/server/routes/admin/sessions.ts
149
+ platform/ui/server/routes/group.ts
150
+ platform/ui/server/routes/session.ts
151
+ platform/ui/server/routes/whatsapp.ts
@@ -490,6 +490,52 @@ fi
490
490
 
491
491
  echo "$SCHEMA_CYPHER" | "$CYPHER_SHELL" -u "$NEO4J_USER" -p "$NEO4J_PASSWORD" -a "$NEO4J_URI"
492
492
 
493
+ # ------------------------------------------------------------------
494
+ # Task 1007 — sessionKey backfill (idempotent, runs every seed pass).
495
+ #
496
+ # Conversation and Message rows minted before Task 985 carry only
497
+ # `conversationId`. The new canonical identifier is `sessionKey` (same
498
+ # UUID shape). This block copies conversationId → sessionKey on every
499
+ # row where sessionKey is still null, leaving rows that already carry
500
+ # sessionKey untouched. Re-runs are no-ops. The legacy
501
+ # `conversation_id_unique` constraint and `m.conversationId` index
502
+ # stay until the full code-rename slice lands and no path reads the
503
+ # legacy field; the drop happens in Task 1007's open completion scope.
504
+ # ------------------------------------------------------------------
505
+ echo "==> Backfilling sessionKey on :Conversation and :Message..."
506
+ BACKFILL_RESULT=$("$CYPHER_SHELL" -u "$NEO4J_USER" -p "$NEO4J_PASSWORD" -a "$NEO4J_URI" --format plain << 'BACKFILL_EOF'
507
+ MATCH (c:Conversation)
508
+ WHERE c.sessionKey IS NULL AND c.conversationId IS NOT NULL
509
+ SET c.sessionKey = c.conversationId
510
+ RETURN count(c) AS conversations_backfilled;
511
+ MATCH (m:Message)
512
+ WHERE m.sessionKey IS NULL AND m.conversationId IS NOT NULL
513
+ SET m.sessionKey = m.conversationId
514
+ RETURN count(m) AS messages_backfilled;
515
+ MATCH (c:Conversation) WHERE c.sessionKey IS NULL RETURN count(c) AS conversations_null_after;
516
+ MATCH (m:Message) WHERE m.sessionKey IS NULL RETURN count(m) AS messages_null_after;
517
+ BACKFILL_EOF
518
+ )
519
+ # Emit the migration-1007 adherence lines on stderr so they land in server.log
520
+ # the same as every other log line. Non-zero null counts after backfill are P0:
521
+ # they indicate orphan rows that carry neither identifier and need operator
522
+ # attention before the constraint flip in Task 1011.
523
+ echo "$BACKFILL_RESULT" | python3 -c "
524
+ import sys, re
525
+ rows = [r.strip() for r in sys.stdin.read().splitlines() if r.strip() and not r.strip().startswith(('conversations_', 'messages_'))]
526
+ nums = [int(r) for r in rows if re.fullmatch(r'\d+', r)]
527
+ if len(nums) >= 4:
528
+ conv_bf, msg_bf, conv_null, msg_null = nums[0], nums[1], nums[2], nums[3]
529
+ print(f'[migration-1007] conversation-row-backfill rows={conv_bf} outcome=ok', file=sys.stderr)
530
+ print(f'[migration-1007] message-row-backfill rows={msg_bf} outcome=ok', file=sys.stderr)
531
+ print(f'[migration-1007] adherence-check label=Conversation rows-with-null-sessionkey={conv_null}', file=sys.stderr)
532
+ print(f'[migration-1007] adherence-check label=Message rows-with-null-sessionkey={msg_null}', file=sys.stderr)
533
+ if conv_null > 0 or msg_null > 0:
534
+ print(f'[migration-1007] adherence-check P0=true reason=null-sessionkey-after-backfill', file=sys.stderr)
535
+ else:
536
+ print(f'[migration-1007] backfill output unparseable rows={len(nums)}', file=sys.stderr)
537
+ "
538
+
493
539
  # ------------------------------------------------------------------
494
540
  # 3. Create AdminUser node + ADMIN_OF relationship
495
541
  # ------------------------------------------------------------------