@genn-inc/cluebase-cli 0.0.1

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.
Files changed (38) hide show
  1. package/README.md +101 -0
  2. package/bin/cluebase-cli.mjs +11 -0
  3. package/package.json +17 -0
  4. package/src/cli-command.mjs +515 -0
  5. package/src/cli-invocation.mjs +17 -0
  6. package/src/code-evidence-analyzer.mjs +2041 -0
  7. package/src/contracts.mjs +36 -0
  8. package/src/generated-code-evidence-contract.mjs +22 -0
  9. package/src/generated-sdk-version-contract.mjs +5 -0
  10. package/src/generated-source-path-policy.mjs +20 -0
  11. package/src/lifecycle-guard.mjs +202 -0
  12. package/src/path-policy.mjs +81 -0
  13. package/src/setup-ai-contract.mjs +221 -0
  14. package/src/setup-check-constants.mjs +110 -0
  15. package/src/setup-check-scan-a.mjs +849 -0
  16. package/src/setup-check-scan-b.mjs +994 -0
  17. package/src/setup-check.mjs +575 -0
  18. package/src/setup-discover-check.mjs +755 -0
  19. package/src/setup-doctor-deadline.mjs +221 -0
  20. package/src/setup-doctor-env.mjs +331 -0
  21. package/src/setup-doctor-file-boundary.mjs +426 -0
  22. package/src/setup-doctor-probe.mjs +719 -0
  23. package/src/setup-doctor-quality-checks-a.mjs +593 -0
  24. package/src/setup-doctor-quality-checks-b.mjs +638 -0
  25. package/src/setup-doctor-quality-shared.mjs +382 -0
  26. package/src/setup-doctor-quality.mjs +209 -0
  27. package/src/setup-doctor-route-scan.mjs +160 -0
  28. package/src/setup-doctor-sdk-probe.mjs +340 -0
  29. package/src/setup-doctor.mjs +545 -0
  30. package/src/setup-documents.mjs +112 -0
  31. package/src/setup-help.mjs +130 -0
  32. package/src/setup-prepare.mjs +360 -0
  33. package/src/setup-repository-discovery.mjs +764 -0
  34. package/src/setup-step-builders-discover.mjs +701 -0
  35. package/src/setup-step-builders-events.mjs +229 -0
  36. package/src/setup-step-builders-implement.mjs +710 -0
  37. package/src/setup-step-commands.mjs +427 -0
  38. package/src/setup-tool.mjs +27 -0
