intentdocs 0.8.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.
@@ -0,0 +1,79 @@
1
+ // src/lib/prompt.ts
2
+ import { createInterface } from "readline";
3
+ var rl = null;
4
+ function getRL() {
5
+ if (!rl) {
6
+ rl = createInterface({
7
+ input: process.stdin,
8
+ output: process.stdout
9
+ });
10
+ }
11
+ return rl;
12
+ }
13
+ function ask(question) {
14
+ return new Promise((resolve) => {
15
+ getRL().question(question, (answer) => {
16
+ resolve(answer.trim());
17
+ });
18
+ });
19
+ }
20
+ function askMultiline(question) {
21
+ console.log(question);
22
+ console.log(" (Press Enter twice to finish)\n");
23
+ return new Promise((resolve) => {
24
+ const lines = [];
25
+ let emptyCount = 0;
26
+ const handler = (line) => {
27
+ if (line === "") {
28
+ emptyCount++;
29
+ if (emptyCount >= 2) {
30
+ process.stdin.removeListener("line", handler);
31
+ resolve(lines.join("\n").trim());
32
+ return;
33
+ }
34
+ } else {
35
+ emptyCount = 0;
36
+ }
37
+ lines.push(line);
38
+ };
39
+ process.stdin.on("line", handler);
40
+ });
41
+ }
42
+ async function confirm(question) {
43
+ const answer = await ask(`${question} (y/n) `);
44
+ return answer.toLowerCase().startsWith("y");
45
+ }
46
+ async function choose(question, options) {
47
+ console.log(`
48
+ ${question}
49
+ `);
50
+ for (let i = 0; i < options.length; i++) {
51
+ console.log(` ${i + 1}. ${options[i]}`);
52
+ }
53
+ const answer = await ask(`
54
+ Choice (1-${options.length}): `);
55
+ const idx = parseInt(answer, 10) - 1;
56
+ if (idx < 0 || idx >= options.length) return 0;
57
+ return idx;
58
+ }
59
+ function closePrompt() {
60
+ if (rl) {
61
+ rl.close();
62
+ rl = null;
63
+ }
64
+ }
65
+ function pausePrompt() {
66
+ if (rl) {
67
+ rl.close();
68
+ rl = null;
69
+ }
70
+ }
71
+
72
+ export {
73
+ ask,
74
+ askMultiline,
75
+ confirm,
76
+ choose,
77
+ closePrompt,
78
+ pausePrompt
79
+ };
@@ -0,0 +1,79 @@
1
+ import {
2
+ isPlanGated,
3
+ printUpgradeMessage
4
+ } from "./chunk-ITQUQYWB.js";
5
+ import {
6
+ apiUrl,
7
+ listStories
8
+ } from "./chunk-6XKB6RTU.js";
9
+ import {
10
+ requireConfig
11
+ } from "./chunk-ICOMMHKG.js";
12
+ import "./chunk-PCNDP5SX.js";
13
+
14
+ // src/commands/complexity.ts
15
+ import ora from "ora";
16
+ async function complexity(storyId) {
17
+ const config = requireConfig();
18
+ const spinner = ora(" Analyzing complexity...").start();
19
+ try {
20
+ const data = await listStories(config);
21
+ let storyIds;
22
+ if (storyId) {
23
+ const match = data.stories.find((s) => s.id.startsWith(storyId));
24
+ if (!match) {
25
+ spinner.fail(` No story found matching "${storyId}"`);
26
+ return;
27
+ }
28
+ storyIds = [match.id];
29
+ } else {
30
+ storyIds = data.stories.filter((s) => s.status !== "done").map((s) => s.id);
31
+ }
32
+ if (!storyIds.length) {
33
+ spinner.succeed(" No stories to analyze \u2014 all done!");
34
+ return;
35
+ }
36
+ const res = await fetch(apiUrl(config, "/complexity"), {
37
+ method: "POST",
38
+ headers: { "Content-Type": "application/json" },
39
+ body: JSON.stringify({ story_ids: storyIds })
40
+ });
41
+ if (!res.ok) {
42
+ if (isPlanGated(res.status)) {
43
+ spinner.fail(" Complexity analysis is not available on your plan");
44
+ printUpgradeMessage();
45
+ return;
46
+ }
47
+ spinner.fail(" Complexity analysis failed");
48
+ return;
49
+ }
50
+ const result = await res.json();
51
+ spinner.succeed(` Analyzed ${result.stories.length} stories
52
+ `);
53
+ const sorted = result.stories.sort((a, b) => b.complexity - a.complexity);
54
+ for (const s of sorted) {
55
+ const bar = "\u2588".repeat(s.complexity) + "\u2591".repeat(10 - s.complexity);
56
+ const color = s.complexity >= 8 ? "\x1B[31m" : s.complexity >= 5 ? "\x1B[33m" : "\x1B[32m";
57
+ const reset = "\x1B[0m";
58
+ console.log(` ${color}${bar}${reset} ${s.complexity}/10 ${s.title}`);
59
+ console.log(` ${s.reasoning}`);
60
+ if (s.risks?.length) {
61
+ console.log(` \u26A0 ${s.risks.join(", ")}`);
62
+ }
63
+ console.log(` Suggested effort: ${s.suggested_effort}
64
+ `);
65
+ }
66
+ const avg = sorted.reduce((a, s) => a + s.complexity, 0) / sorted.length;
67
+ const high = sorted.filter((s) => s.complexity >= 7).length;
68
+ console.log(` \u2500\u2500 Summary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
69
+ console.log(` Average complexity: ${avg.toFixed(1)}/10`);
70
+ console.log(` High complexity (7+): ${high} stories`);
71
+ console.log(` Total analyzed: ${sorted.length}
72
+ `);
73
+ } catch (err) {
74
+ spinner.fail(` Error: ${err.message}`);
75
+ }
76
+ }
77
+ export {
78
+ complexity
79
+ };
@@ -0,0 +1,134 @@
1
+ import {
2
+ closePrompt,
3
+ confirm
4
+ } from "./chunk-WPVDURTJ.js";
5
+ import {
6
+ isPlanGated,
7
+ printUpgradeMessage
8
+ } from "./chunk-ITQUQYWB.js";
9
+ import {
10
+ apiUrl
11
+ } from "./chunk-6XKB6RTU.js";
12
+ import {
13
+ requireConfig
14
+ } from "./chunk-ICOMMHKG.js";
15
+ import "./chunk-PCNDP5SX.js";
16
+
17
+ // src/commands/import-prd.ts
18
+ import { readFileSync, existsSync } from "fs";
19
+ import ora from "ora";
20
+ async function importPrd(filePath) {
21
+ const config = requireConfig();
22
+ let prdText;
23
+ let format = "PRD";
24
+ if (filePath) {
25
+ if (!existsSync(filePath)) {
26
+ console.error(` File not found: ${filePath}`);
27
+ return;
28
+ }
29
+ prdText = readFileSync(filePath, "utf-8");
30
+ if (filePath.endsWith(".md")) format = "Markdown";
31
+ else if (filePath.endsWith(".txt")) format = "text";
32
+ } else {
33
+ console.log(" Paste your PRD below (press Ctrl+D when done):\n");
34
+ const chunks = [];
35
+ for await (const chunk of process.stdin) {
36
+ chunks.push(chunk);
37
+ }
38
+ prdText = Buffer.concat(chunks).toString("utf-8");
39
+ }
40
+ if (!prdText.trim()) {
41
+ console.error(" No content to import.");
42
+ return;
43
+ }
44
+ console.log(`
45
+ Importing ${format} (${prdText.length} chars)...
46
+ `);
47
+ const spinner = ora(" Parsing into story map...").start();
48
+ try {
49
+ const res = await fetch(apiUrl(config, "/import"), {
50
+ method: "POST",
51
+ headers: { "Content-Type": "application/json" },
52
+ body: JSON.stringify({ prd: prdText, format })
53
+ });
54
+ if (!res.ok) {
55
+ if (isPlanGated(res.status)) {
56
+ spinner.fail(" PRD import is not available on your plan");
57
+ printUpgradeMessage();
58
+ return;
59
+ }
60
+ spinner.fail(" Import failed");
61
+ const errText = await res.text();
62
+ console.error(` ${errText.slice(0, 200)}`);
63
+ return;
64
+ }
65
+ const result = await res.json();
66
+ spinner.succeed(
67
+ ` Parsed ${result.summary.activities} activities, ${result.summary.steps} steps, ${result.summary.stories} stories, ${result.summary.acceptance_criteria} acceptance criteria
68
+ `
69
+ );
70
+ for (const activity of result.hierarchy.activities) {
71
+ console.log(` \x1B[1m${activity.title}\x1B[0m`);
72
+ for (const step of activity.steps) {
73
+ console.log(` \u2514\u2500 ${step.title}`);
74
+ for (const story of step.stories) {
75
+ const priorityColor = story.priority === "must" ? "\x1B[31m" : story.priority === "should" ? "\x1B[33m" : "\x1B[32m";
76
+ const reset = "\x1B[0m";
77
+ console.log(` ${priorityColor}[${story.priority}]${reset} ${story.title} (${story.effort})`);
78
+ if (story.acceptance_criteria?.length) {
79
+ for (const ac of story.acceptance_criteria) {
80
+ console.log(` \u2713 ${ac}`);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ console.log();
86
+ }
87
+ const doImport = await confirm(
88
+ ` Import this story map structure?`
89
+ );
90
+ if (doImport) {
91
+ const importSpinner = ora(" Creating story map...").start();
92
+ const backbone = result.hierarchy.activities.map((activity) => ({
93
+ activity: activity.title,
94
+ tasks: activity.steps.map((step) => ({
95
+ task: step.title,
96
+ stories: step.stories.map((story) => ({
97
+ story: story.title,
98
+ acceptance_criteria: story.acceptance_criteria,
99
+ priority: story.priority,
100
+ effort: story.effort
101
+ }))
102
+ }))
103
+ }));
104
+ const createRes = await fetch(apiUrl(config, "/map-import"), {
105
+ method: "POST",
106
+ headers: { "Content-Type": "application/json" },
107
+ body: JSON.stringify({
108
+ schema_version: "1.0",
109
+ source: "prd-import",
110
+ backbone
111
+ })
112
+ });
113
+ if (createRes.ok) {
114
+ const createResult = await createRes.json();
115
+ importSpinner.succeed(
116
+ ` \u2713 Created ${createResult.activities} activities, ${createResult.steps} steps, ${createResult.stories} stories
117
+ `
118
+ );
119
+ } else {
120
+ importSpinner.fail(" Failed to create story map");
121
+ const errText = await createRes.text();
122
+ console.error(` ${errText.slice(0, 200)}`);
123
+ }
124
+ } else {
125
+ console.log(" Import cancelled.\n");
126
+ }
127
+ closePrompt();
128
+ } catch (err) {
129
+ spinner.fail(` Error: ${err.message}`);
130
+ }
131
+ }
132
+ export {
133
+ importPrd
134
+ };