@geekyants/think-before 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 think-before contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # think-before
2
+
3
+ **A fast yes/no reflection before you change something.**
4
+
5
+ A small change in a big app is rarely small. `think-before` is a tiny, zero-dependency CLI that walks you through a sharp set of yes/no questions so the side-effects you'd otherwise discover *in production* surface *on the whiteboard* instead.
6
+
7
+ It's the pause between "this is a one-line fix" and `git push`.
8
+
9
+ ```
10
+ $ npx @geekyants/think-before
11
+
12
+ Quick — Blast-radius check
13
+ A small change in a big app is rarely small. 60 seconds of honesty before you start.
14
+ Answer fast — y yes · n no · s skip · ? why · q quit
15
+
16
+ Blast radius
17
+ 3/16 Is this in shared/global code used in many places? [y/n] ✓ yes ⚠ worth a second look
18
+ ↳ Shared code multiplies the blast radius — one edit ripples everywhere it's imported.
19
+ ```
20
+
21
+ ## Quick start
22
+
23
+ No install needed:
24
+
25
+ ```bash
26
+ npx @geekyants/think-before # quick blast-radius check (default)
27
+ npx @geekyants/think-before full # the full pre-development discovery checklist
28
+ ```
29
+
30
+ Or install it:
31
+
32
+ ```bash
33
+ npm install -g @geekyants/think-before
34
+ think-before # the installed command is just `think-before`
35
+ ```
36
+
37
+ ## Modes
38
+
39
+ | Mode | What it's for |
40
+ | --- | --- |
41
+ | `quick` *(default)* | The "I'm about to touch the big app" moment. ~16 sharp questions about blast radius, data, contracts, your safety net, and timing. |
42
+ | `full` | A team-level pre-development discovery sweep: problem, users, scope, risks, plus role sections for designers, engineers, and developers. |
43
+
44
+ In `full` mode you can focus on one role (shared sections are always included):
45
+
46
+ ```bash
47
+ think-before full --role designer
48
+ think-before full --role engineer
49
+ think-before full --role developer
50
+ ```
51
+
52
+ ## How to answer
53
+
54
+ Single keypress, no Enter needed:
55
+
56
+ | Key | Meaning |
57
+ | --- | --- |
58
+ | `y` | yes |
59
+ | `n` | no |
60
+ | `s` or `Enter` | skip (logs it as an open question) |
61
+ | `?` | show *why this question matters* |
62
+ | `q` or `Esc` | quit |
63
+
64
+ Answers that point at risk get **flagged** with a one-line reason. At the end you get a summary of everything worth a second look — and the option to save it.
65
+
66
+ > **A skipped question is an open question, not a free pass.** A short list of "we don't know yet" is more valuable than a confident plan built on untested assumptions.
67
+
68
+ ## Options
69
+
70
+ ```
71
+ --role <r> In full mode, show shared + one role: designer | engineer | developer
72
+ --save [file] Save a Markdown report (optionally to <file>) without asking
73
+ --no-save Don't save and don't ask
74
+ --list Print the checklist and exit (no prompts)
75
+ --no-color Disable colored output
76
+ -v, --version Print version
77
+ -h, --help Show this help
78
+ ```
79
+
80
+ The report is plain Markdown — drop it into a PR description, a ticket, or your design doc.
81
+
82
+ ## Use as a library
83
+
84
+ ```ts
85
+ import { quick, full, filterSections, runSession, buildMarkdown } from "@geekyants/think-before";
86
+
87
+ const sections = filterSections(full, "engineer");
88
+ const result = await runSession(full, sections);
89
+ const markdown = buildMarkdown(full, result, new Date());
90
+ ```
91
+
92
+ ## Develop
93
+
94
+ ```bash
95
+ npm install
96
+ npm run dev # run the CLI straight from TypeScript source
97
+ npm run build # compile to dist/
98
+ npm start # run the built CLI
99
+ ```
100
+
101
+ Want to add or tweak questions? They live in [`src/checklists.ts`](src/checklists.ts) — each question declares which answer (`yes`/`no`) is the risky one, plus an optional `why`. PRs welcome.
102
+
103
+ ## License
104
+
105
+ MIT
@@ -0,0 +1,21 @@
1
+ import type { Checklist } from "./types.js";
2
+ /**
3
+ * QUICK — the blast-radius check.
4
+ *
5
+ * For the "I'm about to make a small change to a big app" moment. Fast,
6
+ * sharp, and focused on the side-effects people overlook. Most questions
7
+ * are phrased so that the *risky* answer surfaces something to double-check
8
+ * before you touch the code.
9
+ */
10
+ export declare const quick: Checklist;
11
+ /**
12
+ * FULL — the pre-development discovery checklist.
13
+ *
14
+ * The team-level questions to ask *before* starting any workflow, reframed
15
+ * as yes/no so you can sweep them quickly. A "no" here usually means a gap
16
+ * worth closing, not a blocker — log it as an open question.
17
+ */
18
+ export declare const full: Checklist;
19
+ /** All built-in checklists, keyed by id. */
20
+ export declare const checklists: Record<string, Checklist>;
21
+ //# sourceMappingURL=checklists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklists.d.ts","sourceRoot":"","sources":["../src/checklists.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,EAAE,SA0InB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,EAAE,SAiJlB,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAGhD,CAAC"}
@@ -0,0 +1,306 @@
1
+ /**
2
+ * QUICK — the blast-radius check.
3
+ *
4
+ * For the "I'm about to make a small change to a big app" moment. Fast,
5
+ * sharp, and focused on the side-effects people overlook. Most questions
6
+ * are phrased so that the *risky* answer surfaces something to double-check
7
+ * before you touch the code.
8
+ */
9
+ export const quick = {
10
+ id: "quick",
11
+ title: "Quick — Blast-radius check",
12
+ intro: "A small change in a big app is rarely small. 60 seconds of honesty before you start.",
13
+ sections: [
14
+ {
15
+ id: "understand",
16
+ title: "Understand the change",
17
+ roles: ["shared"],
18
+ questions: [
19
+ {
20
+ id: "understand-current",
21
+ text: "Do you understand what this code does today — not just the line you're editing?",
22
+ risky: "no",
23
+ why: "Editing code you don't fully understand is the #1 source of surprise side-effects.",
24
+ },
25
+ {
26
+ id: "one-sentence",
27
+ text: "Can you describe the change and its intended effect in one sentence?",
28
+ risky: "no",
29
+ why: "If you can't state it simply, the scope isn't clear yet — and unclear scope hides risk.",
30
+ },
31
+ ],
32
+ },
33
+ {
34
+ id: "blast-radius",
35
+ title: "Blast radius",
36
+ roles: ["shared"],
37
+ questions: [
38
+ {
39
+ id: "shared-code",
40
+ text: "Is this in shared/global code (a util, base component, hook, config, middleware) used in many places?",
41
+ risky: "yes",
42
+ why: "Shared code multiplies the blast radius — one edit ripples everywhere it's imported.",
43
+ },
44
+ {
45
+ id: "found-callers",
46
+ text: "Have you searched for every caller / usage of what you're changing?",
47
+ risky: "no",
48
+ why: "Unknown callers are unknown breakage. Grep for usages before you edit, not after.",
49
+ },
50
+ {
51
+ id: "untested-flows",
52
+ text: "Could this change behavior in flows you are NOT going to manually test?",
53
+ risky: "yes",
54
+ why: "The side-effects you don't test for are exactly the ones that reach production.",
55
+ },
56
+ ],
57
+ },
58
+ {
59
+ id: "data-contracts",
60
+ title: "Data & contracts",
61
+ roles: ["shared"],
62
+ questions: [
63
+ {
64
+ id: "data-touch",
65
+ text: "Does it touch persisted data — schema, migrations, stored formats, or cached values?",
66
+ risky: "yes",
67
+ why: "Data changes are the hardest to roll back; old data outlives your deploy.",
68
+ },
69
+ {
70
+ id: "public-contract",
71
+ text: "Does it change a public API, response shape, event, or contract others depend on?",
72
+ risky: "yes",
73
+ why: "Consumers you can't see — other teams, mobile apps, integrations — may break silently.",
74
+ },
75
+ {
76
+ id: "backward-compat",
77
+ text: "Have you accounted for backward compatibility and in-flight / old-shaped data?",
78
+ risky: "no",
79
+ why: "Queues, caches, and old clients may still hold the previous shape after you deploy.",
80
+ },
81
+ ],
82
+ },
83
+ {
84
+ id: "safety-net",
85
+ title: "Safety net",
86
+ roles: ["shared"],
87
+ questions: [
88
+ {
89
+ id: "tests-cover",
90
+ text: "Do existing automated tests cover this path, and do they still pass?",
91
+ risky: "no",
92
+ why: "No test means no safety net. Add or run one before the change, not after the incident.",
93
+ },
94
+ {
95
+ id: "rollback",
96
+ text: "Is there a fast way to undo this (revert, feature flag, kill switch)?",
97
+ risky: "no",
98
+ why: "If you can't roll back quickly, the cost of being wrong is much higher.",
99
+ },
100
+ {
101
+ id: "observability",
102
+ text: "If this breaks in production, will you find out (logs, metrics, alerts)?",
103
+ risky: "no",
104
+ why: "Silent failures are the worst kind — you learn about them from angry users.",
105
+ },
106
+ ],
107
+ },
108
+ {
109
+ id: "risk-surfaces",
110
+ title: "High-risk surfaces",
111
+ roles: ["shared"],
112
+ questions: [
113
+ {
114
+ id: "security",
115
+ text: "Does it touch auth, permissions, security, or anything handling PII / secrets?",
116
+ risky: "yes",
117
+ why: "These failures are high-severity and often invisible until they're exploited.",
118
+ },
119
+ {
120
+ id: "performance",
121
+ text: "Could it affect performance at scale (N+1, large lists, hot path, extra network calls)?",
122
+ risky: "yes",
123
+ why: "What's fine with 10 rows can melt down at 10 million. Side-effects scale too.",
124
+ },
125
+ ],
126
+ },
127
+ {
128
+ id: "timing-gut",
129
+ title: "Timing & gut check",
130
+ roles: ["shared"],
131
+ questions: [
132
+ {
133
+ id: "timing",
134
+ text: "Are you shipping at a risky time (Friday, right before a release, peak traffic, on-call gap)?",
135
+ risky: "yes",
136
+ why: "Bad timing turns a small bug into a long incident with nobody around to fix it.",
137
+ },
138
+ {
139
+ id: "gut",
140
+ text: "Be honest — do you actually understand the side-effects of this change?",
141
+ risky: "no",
142
+ why: "Your gut is data. If it says 'not sure', pause and dig before you commit.",
143
+ },
144
+ ],
145
+ },
146
+ ],
147
+ };
148
+ /**
149
+ * FULL — the pre-development discovery checklist.
150
+ *
151
+ * The team-level questions to ask *before* starting any workflow, reframed
152
+ * as yes/no so you can sweep them quickly. A "no" here usually means a gap
153
+ * worth closing, not a blocker — log it as an open question.
154
+ */
155
+ export const full = {
156
+ id: "full",
157
+ title: "Full — Pre-development discovery",
158
+ intro: "Surface assumptions, scope, and risk while changes are still cheap — on a whiteboard, not in prod.",
159
+ sections: [
160
+ {
161
+ id: "problem-goals",
162
+ title: "1. Problem & Goals",
163
+ roles: ["shared"],
164
+ questions: [
165
+ { id: "problem-statement", text: "Can you state the problem you're solving in one sentence?", risky: "no" },
166
+ { id: "why-now", text: "Do you know why now — and what happens if you don't build it?", risky: "no" },
167
+ { id: "success-metric", text: "Is success defined with a metric, a target, and a timeframe?", risky: "no" },
168
+ { id: "change-type", text: "Are you clear whether this is a new capability, an improvement, or a fix?", risky: "no", why: "It changes the risk profile and how much process it needs." },
169
+ { id: "decision-maker", text: "Is the final decision-maker on scope identified?", risky: "no" },
170
+ { id: "attempted-before", text: "Do you know whether this was attempted before, and what happened?", risky: "no" },
171
+ ],
172
+ },
173
+ {
174
+ id: "users-stakeholders",
175
+ title: "2. Users & Stakeholders",
176
+ roles: ["shared"],
177
+ questions: [
178
+ { id: "primary-users", text: "Do you know who the primary (and secondary) users are?", risky: "no" },
179
+ { id: "job-to-be-done", text: "Is the user's job-to-be-done clearly understood?", risky: "no" },
180
+ { id: "current-workflow", text: "Do you understand the current workflow without this feature?", risky: "no" },
181
+ { id: "signoff-stages", text: "Are the stakeholders who must review or sign off identified, with stages?", risky: "no" },
182
+ { id: "internal-users", text: "Have you considered internal users (support, ops, admins) and their needs?", risky: "no" },
183
+ { id: "discovery", text: "Is there a plan for how users will find out this exists?", risky: "no" },
184
+ ],
185
+ },
186
+ {
187
+ id: "scope-requirements",
188
+ title: "3. Scope & Requirements",
189
+ roles: ["shared"],
190
+ questions: [
191
+ { id: "in-scope", text: "Is what's IN scope for this iteration written down?", risky: "no" },
192
+ { id: "out-of-scope", text: "Is what's OUT of scope written down?", risky: "no", why: "Explicit non-goals are what actually prevent scope creep." },
193
+ { id: "mvp-cut", text: "Is the MVP cut — the minimum that delivers value — defined?", risky: "no" },
194
+ { id: "acceptance-criteria", text: "Are the acceptance criteria for 'done' defined?", risky: "no" },
195
+ { id: "requirements-stability", text: "Do you know whether requirements are fixed or expected to evolve?", risky: "no" },
196
+ { id: "unvalidated-assumptions", text: "Have you listed the assumptions you're making but haven't validated?", risky: "no" },
197
+ ],
198
+ },
199
+ {
200
+ id: "constraints-logistics",
201
+ title: "4. Constraints & Logistics",
202
+ roles: ["shared"],
203
+ questions: [
204
+ { id: "deadline", text: "Is the deadline known, and whether it's hard or soft (and why)?", risky: "no" },
205
+ { id: "capacity", text: "Is the available budget / capacity (people, hours) known?", risky: "no" },
206
+ { id: "ownership", text: "Is long-term ownership after launch assigned?", risky: "no" },
207
+ { id: "dependencies", text: "Are dependencies on other teams, vendors, or releases mapped?", risky: "no" },
208
+ { id: "legal-deadlines", text: "Are any legal / contractual / regulatory deadlines identified?", risky: "no" },
209
+ { id: "fallback-plan", text: "Is there a rollback / fallback plan if it goes wrong?", risky: "no" },
210
+ ],
211
+ },
212
+ {
213
+ id: "risks-unknowns",
214
+ title: "5. Risks & Unknowns",
215
+ roles: ["shared"],
216
+ questions: [
217
+ { id: "biggest-risk", text: "Do you know the single biggest risk to this project?", risky: "no" },
218
+ { id: "riskiest-assumption", text: "Have you identified the riskiest assumption — and can you test it cheaply first?", risky: "no" },
219
+ { id: "known-unknowns", text: "Are the known unknowns to research before committing listed?", risky: "no" },
220
+ { id: "three-x", text: "Do you know what could make this take 3x longer than estimated?", risky: "no" },
221
+ { id: "spof", text: "Have you checked for single points of failure (one person, one system, one vendor)?", risky: "no" },
222
+ ],
223
+ },
224
+ {
225
+ id: "designers",
226
+ title: "6. For Designers",
227
+ roles: ["designer"],
228
+ questions: [
229
+ { id: "real-research", text: "Do you have real user research (not guesses) for who you're designing for?", risky: "no" },
230
+ { id: "existing-patterns", text: "Have you identified the existing patterns, components, or design-system rules that apply?", risky: "no" },
231
+ { id: "key-flows", text: "Are the key user flows mapped, including error and empty states?", risky: "no" },
232
+ { id: "a11y", text: "Do you know the accessibility standards to meet (e.g. WCAG AA: contrast, keyboard, screen readers, touch targets)?", risky: "no" },
233
+ { id: "viewports", text: "Are the supported devices, breakpoints, and viewports defined?", risky: "no" },
234
+ { id: "copy", text: "Is it clear what copy is needed, who writes it, and any localization?", risky: "no" },
235
+ { id: "design-edge-cases", text: "Have you considered edge cases: long text, missing data, slow connections, large lists?", risky: "no" },
236
+ { id: "validation", text: "Is there a plan to validate the design (usability test, prototype, A/B)?", risky: "no" },
237
+ { id: "handoff", text: "Is the engineering handoff defined (tokens, specs, states, motion)?", risky: "no" },
238
+ { id: "brand-legal", text: "Have you checked brand, legal, or compliance constraints on the UI?", risky: "no" },
239
+ ],
240
+ },
241
+ {
242
+ id: "engineers",
243
+ title: "7. For Engineers / Architects",
244
+ roles: ["engineer"],
245
+ questions: [
246
+ { id: "nfrs", text: "Are the non-functional requirements (performance, scale, latency, uptime) defined?", risky: "no" },
247
+ { id: "load", text: "Do you know the expected load at launch and at projected growth?", risky: "no" },
248
+ { id: "data-ownership", text: "Is it clear what data you read/write, where it lives, and who owns it?", risky: "no" },
249
+ { id: "external-apis", text: "Are external APIs/services, their rate limits, and SLAs identified?", risky: "no" },
250
+ { id: "fits-architecture", text: "Do you know whether this fits the current architecture or needs a new pattern?", risky: "no" },
251
+ { id: "security-reqs", text: "Are the security requirements (authn/authz, encryption, secrets, PII) defined?", risky: "no" },
252
+ { id: "compliance", text: "Are the applicable privacy/compliance rules known (GDPR, CCPA, HIPAA, SOC 2, residency)?", risky: "no" },
253
+ { id: "failure-handling", text: "Is there a plan for failures, retries, idempotency, and degraded states?", risky: "no" },
254
+ { id: "observability-plan", text: "Is the observability plan (logging, metrics, tracing, alerts) defined?", risky: "no" },
255
+ { id: "deploy-plan", text: "Is the deployment approach clear (CI/CD, feature flags, migrations, zero-downtime)?", risky: "no" },
256
+ ],
257
+ },
258
+ {
259
+ id: "developers",
260
+ title: "8. For Developers (Implementation)",
261
+ roles: ["developer"],
262
+ questions: [
263
+ { id: "first-test", text: "Do you understand the acceptance criteria well enough to write the first test?", risky: "no" },
264
+ { id: "small-pieces", text: "Can you break this into small, independently shippable pieces?", risky: "no" },
265
+ { id: "code-location", text: "Do you know where the code lives and what conventions/standards apply?", risky: "no" },
266
+ { id: "reuse", text: "Have you checked what already exists that you can reuse instead of rewriting?", risky: "no" },
267
+ { id: "testing-strategy", text: "Is the testing strategy (unit, integration, e2e) and coverage target clear?", risky: "no" },
268
+ { id: "run-locally", text: "Can you run this locally — is the dev environment / test data ready?", risky: "no" },
269
+ { id: "edge-inputs", text: "Do you know the edge cases and invalid inputs you must handle?", risky: "no" },
270
+ { id: "migration", text: "Have you considered backward-compatibility and migration concerns?", risky: "no" },
271
+ { id: "review-bar", text: "Is it clear how this will be reviewed and what 'ready to merge' means?", risky: "no" },
272
+ { id: "docs", text: "Do you know what documentation you need to write (README, API docs, runbook)?", risky: "no" },
273
+ ],
274
+ },
275
+ {
276
+ id: "launch-readiness",
277
+ title: "9. Quality & Launch Readiness",
278
+ roles: ["shared"],
279
+ questions: [
280
+ { id: "release-checklist", text: "Is the release checklist — what must be true before shipping — defined?", risky: "no" },
281
+ { id: "prod-like-test", text: "Is there a plan to test in a production-like environment?", risky: "no" },
282
+ { id: "monitoring-oncall", text: "Is the monitoring plan and the on-call owner after launch defined?", risky: "no" },
283
+ { id: "fast-rollback", text: "Is there a fast rollback if something breaks?", risky: "no" },
284
+ { id: "comms-plan", text: "Is the launch communication plan (internal + users) ready?", risky: "no" },
285
+ { id: "goal-review", text: "Is there a plan and date to review whether this actually hit its goals?", risky: "no" },
286
+ ],
287
+ },
288
+ {
289
+ id: "gut-check",
290
+ title: "10. Final Gut Check",
291
+ roles: ["shared"],
292
+ questions: [
293
+ { id: "half-value", text: "If you shipped only half of this, do you know which half delivers the most value?", risky: "no" },
294
+ { id: "alignment", text: "Is everyone aligned on scope, owner, and definition of done?", risky: "no" },
295
+ { id: "regret", text: "Do you know the one thing you're most likely to regret skipping?", risky: "no" },
296
+ { id: "real-problem", text: "Are you solving the real problem, not just the requested solution?", risky: "no" },
297
+ ],
298
+ },
299
+ ],
300
+ };
301
+ /** All built-in checklists, keyed by id. */
302
+ export const checklists = {
303
+ quick,
304
+ full,
305
+ };
306
+ //# sourceMappingURL=checklists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklists.js","sourceRoot":"","sources":["../src/checklists.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import { checklists } from "./checklists.js";
4
+ import { filterSections, runSession } from "./session.js";
5
+ import { buildMarkdown, defaultReportName, printList, printSummary, saveReport } from "./report.js";
6
+ import { askYesNo, closeInput } from "./prompt.js";
7
+ import { bold, cyan, dim, green, setColor, yellow } from "./colors.js";
8
+ const VALID_ROLES = ["designer", "engineer", "developer", "shared"];
9
+ function readVersion() {
10
+ try {
11
+ const pkg = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
12
+ return typeof pkg.version === "string" ? pkg.version : "0.0.0";
13
+ }
14
+ catch {
15
+ return "0.0.0";
16
+ }
17
+ }
18
+ function printHelp() {
19
+ const b = bold;
20
+ console.log(`
21
+ ${b("think-before")} — a fast yes/no reflection before you change something.
22
+
23
+ ${b("Usage")}
24
+ think-before [mode] [options]
25
+
26
+ ${b("Modes")}
27
+ quick Blast-radius check for a small change ${dim("(default)")}
28
+ full Full pre-development discovery checklist
29
+
30
+ ${b("Options")}
31
+ --role <r> In full mode, show shared + one role: designer | engineer | developer
32
+ --save [file] Save a Markdown report (optionally to <file>) without asking
33
+ --no-save Don't save and don't ask
34
+ --list Print the checklist and exit (no prompts)
35
+ --no-color Disable colored output
36
+ -v, --version Print version
37
+ -h, --help Show this help
38
+
39
+ ${b("Keys during a session")}
40
+ ${cyan("y")} yes · ${cyan("n")} no · ${cyan("s")} skip · ${cyan("?")} why this matters · ${cyan("q")} quit
41
+
42
+ ${b("Examples")}
43
+ npx @geekyants/think-before
44
+ npx @geekyants/think-before full
45
+ npx @geekyants/think-before full --role engineer
46
+ npx @geekyants/think-before quick --save
47
+ `);
48
+ }
49
+ function parseArgs(argv) {
50
+ const opts = { mode: "quick", saveMode: "prompt", list: false, color: true };
51
+ for (let i = 0; i < argv.length; i++) {
52
+ const arg = argv[i];
53
+ switch (arg) {
54
+ case "-h":
55
+ case "--help":
56
+ printHelp();
57
+ process.exit(0);
58
+ break;
59
+ case "-v":
60
+ case "--version":
61
+ console.log(readVersion());
62
+ process.exit(0);
63
+ break;
64
+ case "--list":
65
+ opts.list = true;
66
+ break;
67
+ case "--no-color":
68
+ opts.color = false;
69
+ break;
70
+ case "--no-save":
71
+ opts.saveMode = "off";
72
+ break;
73
+ case "--save": {
74
+ opts.saveMode = "auto";
75
+ const next = argv[i + 1];
76
+ if (next && !next.startsWith("-")) {
77
+ opts.savePath = next;
78
+ i++;
79
+ }
80
+ break;
81
+ }
82
+ case "--role": {
83
+ const next = argv[i + 1];
84
+ if (!next || !VALID_ROLES.includes(next)) {
85
+ fail(`--role must be one of: ${VALID_ROLES.filter((r) => r !== "shared").join(", ")}`);
86
+ }
87
+ opts.role = next;
88
+ i++;
89
+ break;
90
+ }
91
+ default:
92
+ if (arg && arg.startsWith("-")) {
93
+ fail(`Unknown option: ${arg}`);
94
+ }
95
+ else if (arg) {
96
+ opts.mode = arg;
97
+ }
98
+ }
99
+ }
100
+ return opts;
101
+ }
102
+ function fail(message) {
103
+ console.error(yellow("think-before: ") + message);
104
+ console.error(dim("Run `think-before --help` for usage."));
105
+ process.exit(1);
106
+ }
107
+ async function main() {
108
+ const opts = parseArgs(process.argv.slice(2));
109
+ if (!opts.color)
110
+ setColor(false);
111
+ const checklist = checklists[opts.mode];
112
+ if (!checklist) {
113
+ fail(`Unknown mode: ${opts.mode}. Try "quick" or "full".`);
114
+ }
115
+ if (opts.role && opts.mode !== "full") {
116
+ console.error(dim("note: --role only affects full mode; ignoring it for quick mode.\n"));
117
+ opts.role = undefined;
118
+ }
119
+ const sections = filterSections(checklist, opts.role);
120
+ if (opts.list) {
121
+ printList(checklist, sections);
122
+ return;
123
+ }
124
+ const result = await runSession(checklist, sections);
125
+ printSummary(result);
126
+ // Nothing to save if the user quit before answering anything.
127
+ if (result.answers.length === 0)
128
+ return;
129
+ await maybeSave(opts, checklist, result);
130
+ console.log();
131
+ }
132
+ async function maybeSave(opts, checklist, result) {
133
+ if (opts.saveMode === "off")
134
+ return;
135
+ let shouldSave = opts.saveMode === "auto";
136
+ if (opts.saveMode === "prompt") {
137
+ console.log();
138
+ process.stdout.write(dim("Save a Markdown report? ") + dim("[y/N] "));
139
+ const ans = await askYesNo();
140
+ process.stdout.write("\n");
141
+ shouldSave = ans === "yes";
142
+ }
143
+ if (!shouldSave)
144
+ return;
145
+ const now = new Date();
146
+ const fileName = opts.savePath ?? defaultReportName(checklist, now);
147
+ const md = buildMarkdown(checklist, result, now);
148
+ try {
149
+ const saved = saveReport(fileName, md);
150
+ console.log(green("✓ saved ") + saved);
151
+ }
152
+ catch (err) {
153
+ console.error(yellow("Could not save report: ") + err.message);
154
+ }
155
+ }
156
+ main()
157
+ .then(() => closeInput())
158
+ .catch((err) => {
159
+ console.error(err);
160
+ process.exit(1);
161
+ });
162
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /** Force colors on or off (e.g. from a `--no-color` flag). */
2
+ export declare function setColor(on: boolean): void;
3
+ export declare const bold: (s: string) => string;
4
+ export declare const dim: (s: string) => string;
5
+ export declare const red: (s: string) => string;
6
+ export declare const green: (s: string) => string;
7
+ export declare const yellow: (s: string) => string;
8
+ export declare const blue: (s: string) => string;
9
+ export declare const magenta: (s: string) => string;
10
+ export declare const cyan: (s: string) => string;
11
+ export declare const gray: (s: string) => string;
12
+ //# sourceMappingURL=colors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAKA,8DAA8D;AAC9D,wBAAgB,QAAQ,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAE1C;AAMD,eAAO,MAAM,IAAI,MAJ+B,MAAM,KAAK,MAI5B,CAAC;AAChC,eAAO,MAAM,GAAG,MALgC,MAAM,KAAK,MAK7B,CAAC;AAC/B,eAAO,MAAM,GAAG,MANgC,MAAM,KAAK,MAM5B,CAAC;AAChC,eAAO,MAAM,KAAK,MAP8B,MAAM,KAAK,MAO1B,CAAC;AAClC,eAAO,MAAM,MAAM,MAR6B,MAAM,KAAK,MAQzB,CAAC;AACnC,eAAO,MAAM,IAAI,MAT+B,MAAM,KAAK,MAS3B,CAAC;AACjC,eAAO,MAAM,OAAO,MAV4B,MAAM,KAAK,MAUxB,CAAC;AACpC,eAAO,MAAM,IAAI,MAX+B,MAAM,KAAK,MAW3B,CAAC;AACjC,eAAO,MAAM,IAAI,MAZ+B,MAAM,KAAK,MAY3B,CAAC"}
package/dist/colors.js ADDED
@@ -0,0 +1,20 @@
1
+ // Tiny zero-dependency ANSI color helpers. Honors NO_COLOR, non-TTY output,
2
+ // and an explicit `--no-color` flag (via setColor).
3
+ let useColor = Boolean(process.stdout.isTTY) && !process.env["NO_COLOR"];
4
+ /** Force colors on or off (e.g. from a `--no-color` flag). */
5
+ export function setColor(on) {
6
+ useColor = on;
7
+ }
8
+ function wrap(open, close) {
9
+ return (s) => (useColor ? `\x1b[${open}m${s}\x1b[${close}m` : s);
10
+ }
11
+ export const bold = wrap(1, 22);
12
+ export const dim = wrap(2, 22);
13
+ export const red = wrap(31, 39);
14
+ export const green = wrap(32, 39);
15
+ export const yellow = wrap(33, 39);
16
+ export const blue = wrap(34, 39);
17
+ export const magenta = wrap(35, 39);
18
+ export const cyan = wrap(36, 39);
19
+ export const gray = wrap(90, 39);
20
+ //# sourceMappingURL=colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.js","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,oDAAoD;AAEpD,IAAI,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAEzE,8DAA8D;AAC9D,MAAM,UAAU,QAAQ,CAAC,EAAW;IAClC,QAAQ,GAAG,EAAE,CAAC;AAChB,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,KAAa;IACvC,OAAO,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAChC,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAClC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from "./types.js";
2
+ export { quick, full, checklists } from "./checklists.js";
3
+ export { filterSections, runSession } from "./session.js";
4
+ export { askYesNo, closeInput } from "./prompt.js";
5
+ export { buildMarkdown, defaultReportName, printSummary, printList, saveReport } from "./report.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ // Public API — import `think-before` programmatically as a library.
2
+ //
3
+ // import { quick, full, runSession, filterSections, buildMarkdown } from "think-before";
4
+ export * from "./types.js";
5
+ export { quick, full, checklists } from "./checklists.js";
6
+ export { filterSections, runSession } from "./session.js";
7
+ export { askYesNo, closeInput } from "./prompt.js";
8
+ export { buildMarkdown, defaultReportName, printSummary, printList, saveReport } from "./report.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,2FAA2F;AAE3F,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { AnswerValue } from "./types.js";
2
+ export type AnswerOrQuit = AnswerValue | "quit";
3
+ /**
4
+ * Ask a single yes/no/skip question and resolve on the first keypress.
5
+ *
6
+ * y → yes n → no s / Enter → skip
7
+ * ? → print "why this matters" and keep waiting
8
+ * q / Esc / Ctrl-C → quit
9
+ *
10
+ * Falls back to line input when stdin is not a TTY (piped/CI), so the tool
11
+ * still works in non-interactive contexts.
12
+ */
13
+ export declare function askYesNo(why?: string): Promise<AnswerOrQuit>;
14
+ /** Release the shared line reader so the process can exit (non-TTY only). */
15
+ export declare function closeInput(): void;
16
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,MAAM,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAyC5D;AA0CD,6EAA6E;AAC7E,wBAAgB,UAAU,IAAI,IAAI,CAKjC"}
package/dist/prompt.js ADDED
@@ -0,0 +1,107 @@
1
+ import readline from "node:readline";
2
+ import { dim } from "./colors.js";
3
+ /**
4
+ * Ask a single yes/no/skip question and resolve on the first keypress.
5
+ *
6
+ * y → yes n → no s / Enter → skip
7
+ * ? → print "why this matters" and keep waiting
8
+ * q / Esc / Ctrl-C → quit
9
+ *
10
+ * Falls back to line input when stdin is not a TTY (piped/CI), so the tool
11
+ * still works in non-interactive contexts.
12
+ */
13
+ export function askYesNo(why) {
14
+ const stdin = process.stdin;
15
+ if (!stdin.isTTY)
16
+ return askLine();
17
+ return new Promise((resolve) => {
18
+ readline.emitKeypressEvents(stdin);
19
+ stdin.setRawMode(true);
20
+ stdin.resume();
21
+ const cleanup = () => {
22
+ stdin.removeListener("keypress", onKey);
23
+ stdin.setRawMode(false);
24
+ stdin.pause();
25
+ };
26
+ const onKey = (str, key) => {
27
+ if (key && key.ctrl && key.name === "c") {
28
+ cleanup();
29
+ resolve("quit");
30
+ return;
31
+ }
32
+ const k = (str || "").toLowerCase();
33
+ if (k === "y") {
34
+ cleanup();
35
+ resolve("yes");
36
+ }
37
+ else if (k === "n") {
38
+ cleanup();
39
+ resolve("no");
40
+ }
41
+ else if (k === "s" || (key && key.name === "return")) {
42
+ cleanup();
43
+ resolve("skip");
44
+ }
45
+ else if (k === "q" || (key && key.name === "escape")) {
46
+ cleanup();
47
+ resolve("quit");
48
+ }
49
+ else if (k === "?" && why) {
50
+ process.stdout.write("\n " + dim("↳ " + why) + "\n ");
51
+ }
52
+ };
53
+ stdin.on("keypress", onKey);
54
+ });
55
+ }
56
+ // --- Non-TTY line reader -------------------------------------------------
57
+ // A single shared readline interface, reused across all questions. Creating
58
+ // one per question drops buffered lines from piped input, so we keep one and
59
+ // hand out lines to waiters in order.
60
+ let lineRl = null;
61
+ const lineQueue = [];
62
+ const waiters = [];
63
+ function ensureLineReader() {
64
+ if (lineRl)
65
+ return;
66
+ lineRl = readline.createInterface({ input: process.stdin });
67
+ lineRl.on("line", (line) => {
68
+ const waiter = waiters.shift();
69
+ if (waiter)
70
+ waiter(line);
71
+ else
72
+ lineQueue.push(line);
73
+ });
74
+ lineRl.on("close", () => {
75
+ while (waiters.length)
76
+ waiters.shift()?.(null);
77
+ });
78
+ }
79
+ function readLineOnce() {
80
+ ensureLineReader();
81
+ const queued = lineQueue.shift();
82
+ if (queued !== undefined)
83
+ return Promise.resolve(queued);
84
+ return new Promise((resolve) => waiters.push(resolve));
85
+ }
86
+ function askLine() {
87
+ return readLineOnce().then((line) => {
88
+ if (line === null)
89
+ return "quit"; // EOF
90
+ const k = line.trim().toLowerCase();
91
+ if (k.startsWith("y"))
92
+ return "yes";
93
+ if (k.startsWith("n"))
94
+ return "no";
95
+ if (k.startsWith("q"))
96
+ return "quit";
97
+ return "skip";
98
+ });
99
+ }
100
+ /** Release the shared line reader so the process can exit (non-TTY only). */
101
+ export function closeInput() {
102
+ if (lineRl) {
103
+ lineRl.close();
104
+ lineRl = null;
105
+ }
106
+ }
107
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAKlC;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAY;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,IAAI,CAAC,KAAK,CAAC,KAAK;QAAE,OAAO,OAAO,EAAE,CAAC;IAEnC,OAAO,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,EAAE;QAC3C,QAAQ,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACnC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACvB,KAAK,CAAC,MAAM,EAAE,CAAC;QAEf,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YACxC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACxB,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,CAAC,CAAC;QAEF,MAAM,KAAK,GAAG,CAAC,GAAW,EAAE,GAAiB,EAAE,EAAE;YAC/C,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;gBACxC,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,MAAM,CAAC,CAAC;gBAChB,OAAO;YACT,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YACpC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBACd,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;iBAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBACrB,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;iBAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC;gBACvD,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC;iBAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC;gBACvD,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC;iBAAM,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;gBAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;YAChE,CAAC;QACH,CAAC,CAAC;QAEF,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,4EAA4E;AAC5E,4EAA4E;AAC5E,6EAA6E;AAC7E,sCAAsC;AAEtC,IAAI,MAAM,GAA8B,IAAI,CAAC;AAC7C,MAAM,SAAS,GAAa,EAAE,CAAC;AAC/B,MAAM,OAAO,GAAyC,EAAE,CAAC;AAEzD,SAAS,gBAAgB;IACvB,IAAI,MAAM;QAAE,OAAO;IACnB,MAAM,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAC5D,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACzB,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,CAAC;;YACpB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACtB,OAAO,OAAO,CAAC,MAAM;YAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY;IACnB,gBAAgB,EAAE,CAAC;IACnB,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;IACjC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,OAAO;IACd,OAAO,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QAClC,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC,CAAC,MAAM;QACxC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACpC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,MAAM,CAAC;QACrC,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,UAAU;IACxB,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { Checklist, RecordedAnswer, Section, SessionResult } from "./types.js";
2
+ export interface SummaryParts {
3
+ flagged: RecordedAnswer[];
4
+ skipped: RecordedAnswer[];
5
+ yes: number;
6
+ no: number;
7
+ }
8
+ /** Print the end-of-session summary to the terminal. Returns the tallied parts. */
9
+ export declare function printSummary(result: SessionResult): SummaryParts;
10
+ /** A default, sortable report filename for the current moment. */
11
+ export declare function defaultReportName(checklist: Checklist, now: Date): string;
12
+ /** Render a Markdown report of the answers, grouped by section. */
13
+ export declare function buildMarkdown(checklist: Checklist, result: SessionResult, now: Date): string;
14
+ /** Write the report to disk, returning the resolved path. */
15
+ export declare function saveReport(filePath: string, content: string): string;
16
+ /** Print a checklist as plain text (for `--list`) without running a session. */
17
+ export declare function printList(checklist: Checklist, sections: Section[]): void;
18
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEpF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,YAAY,CAoChE;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,CAIzE;AAQD,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,CAwD5F;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAIpE;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAazE"}
package/dist/report.js ADDED
@@ -0,0 +1,125 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { bold, dim, gray, green, red, yellow } from "./colors.js";
4
+ /** Print the end-of-session summary to the terminal. Returns the tallied parts. */
5
+ export function printSummary(result) {
6
+ const { answers, aborted } = result;
7
+ const flagged = answers.filter((a) => a.flagged);
8
+ const skipped = answers.filter((a) => a.value === "skip");
9
+ const yes = answers.filter((a) => a.value === "yes").length;
10
+ const no = answers.filter((a) => a.value === "no").length;
11
+ console.log();
12
+ console.log(bold("Summary"));
13
+ if (aborted)
14
+ console.log(dim("(session ended early — these are the answers you gave)"));
15
+ console.log(" " +
16
+ green(`${yes} yes`) + dim(" · ") +
17
+ red(`${no} no`) + dim(" · ") +
18
+ gray(`${skipped.length} skipped`) + dim(" · ") +
19
+ yellow(`${flagged.length} flagged`));
20
+ if (flagged.length) {
21
+ console.log();
22
+ console.log(yellow(bold("⚠ Worth a second look before you start:")));
23
+ for (const a of flagged) {
24
+ console.log(" " + yellow("•") + " " + a.question.text);
25
+ if (a.question.why)
26
+ console.log(" " + dim(a.question.why));
27
+ }
28
+ }
29
+ else if (!aborted) {
30
+ console.log();
31
+ console.log(green("No flags raised — you've thought it through. Go build. ✨"));
32
+ }
33
+ if (skipped.length) {
34
+ console.log();
35
+ console.log(dim(`${skipped.length} skipped — treat those as open questions, not free passes.`));
36
+ }
37
+ return { flagged, skipped, yes, no };
38
+ }
39
+ /** A default, sortable report filename for the current moment. */
40
+ export function defaultReportName(checklist, now) {
41
+ const p = (n) => String(n).padStart(2, "0");
42
+ const stamp = `${now.getFullYear()}${p(now.getMonth() + 1)}${p(now.getDate())}-${p(now.getHours())}${p(now.getMinutes())}`;
43
+ return `think-before-${checklist.id}-${stamp}.md`;
44
+ }
45
+ const MARK = {
46
+ yes: "[x]",
47
+ no: "[ ]",
48
+ skip: "[ ]",
49
+ };
50
+ /** Render a Markdown report of the answers, grouped by section. */
51
+ export function buildMarkdown(checklist, result, now) {
52
+ const { answers, aborted } = result;
53
+ const flagged = answers.filter((a) => a.flagged);
54
+ const skipped = answers.filter((a) => a.value === "skip");
55
+ const yes = answers.filter((a) => a.value === "yes").length;
56
+ const no = answers.filter((a) => a.value === "no").length;
57
+ const lines = [];
58
+ lines.push(`# think-before — ${checklist.title}`);
59
+ lines.push("");
60
+ lines.push(`> Generated ${now.toISOString()}${aborted ? " (session ended early)" : ""}`);
61
+ lines.push("");
62
+ lines.push(`**${yes} yes · ${no} no · ${skipped.length} skipped · ${flagged.length} flagged**`);
63
+ lines.push("");
64
+ if (flagged.length) {
65
+ lines.push("## ⚠ Worth a second look");
66
+ lines.push("");
67
+ for (const a of flagged) {
68
+ lines.push(`- **${a.question.text}** — answered _${a.value}_`);
69
+ if (a.question.why)
70
+ lines.push(` - ${a.question.why}`);
71
+ }
72
+ lines.push("");
73
+ }
74
+ if (skipped.length) {
75
+ lines.push("## ❓ Open questions (skipped)");
76
+ lines.push("");
77
+ for (const a of skipped)
78
+ lines.push(`- ${a.question.text}`);
79
+ lines.push("");
80
+ }
81
+ lines.push("## All answers");
82
+ lines.push("");
83
+ // Group answers back under their section, preserving order.
84
+ const bySection = new Map();
85
+ for (const a of answers) {
86
+ const entry = bySection.get(a.section.id) ?? { section: a.section, items: [] };
87
+ entry.items.push(a);
88
+ bySection.set(a.section.id, entry);
89
+ }
90
+ for (const { section, items } of bySection.values()) {
91
+ lines.push(`### ${section.title}`);
92
+ lines.push("");
93
+ for (const a of items) {
94
+ const flag = a.flagged ? " ⚠" : "";
95
+ const note = a.value === "skip" ? " _(skipped)_" : ` _(${a.value})_`;
96
+ lines.push(`- ${MARK[a.value]} ${a.question.text}${note}${flag}`);
97
+ }
98
+ lines.push("");
99
+ }
100
+ return lines.join("\n");
101
+ }
102
+ /** Write the report to disk, returning the resolved path. */
103
+ export function saveReport(filePath, content) {
104
+ const resolved = path.resolve(process.cwd(), filePath);
105
+ fs.writeFileSync(resolved, content, "utf8");
106
+ return resolved;
107
+ }
108
+ /** Print a checklist as plain text (for `--list`) without running a session. */
109
+ export function printList(checklist, sections) {
110
+ console.log();
111
+ console.log(bold(checklist.title));
112
+ if (checklist.intro)
113
+ console.log(dim(checklist.intro));
114
+ for (const section of sections) {
115
+ console.log();
116
+ console.log(" " + bold(section.title));
117
+ for (const q of section.questions) {
118
+ console.log(" - [ ] " + q.text);
119
+ if (q.why)
120
+ console.log(" " + dim(q.why));
121
+ }
122
+ }
123
+ console.log();
124
+ }
125
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAUlE,mFAAmF;AACnF,MAAM,UAAU,YAAY,CAAC,MAAqB;IAChD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;IAC5D,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;IAE1D,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC7B,IAAI,OAAO;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC,CAAC;IACxF,OAAO,CAAC,GAAG,CACT,IAAI;QACF,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;QAChC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,UAAU,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;QAC9C,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,UAAU,CAAC,CACtC,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC,CAAC,CAAC;QACrE,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACxD,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG;gBAAE,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;SAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,4DAA4D,CAAC,CAAC,CAAC;IAClG,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;AACvC,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,iBAAiB,CAAC,SAAoB,EAAE,GAAS;IAC/D,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;IAC3H,OAAO,gBAAgB,SAAS,CAAC,EAAE,IAAI,KAAK,KAAK,CAAC;AACpD,CAAC;AAED,MAAM,IAAI,GAA4C;IACpD,GAAG,EAAE,KAAK;IACV,EAAE,EAAE,KAAK;IACT,IAAI,EAAE,KAAK;CACZ,CAAC;AAEF,mEAAmE;AACnE,MAAM,UAAU,aAAa,CAAC,SAAoB,EAAE,MAAqB,EAAE,GAAS;IAClF,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;IAC5D,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;IAE1D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,oBAAoB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;IAClD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,WAAW,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CACR,KAAK,GAAG,UAAU,EAAE,SAAS,OAAO,CAAC,MAAM,cAAc,OAAO,CAAC,MAAM,YAAY,CACpF,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;YAC/D,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,4DAA4D;IAC5D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAyD,CAAC;IACnF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC/E,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;IACD,KAAK,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,CAAC;YACrE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,OAAe;IAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IACvD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,SAAS,CAAC,SAAoB,EAAE,QAAmB;IACjE,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACnC,IAAI,SAAS,CAAC,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACvD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;YACnC,IAAI,CAAC,CAAC,GAAG;gBAAE,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Checklist, Role, Section, SessionResult } from "./types.js";
2
+ /** Pick the sections relevant to a role. With no role, every section is shown. */
3
+ export declare function filterSections(checklist: Checklist, role?: Role): Section[];
4
+ /** Run a checklist interactively over the given sections, collecting answers. */
5
+ export declare function runSession(checklist: Checklist, sections: Section[]): Promise<SessionResult>;
6
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,SAAS,EAAkB,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvG,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,OAAO,EAAE,CAG3E;AAaD,iFAAiF;AACjF,wBAAsB,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAiClG"}
@@ -0,0 +1,63 @@
1
+ import { askYesNo } from "./prompt.js";
2
+ import { bold, cyan, dim, gray, green, red, yellow } from "./colors.js";
3
+ /** Pick the sections relevant to a role. With no role, every section is shown. */
4
+ export function filterSections(checklist, role) {
5
+ if (!role)
6
+ return checklist.sections;
7
+ return checklist.sections.filter((s) => s.roles.includes("shared") || s.roles.includes(role));
8
+ }
9
+ function keyHint() {
10
+ return (dim("Answer fast — ") +
11
+ cyan("y") + dim(" yes · ") +
12
+ cyan("n") + dim(" no · ") +
13
+ cyan("s") + dim(" skip · ") +
14
+ cyan("?") + dim(" why · ") +
15
+ cyan("q") + dim(" quit"));
16
+ }
17
+ /** Run a checklist interactively over the given sections, collecting answers. */
18
+ export async function runSession(checklist, sections) {
19
+ const answers = [];
20
+ const total = sections.reduce((n, s) => n + s.questions.length, 0);
21
+ let i = 0;
22
+ let aborted = false;
23
+ console.log();
24
+ console.log(bold(checklist.title));
25
+ if (checklist.intro)
26
+ console.log(dim(checklist.intro));
27
+ console.log(keyHint());
28
+ outer: for (const section of sections) {
29
+ console.log();
30
+ console.log(" " + bold(section.title));
31
+ for (const q of section.questions) {
32
+ i++;
33
+ const counter = gray(` ${String(i).padStart(2, " ")}/${total}`);
34
+ process.stdout.write(`${counter} ${q.text} ${dim("[y/n/s] ")}`);
35
+ const ans = await askYesNo(q.why);
36
+ if (ans === "quit") {
37
+ aborted = true;
38
+ process.stdout.write("\n");
39
+ break outer;
40
+ }
41
+ const flagged = ans === q.risky;
42
+ answers.push({ question: q, section, value: ans, flagged });
43
+ printResult(ans, flagged, q.why);
44
+ }
45
+ }
46
+ return { answers, aborted };
47
+ }
48
+ function printResult(ans, flagged, why) {
49
+ let label;
50
+ if (ans === "yes")
51
+ label = green("✓ yes");
52
+ else if (ans === "no")
53
+ label = red("✗ no");
54
+ else
55
+ label = gray("– skip");
56
+ let line = label;
57
+ if (flagged)
58
+ line += " " + yellow("⚠ worth a second look");
59
+ console.log(" " + line);
60
+ if (flagged && why)
61
+ console.log(" " + dim("↳ " + why));
62
+ }
63
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /** Which answer to a question should raise a flag / warrant a second thought. */
2
+ export type RiskyAnswer = "yes" | "no";
3
+ /** A single yes/no reflection prompt. */
4
+ export interface Question {
5
+ /** Stable, kebab-case identifier (used in reports). */
6
+ id: string;
7
+ /** The question, phrased so that "yes" / "no" is a meaningful answer. */
8
+ text: string;
9
+ /** The answer that should be flagged as "worth a second look". */
10
+ risky: RiskyAnswer;
11
+ /** Why this matters — shown on `?` during a session and next to flags in the report. */
12
+ why?: string;
13
+ }
14
+ /** Roles a section applies to. `shared` sections are always shown. */
15
+ export type Role = "shared" | "designer" | "engineer" | "developer";
16
+ /** A titled group of related questions. */
17
+ export interface Section {
18
+ id: string;
19
+ title: string;
20
+ /** Roles this section is relevant to. Include `"shared"` to always show it. */
21
+ roles: Role[];
22
+ questions: Question[];
23
+ }
24
+ /** A named, runnable set of sections. */
25
+ export interface Checklist {
26
+ id: string;
27
+ title: string;
28
+ intro?: string;
29
+ sections: Section[];
30
+ }
31
+ /** A user's answer to one question. */
32
+ export type AnswerValue = "yes" | "no" | "skip";
33
+ /** A recorded answer plus the context needed to report on it. */
34
+ export interface RecordedAnswer {
35
+ question: Question;
36
+ section: Section;
37
+ value: AnswerValue;
38
+ /** True when `value` matches the question's `risky` answer. */
39
+ flagged: boolean;
40
+ }
41
+ /** The outcome of running a session. */
42
+ export interface SessionResult {
43
+ answers: RecordedAnswer[];
44
+ /** True if the user quit before answering every question. */
45
+ aborted: boolean;
46
+ }
47
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,IAAI,CAAC;AAEvC,yCAAyC;AACzC,MAAM,WAAW,QAAQ;IACvB,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,KAAK,EAAE,WAAW,CAAC;IACnB,wFAAwF;IACxF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,sEAAsE;AACtE,MAAM,MAAM,IAAI,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;AAEpE,2CAA2C;AAC3C,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,uCAAuC;AACvC,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;AAEhD,iEAAiE;AACjE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,+DAA+D;IAC/D,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,6DAA6D;IAC7D,OAAO,EAAE,OAAO,CAAC;CAClB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@geekyants/think-before",
3
+ "version": "0.1.0",
4
+ "description": "A fast yes/no reflection CLI to surface the side-effects of a change before you make it. Think before you touch the big app.",
5
+ "type": "module",
6
+ "bin": {
7
+ "think-before": "dist/cli.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "engines": {
17
+ "node": ">=18"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "dev": "npm run build && node dist/cli.js",
22
+ "start": "node dist/cli.js",
23
+ "prepublishOnly": "npm run build",
24
+ "clean": "rm -rf dist"
25
+ },
26
+ "keywords": [
27
+ "checklist",
28
+ "cli",
29
+ "reflection",
30
+ "premortem",
31
+ "code-review",
32
+ "side-effects",
33
+ "blast-radius",
34
+ "developer-tools",
35
+ "discovery",
36
+ "yes-no"
37
+ ],
38
+ "author": "GeekyAnts",
39
+ "license": "MIT",
40
+ "homepage": "https://geekyants.com",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/GeekyAnts/think-before.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/GeekyAnts/think-before/issues"
47
+ },
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^22.10.0",
53
+ "typescript": "^5.7.0"
54
+ }
55
+ }