@@ -0,0 +1,229 @@
1
+ import { CLUEBASE_CLI_RECOMMENDED_PREFIX as CLUEBASE_CLI_INVOCATION } from "./cli-invocation.mjs";
2
+ import {
3
+ EXTERNAL_DATA_CONNECTION_PATH,
4
+ EXTERNAL_DATA_CONNECTION_SCREEN_NAME,
5
+ } from "./setup-documents.mjs";
6
+
7
+ // STEP 8 builder — guided business value event instrumentation (cluebase.track).
8
+ //
9
+ // The lifecycle STEPs (1-7) wire cluebase.init / identify / group / reset and rely
10
+ // on autocapture for generic UI signals (click / page view / form submit).
11
+ // Autocapture cannot observe business VALUE milestones that are decided
12
+ // server-side or as semantic outcomes (a paid conversion, a cancellation, a
13
+ // plan change). This STEP lets the customer pick which value milestones matter
14
+ // and guides the AI coding tool to instrument cluebase.track at the authoritative
15
+ // site, verify arrival, and record the mapping — WITHOUT baking any single
16
+ // business problem (churn, activation, upsell, …) into code.
17
+ //
18
+ // Doctrine framing: a cluebase.track event here is a value_achievement / high-value
19
+ // observation, not generic event analytics. The instrumented event name is the
20
+ // meaning signal the backend semantic layer maps to customer value; the
21
+ // customer-specific "which code path == which milestone" mapping is recorded as
22
+ // tenant meaning in `.cluebase/business-events.json`, never as per-category
23
+ // branching in this SDK/CLI.
24
+ //
25
+ // GENERALIZATION CONTRACT (enforced by setup-value-events.test.mjs):
26
+ // - VALUE_EVENT_CATEGORIES is a flat, data-driven list of generic value
27
+ // milestones. No entry names a specific business problem.
28
+ // - The builder renders every category through the SAME template. It must
29
+ // never branch on a category id. The rendered prompt must work for an
30
+ // arbitrary customer-defined event (the "custom" path), proving the flow
31
+ // is not churn-specific.
32
+
33
+ // Generic customer-value milestones offered for selection. Each entry is pure
34
+ // data: `id` is the stable, framework-agnostic cluebase.track event name; `label`
35
+ // is the Japanese selection label; `semantic` describes the milestone by MEANING
36
+ // so the AI locates it by concept (not by a fixed code literal); `valueSignal`
37
+ // ties it to the canonical Cluebase concept it feeds; `surfaceHint` is a
38
+ // non-binding hint about where the authoritative site usually lives.
39
+ export const VALUE_EVENT_CATEGORIES = [
40
+ {
41
+ id: "subscription_started",
42
+ label: "課金・サブスク開始(無料→有料転換)",
43
+ semantic:
44
+ "The moment a customer's paid subscription / billing relationship becomes active for the first time — the authoritative confirmation of a paid conversion. Usually decided by the payment provider callback / billing service, not by a button click.",
45
+ valueSignal: "value_achievement",
46
+ surfaceHint: "backend",
47
+ },
48
+ {
49
+ id: "subscription_canceled",
50
+ label: "解約・サブスク停止",
51
+ semantic:
52
+ "The moment a customer's paid subscription is canceled, downgraded to free, or scheduled to end — the authoritative record that the paid relationship is ending. Usually decided by a billing service / cancellation handler / provider callback.",
53
+ valueSignal: "value_achievement",
54
+ surfaceHint: "backend",
55
+ },
56
+ {
57
+ id: "plan_changed",
58
+ label: "プラン変更(アップグレード/ダウングレード)",
59
+ semantic:
60
+ "The moment a customer moves between paid tiers or quotas (upgrade or downgrade) while the subscription stays active. Distinct from start / cancel — the subscription persists but its value level changes.",
61
+ valueSignal: "value_achievement",
62
+ surfaceHint: "backend",
63
+ },
64
+ {
65
+ id: "signup_completed",
66
+ label: "サインアップ完了(アカウント作成)",
67
+ semantic:
68
+ "The moment a brand-new account / customer record is successfully created for the first time — the authoritative first-touch of a new customer. Distinct from every subsequent login (which is lifecycle identify, not this milestone).",
69
+ valueSignal: "value_achievement",
70
+ surfaceHint: "either",
71
+ },
72
+ {
73
+ id: "member_invited",
74
+ label: "メンバー招待(組織への招待送信)",
75
+ semantic:
76
+ "The moment an existing customer invites another person into their company / organization / workspace context — an expansion signal. The authoritative site is the invitation-creation handler, not the invitee's later acceptance.",
77
+ valueSignal: "value_achievement",
78
+ surfaceHint: "backend",
79
+ },
80
+ {
81
+ id: "key_feature_reached",
82
+ label: "主要機能への到達・アクティベーション",
83
+ semantic:
84
+ "The moment a customer first reaches the product's core value action — the activation milestone the product considers proof the customer got value (first successful core workflow completion, first meaningful output produced, etc.). The specific action is product-defined; ask the customer which action represents 'they got the core value'.",
85
+ valueSignal: "value_achievement",
86
+ surfaceHint: "either",
87
+ },
88
+ ];
89
+
90
+ // Render the selectable catalogue as a Markdown table. Pure projection over the
91
+ // data list — no per-category logic.
92
+ function renderCategoryTable(categories) {
93
+ const header =
94
+ "| # | 選択肢 (label) | イベント名 (event name) | 意味 (semantic milestone) | 典型的な計装面 |\n" +
95
+ "| --- | --- | --- | --- | --- |";
96
+ const rows = categories.map((category, index) => {
97
+ const surface =
98
+ category.surfaceHint === "backend"
99
+ ? "backend 優先"
100
+ : category.surfaceHint === "frontend"
101
+ ? "frontend 優先"
102
+ : "frontend / backend いずれか (実際の権威ソースで判断)";
103
+ return `| ${index + 1} | ${category.label} | \`${category.id}\` | ${category.semantic} | ${surface} |`;
104
+ });
105
+ return [header, ...rows].join("\n");
106
+ }
107
+
108
+ export function buildStep8ValueEvents({ documentsUrl }) {
109
+ const categoryTable = renderCategoryTable(VALUE_EVENT_CATEGORIES);
110
+
111
+ return `You are running inside an AI coding tool. This is STEP 8 of the Cluebase setup flow (guided business value event instrumentation).
112
+
113
+ Goal:
114
+ The lifecycle STEPs (1-7) already wired cluebase.init / cluebase.identify / cluebase.group / cluebase.reset and rely on autocapture for generic UI signals (click / page view / form submit). This STEP layers on the customer's OWN business value milestones — the high-value moments autocapture cannot observe because they are decided server-side or as semantic outcomes. For each milestone the customer selects, you locate the authoritative code path by MEANING, insert a single cluebase.track call there, verify it arrives linked to the acting account, and record the mapping. Business value events are the ONLY place cluebase.track is added — the lifecycle STEPs never add track.
115
+
116
+ Doctrine (read before instrumenting):
117
+ - A cluebase.track event here is a customer VALUE signal (value_achievement), not generic event analytics. Instrument value milestones (a paid conversion, a cancellation, an activation), NOT raw UI noise.
118
+ - Keep observed fact separate from meaning: the SDK sends the fact (event name + reachable properties). Cluebase's backend interprets value. Do NOT compute value/scores in the customer app.
119
+ - Do NOT duplicate autocapture. Never add cluebase.track for events autocapture already covers (click / page view / form submit / input change / button click). The selectable catalogue below is deliberately free of those.
120
+
121
+ Cluebase SDK call signature (CURRENT API — do not deviate):
122
+ \`\`\`typescript
123
+ // Frontend (@genn-inc/cluebase-frontend-sdk) and Node backend (@genn-inc/cluebase-backend-sdk)
124
+ cluebase.track(eventName: string, properties?: Record<string, unknown>, metrics?: Record<string, number>): void
125
+ \`\`\`
126
+ \`\`\`python
127
+ # Python backend (cluebase-backend-sdk)
128
+ cluebase.track(event_name: str, properties: Mapping[str, object] | None = None, metrics: Mapping[str, object] | None = None) -> None
129
+ \`\`\`
130
+
131
+ Inputs (Read tool — already on disk from earlier STEPs):
132
+ [A] \`.cluebase/discoveries.json\` — the lifecycle boundaries + \`db_schema\` grounding + \`organization_context\` produced by STEP 1-3. Use its \`db_schema\` and \`available_fields\` as grounding for what data is reachable; do NOT re-grep the whole repo from scratch.
133
+ [B] \`.cluebase/business-events.json\` — this STEP's own record (may not exist yet on first run; see State recovery).
134
+
135
+ ## Sub-step 1 — Present the catalogue and let the customer choose
136
+
137
+ Show the customer this catalogue and ask, in one Japanese message, which milestones matter to their business (multiple選択可 / 該当なしも可). Each row is a GENERIC value milestone — the customer maps it to their own product:
138
+
139
+ ${categoryTable}
140
+
141
+ Also offer, in the same message, a free-form option:
142
+ 「上記以外にも、御社にとって重要な業務イベント(例: 特定のプラン購入、特定の申込完了、特定の成果達成など)があれば、イベントの意味を日本語で教えてください。安定した英小文字スラッグのイベント名(例: \`quote_requested\`)を一緒に決めて計装します。」
143
+
144
+ Selection rules:
145
+ - The customer may pick any subset of the catalogue, add any number of custom events, or select none.
146
+ - If the customer selects NONE (no catalogue rows, no custom events), skip all instrumentation, record an empty selection in \`.cluebase/business-events.json\`, and go straight to the hand-off. This is a valid outcome — not every product wants business-event tracking on day one.
147
+ - For a custom event, agree on a stable, lowercase, snake_case event name that reads as a business milestone (never a UI element name, never a raw table name). Treat it EXACTLY like a catalogue entry from here on — there is no special-case handling for built-in vs custom events.
148
+
149
+ ## Sub-step 2 — Locate the authoritative site by MEANING (per selected event)
150
+
151
+ For EACH selected event (catalogue or custom), find the ONE authoritative place the milestone actually occurs. This is a SEMANTIC search, not a literal-pattern grep:
152
+ 1. **Concept check** — re-read the event's semantic milestone. Understand WHAT moment you are looking for.
153
+ 2. **Grounded candidate sweep** — using \`db_schema\` from discoveries + a semantic search of the repo, enumerate every place that concept could be decided. Judge by MEANING, including non-English / industry-specific naming. The milestone's real home varies by product and framework — a paid conversion may live in a Stripe/Braintree/PayPal webhook handler, a billing service method, a subscription state transition, an order-completed domain event, or a provider callback. Do not assume a single framework.
154
+ 3. **Authority verification** — open each candidate and confirm it is where the milestone is TRUE, exactly once, for real. Prefer the server-authoritative source when the milestone is server-decided (e.g. a payment provider confirmation), because a client-side "clicked upgrade" is an intent, not the confirmed value milestone. Reject retry loops, read/polling paths, and optimistic UI that can fire before the milestone is real.
155
+ 4. **Surface + SDK choice** — if the authoritative site is a browser module, use the frontend SDK's cluebase.track; if it is server code, use the backend SDK's cluebase.track. The \`典型的な計装面\` column is a hint only — let the actual authoritative site decide.
156
+ 5. **Account linkage check** — the milestone must be attributable to a customer. Confirm the acting subject is known at the site: frontend track must fire in a context where cluebase.identify already ran (post-login); backend track must run where the request/session carries the identified user (the same identity the backend SDK established). If the authoritative site genuinely has no subject in scope (e.g. an anonymous webhook that only carries a provider customer id), record that gap in \`.cluebase/business-events.json\` and surface it to the customer instead of inventing an id — never pass a hardcoded or placeholder subject.
157
+
158
+ ## Sub-step 3 — Insert one cluebase.track per located site
159
+
160
+ For each event with a verified authoritative site:
161
+ - Use the Edit tool with surgical \`old_string\` / \`new_string\` to insert a SINGLE cluebase.track call at the site. Do NOT use the Write tool on existing files.
162
+ - Event name = the exact event id from the catalogue (or the agreed custom slug). Do not rename per file.
163
+ - Properties: attach ONLY value-relevant fields already reachable at the site (plan / tier / amount / currency / organization id, etc.), pasted VERBATIM as expressions the same way STEP 3/5 use \`available_fields\`. NEVER add a new fetch, new API field, or new query to populate properties — if a useful property is not already in scope, omit it. Omit null fields.
164
+ - Numeric value-of-event fields (amount, seats, quantity) go in the third \`metrics\` argument as numbers when reachable; descriptive fields go in \`properties\`.
165
+ - Do NOT wrap cluebase.track in try/catch solely for Cluebase — the SDK is already failure-safe. Match the file's existing style otherwise.
166
+ - Framework-agnostic examples (illustrative — the real path comes from the located site):
167
+ Node/TS billing webhook: \`cluebase.track("subscription_started", { plan: subscription.plan, organizationId: account.id }, { amount: invoice.amountPaid });\`
168
+ Python billing service: \`cluebase.track("subscription_canceled", {"plan": sub.plan, "organizationId": str(account.id)})\`
169
+ Frontend activation: \`cluebase.track("key_feature_reached", { feature: workflow.kind });\`
170
+
171
+ ## Sub-step 4 — Record the mapping (tenant meaning)
172
+
173
+ Use the Write tool to save \`.cluebase/business-events.json\` at the repo root capturing the customer's value-milestone mapping (this is the record the semantic layer + support use; the live meaning also travels on the stable event names you inserted):
174
+ \`\`\`jsonc
175
+ {
176
+ "selected": [
177
+ {
178
+ "event_name": "<catalogue id or custom slug>",
179
+ "label": "<human-readable milestone, Japanese ok>",
180
+ "value_signal": "value_achievement",
181
+ "sites": [{ "file": "<relative path>", "line": <number>, "surface": "frontend" | "backend" }],
182
+ "properties": ["<property expression paths inserted>"],
183
+ "external_source_only": false,
184
+ "notes": "<account-linkage gap or other caveat, else empty>"
185
+ }
186
+ ],
187
+ "_progress": { "completed_substeps": ["step8_events"], "last_updated_at": "<ISO 8601 UTC>" }
188
+ }
189
+ \`\`\`
190
+ On a re-run, read this file first: events already present in \`selected\` with a real \`sites\` entry are DONE — do not re-insert. Only instrument events not yet recorded.
191
+
192
+ ## Sub-step 5 — No-code fallback: guide to the external data source connection
193
+
194
+ If a selected milestone has NO authoritative code path in this repo (the value is only known in an external system the app never sees — e.g. billing lives entirely in a payment platform, a CRM, or a spreadsheet, with no webhook or handler in this codebase), do NOT fabricate code or force a track call. Instead:
195
+ - Record the event in \`.cluebase/business-events.json\` with \`"external_source_only": true\` and a note naming the external system.
196
+ - Tell the customer, in Japanese, that this milestone is best connected via Cluebase's external data source connection screen rather than in-code instrumentation, and point them at the REAL screen path (do not paraphrase the route):
197
+ 「『<milestone>』は、このリポジトリのコードでは発生を捕捉できません(値が外部システムにのみ存在します)。Cluebase 管理画面のサイドバー「設定(Settings)」→「外部データ」(${EXTERNAL_DATA_CONNECTION_PATH})を開き、「${EXTERNAL_DATA_CONNECTION_SCREEN_NAME}」画面からその外部システム(決済プラットフォーム / CRM / スプレッドシート等)を接続すると、コードを変更せずにこの業務イベントを取り込めます。背景は Cluebase のドキュメント(${documentsUrl})も参照してください。」
198
+ - Deep wiring of the external connection is done in the Cluebase dashboard at ${EXTERNAL_DATA_CONNECTION_PATH}, not in this STEP — your job is the guidance + record only.
199
+
200
+ ## Sub-step 6 — Verify send → arrival → account linkage (reuse existing tooling)
201
+
202
+ For at least one instrumented (non-external) event, drive the smallest possible confirmation loop. Do NOT invent a new verification tool — reuse the setup doctor + published batch evidence that STEP 9 also uses:
203
+ 1. Ask the customer to exercise the milestone once in their locally running app WHILE LOGGED IN (so the event carries the identified subject) — e.g. complete a test signup / trigger a test upgrade in a sandbox.
204
+ 2. Run \`${CLUEBASE_CLI_INVOCATION} setup-doctor --local\` via the Bash tool. This confirms the browser/backend ingest transport reaches downstream batch publish evidence (the same ledger hop the milestone event travels).
205
+ 3. Confirm arrival + linkage: check the Cluebase setup logs / published batch evidence for the milestone's event name arriving under the identified subject (not anonymous). If it arrives anonymous, the account-linkage check in Sub-step 2 failed — re-inspect whether the track site runs after identify / with the request subject, fix, and re-verify.
206
+ 4. If the customer cannot exercise the event locally right now, say so plainly and defer the arrival check to STEP 9's \`/cluebase-doctor\` run + a later real exercise; do NOT claim arrival you did not observe.
207
+
208
+ Hard rules:
209
+ - cluebase.track is added ONLY for the customer-selected value milestones located above. Do NOT broadly instrument, do NOT add track for autocapture-covered UI events, and do NOT touch the lifecycle calls from STEP 5.
210
+ - Do NOT modify any API, ORM model, response shape, or add any fetch to populate track properties. Use only fields already reachable at the site.
211
+ - Do NOT pass a hardcoded / placeholder / id-as-name subject to satisfy account linkage. Surface the gap instead.
212
+ - Do NOT edit \`.cluebase/discoveries.json\` (read-only here) except to patch its top-level \`_progress\` per the State recovery contract.
213
+ - Treat catalogue and custom events identically — no per-event special-casing.
214
+
215
+ When all selected events are instrumented (or recorded as external-source / no-selection) and at least one verification loop is attempted, respond with exactly the following Japanese block (and nothing else after it):
216
+
217
+ ==========================================
218
+ STEP 8(重要業務イベントの計装)完了
219
+ ==========================================
220
+ 計装した業務イベント: <event names + files, or「なし(選択なし)」>
221
+ 外部データ接続画面(${EXTERNAL_DATA_CONNECTION_PATH})に案内: <event names, or「なし」>
222
+ 着弾確認: <確認済み event name / 未確認(理由)>
223
+ 記録: .cluebase/business-events.json
224
+
225
+ 次は Claude Code で /cluebase-doctor と打って STEP 9(最終疎通確認)を実行してください。
226
+ ==========================================
227
+
228
+ Reference docs: ${documentsUrl}`;
229
+ }