@doquflow/cli 1.6.0 → 2.0.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,144 @@
1
+ "use strict";
2
+ /**
3
+ * docuflow query
4
+ *
5
+ * Calls query_wiki and renders the answer with citations.
6
+ *
7
+ * Usage:
8
+ * docuflow query "<question>"
9
+ * docuflow query "<question>" --max-sources 5
10
+ * docuflow query "<question>" --json
11
+ * docuflow query "<question>" --no-cite
12
+ * docuflow query "<question>" --save-as "<title>"
13
+ * docuflow query "<question>" --quiet
14
+ *
15
+ * Exit codes:
16
+ * 0 — answer produced
17
+ * 2 — fatal (.docuflow missing, server tool not found)
18
+ * 3 — query produced no matching sources
19
+ */
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.run = run;
25
+ const node_fs_1 = __importDefault(require("node:fs"));
26
+ const node_path_1 = __importDefault(require("node:path"));
27
+ // ─── Colour helpers ────────────────────────────────────────────────────────────
28
+ const c = {
29
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
30
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
31
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
32
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
33
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
34
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
35
+ };
36
+ // ─── Dynamic server tool loader (mirrors rewiki.ts pattern) ───────────────────
37
+ function loadServerTool(toolFile) {
38
+ const candidates = [
39
+ () => require(`@doquflow/core/dist/tools/${toolFile}`),
40
+ () => require(node_path_1.default.resolve(__dirname, "../../../core/dist/tools", toolFile)),
41
+ () => require(node_path_1.default.resolve(__dirname, "../../core/dist/tools", toolFile)),
42
+ () => require(`@doquflow/studio/dist/tools/${toolFile}`),
43
+ () => require(node_path_1.default.resolve(__dirname, "../../../studio/dist/tools", toolFile)),
44
+ () => require(node_path_1.default.resolve(__dirname, "../../studio/dist/tools", toolFile)),
45
+ ];
46
+ for (const attempt of candidates) {
47
+ try {
48
+ return attempt();
49
+ }
50
+ catch { }
51
+ }
52
+ throw new Error(`Cannot load server tool "${toolFile}". Run "npm run build" first.`);
53
+ }
54
+ async function run(options) {
55
+ const { question, maxSources = 5, json = false, noCite = false, saveAs, quiet = false } = options;
56
+ const projectPath = node_path_1.default.resolve(process.cwd());
57
+ const docuDir = node_path_1.default.join(projectPath, ".docuflow");
58
+ function info(msg) { if (!quiet)
59
+ console.log(msg); }
60
+ // ── Validate question ───────────────────────────────────────────────────────
61
+ if (!question || question.trim() === "") {
62
+ console.error(c.red(" ✗ Question is required."));
63
+ console.error(` Usage: docuflow query "<question>"`);
64
+ process.exit(2);
65
+ }
66
+ // ── Pre-flight ──────────────────────────────────────────────────────────────
67
+ if (!node_fs_1.default.existsSync(docuDir)) {
68
+ console.error(c.red(` ✗ .docuflow/ not found at ${projectPath}`));
69
+ console.error(` Run "docuflow init" first.`);
70
+ process.exit(2);
71
+ }
72
+ // ── Load tools ──────────────────────────────────────────────────────────────
73
+ let queryWiki;
74
+ let saveAnswerAsPage;
75
+ try {
76
+ ({ queryWiki } = loadServerTool("query-wiki"));
77
+ if (saveAs) {
78
+ ({ saveAnswerAsPage } = loadServerTool("save-answer-as-page"));
79
+ }
80
+ }
81
+ catch (e) {
82
+ console.error(c.red(` ✗ ${e.message}`));
83
+ process.exit(2);
84
+ }
85
+ // ── Execute query ───────────────────────────────────────────────────────────
86
+ info(c.dim(` Searching wiki for: "${question}"`));
87
+ let result;
88
+ try {
89
+ result = await queryWiki({ project_path: projectPath, question, max_sources: maxSources });
90
+ }
91
+ catch (e) {
92
+ console.error(c.red(` ✗ Query failed: ${e.message}`));
93
+ process.exit(2);
94
+ }
95
+ if (result.error) {
96
+ console.error(c.red(` ✗ ${result.error}`));
97
+ process.exit(2);
98
+ }
99
+ // ── No sources found ────────────────────────────────────────────────────────
100
+ if (!result.source_pages || result.source_pages.length === 0) {
101
+ if (!json) {
102
+ console.error(c.yellow(" No matching sources found in the wiki."));
103
+ console.error(` Try running "docuflow rewiki" to rebuild the wiki first.`);
104
+ }
105
+ process.exit(3);
106
+ }
107
+ // ── Output ──────────────────────────────────────────────────────────────────
108
+ if (json) {
109
+ console.log(JSON.stringify({
110
+ question: result.question,
111
+ answer: result.answer,
112
+ source_pages: result.source_pages,
113
+ search_results: result.search_results,
114
+ confidence: result.confidence,
115
+ }, null, 2));
116
+ }
117
+ else if (noCite) {
118
+ console.log(result.answer);
119
+ }
120
+ else {
121
+ console.log(result.answer);
122
+ console.log("");
123
+ console.log(c.bold("## Sources"));
124
+ for (const page of result.source_pages) {
125
+ console.log(` - ${page.title} ${c.dim("(" + page.page_id + ")")}`);
126
+ }
127
+ }
128
+ // ── Save ────────────────────────────────────────────────────────────────────
129
+ if (saveAs && saveAnswerAsPage) {
130
+ try {
131
+ const saved = await saveAnswerAsPage({
132
+ project_path: projectPath,
133
+ question,
134
+ answer: result.answer,
135
+ page_title: saveAs,
136
+ source_page_ids: (result.source_pages ?? []).map((p) => p.page_id),
137
+ });
138
+ process.stderr.write(`page-id: ${saved?.page_id ?? saveAs}\n`);
139
+ }
140
+ catch (e) {
141
+ process.stderr.write(c.red(`Warning: could not save page: ${e.message}\n`));
142
+ }
143
+ }
144
+ }
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * docuflow recent
4
4
  *
5
- * Aggregates recent work by scanning .devloop/specs/TASK-*.md files,
6
- * correlating git commits by task ID, reading .docuflow/log.md for wiki
7
- * activity, and rendering a formatted dashboard in the terminal.
5
+ * Shows a dashboard of recent activity:
6
+ * - Recent git commits (last N days)
7
+ * - Recent wiki activity from .docuflow/log.md
8
8
  */
9
9
  var __importDefault = (this && this.__importDefault) || function (mod) {
10
10
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -14,106 +14,27 @@ exports.run = run;
14
14
  const promises_1 = __importDefault(require("node:fs/promises"));
15
15
  const node_path_1 = __importDefault(require("node:path"));
16
16
  const node_child_process_1 = require("node:child_process");
17
- // ── ANSI helpers ────────────────────────────────────────────────────────────
17
+ // ── ANSI helpers ──────────────────────────────────────────────────────────────
18
18
  const c = {
19
- green: (s) => `\x1b[32m${s}\x1b[0m`,
20
- yellow: (s) => `\x1b[33m${s}\x1b[0m`,
21
- red: (s) => `\x1b[31m${s}\x1b[0m`,
22
19
  dim: (s) => `\x1b[2m${s}\x1b[0m`,
23
20
  bold: (s) => `\x1b[1m${s}\x1b[0m`,
21
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
24
22
  };
25
- function colourStatus(status, text) {
26
- if (status === "approved")
27
- return c.green(text);
28
- if (status === "needs-work")
29
- return c.yellow(text);
30
- if (status === "rejected")
31
- return c.red(text);
32
- return c.dim(text);
33
- }
34
- function normaliseStatus(raw) {
35
- // Strip emojis (✅ ⚠️ ⏳ ❌) and other non-printable/non-ASCII characters
36
- const stripped = raw.replace(/[^\x20-\x7E]/g, " ").trim().toLowerCase();
37
- if (stripped.includes("approved"))
38
- return "approved";
39
- if (stripped.includes("needs-work") || stripped.includes("needs_work"))
40
- return "needs-work";
41
- if (stripped.includes("rejected"))
42
- return "rejected";
43
- if (stripped.includes("pending"))
44
- return "pending";
45
- return stripped.split(/\s+/)[0] || "pending";
46
- }
47
- function truncate(s, max) {
48
- return s.length > max ? s.slice(0, max - 1) + "…" : s;
49
- }
50
23
  function formatDateYMD(d) {
51
24
  return d.toISOString().slice(0, 10);
52
25
  }
53
- // ── Git helper ───────────────────────────────────────────────────────────────
54
- function gitLog(taskId) {
26
+ // ── Git commits (recent, date-filtered) ──────────────────────────────────────
27
+ function recentCommits(days) {
55
28
  try {
56
- const out = (0, node_child_process_1.execSync)(`git log --oneline --all --grep="${taskId}"`, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] });
29
+ const out = (0, node_child_process_1.execSync)(`git log --oneline --since="${days} days ago"`, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] });
57
30
  return out.trim().split("\n").filter(Boolean);
58
31
  }
59
32
  catch {
60
33
  return [];
61
34
  }
62
35
  }
63
- // ── Spec parser ───────────────────────────────────────────────────────────────
64
- async function parseSpec(specPath) {
65
- let content;
66
- try {
67
- content = await promises_1.default.readFile(specPath, "utf8");
68
- }
69
- catch {
70
- return {};
71
- }
72
- let title = "";
73
- let feature = "";
74
- let status = "pending";
75
- for (const line of content.split("\n")) {
76
- // First H1 heading: "# TASK-YYYYMMDD-HHMMSS: <title>"
77
- if (!title && line.startsWith("# TASK-")) {
78
- const colonIdx = line.indexOf(":");
79
- if (colonIdx !== -1) {
80
- title = line.slice(colonIdx + 1).trim();
81
- }
82
- }
83
- // **Feature**: value
84
- if (!feature && line.startsWith("**Feature**:")) {
85
- feature = line.slice("**Feature**:".length).trim().slice(0, 120).trimEnd();
86
- }
87
- // **Status**: value
88
- if (line.startsWith("**Status**:")) {
89
- const raw = line.slice("**Status**:".length).trim();
90
- status = normaliseStatus(raw);
91
- }
92
- }
93
- return { title, feature, status };
94
- }
95
- // ── Review parser ────────────────────────────────────────────────────────────
96
- async function parseReview(reviewPath) {
97
- let content;
98
- try {
99
- content = await promises_1.default.readFile(reviewPath, "utf8");
100
- }
101
- catch {
102
- return { score: null, reviewVerdict: null };
103
- }
104
- let score = null;
105
- let reviewVerdict = null;
106
- const scoreMatch = content.match(/Score:\s*(\d+\/\d+)/);
107
- if (scoreMatch)
108
- score = scoreMatch[1];
109
- const verdictMatch = content.match(/Verdict:\s*(APPROVED|NEEDS[\s_]WORK|REJECTED)/i);
110
- if (verdictMatch) {
111
- reviewVerdict = verdictMatch[1].toUpperCase().replace(/[\s-]+/g, "_");
112
- }
113
- return { score, reviewVerdict };
114
- }
115
- // ── Wiki log parser ──────────────────────────────────────────────────────────
116
- // log.md format: ## [2026-05-01T13:49:38.141Z] operation | description
36
+ // ── Wiki log parsing ──────────────────────────────────────────────────────────
37
+ const headingRe = /^##\s+\[([^\]]+)\]\s+([^|]+?)(?:\s*\|\s*(.+))?$/;
117
38
  async function parseWikiLog(logPath, since) {
118
39
  let content;
119
40
  try {
@@ -123,73 +44,80 @@ async function parseWikiLog(logPath, since) {
123
44
  return [];
124
45
  }
125
46
  const entries = [];
126
- const headingRe = /^##\s+\[([^\]]+)\]\s+([^|]+)\|\s*(.+)$/;
127
47
  for (const line of content.split("\n")) {
128
- const m = line.match(headingRe);
129
- if (!m)
48
+ const m = headingRe.exec(line.trim());
49
+ if (!m) {
50
+ // Legacy pipe-delimited: timestamp | tool | target | delta
51
+ const parts = line.split("|").map(p => p.trim());
52
+ if (parts.length >= 3 && parts[0].includes("T")) {
53
+ const d = new Date(parts[0]);
54
+ if (!isNaN(d.getTime()) && d >= since) {
55
+ entries.push({ date: formatDateYMD(d), operation: parts[1] ?? "", file: parts[2] ?? "" });
56
+ }
57
+ }
130
58
  continue;
131
- const rawDate = m[1].trim();
132
- const operation = m[2].trim();
133
- const file = m[3].trim();
134
- const dateVal = new Date(rawDate);
135
- if (!isNaN(dateVal.getTime()) && dateVal >= since) {
136
- entries.push({ date: rawDate.slice(0, 10), operation, file });
137
59
  }
60
+ const d = new Date(m[1]);
61
+ if (isNaN(d.getTime()) || d < since)
62
+ continue;
63
+ entries.push({ date: formatDateYMD(d), operation: (m[2] ?? "").trim(), file: (m[3] ?? "").trim() });
138
64
  }
139
65
  return entries;
140
66
  }
141
- // ── Renderers ────────────────────────────────────────────────────────────────
142
- function renderTable(tasks, allCommits, wikiEntries, days, fromDate, toDate) {
143
- const SEP = "─".repeat(72);
144
- console.log(c.bold(`Recent Work last ${days} days (${fromDate} → ${toDate})`));
145
- console.log(SEP);
146
- console.log(` ${"TASK".padEnd(24)} ${"TITLE".padEnd(40)} ${"STATUS".padEnd(12)} SCORE`);
147
- console.log(SEP);
148
- for (const t of tasks) {
149
- const title = truncate(t.title || t.feature, 40).padEnd(40);
150
- const status = t.status.padEnd(12);
151
- const score = t.score ?? "—";
152
- const row = ` ${t.id.padEnd(24)} ${title} ${status} ${score}`;
153
- console.log(colourStatus(t.status, row));
67
+ // ── Renderers ─────────────────────────────────────────────────────────────────
68
+ function renderTable(commits, wikiEntries, days) {
69
+ const fromDate = formatDateYMD(new Date(Date.now() - days * 86400000));
70
+ const toDate = formatDateYMD(new Date());
71
+ console.log("");
72
+ console.log(c.bold(`DocuFlow — Recent Activity (${fromDate} ${toDate})`));
73
+ console.log("");
74
+ console.log(c.bold(`Git Commits (last ${days} days)`));
75
+ console.log("─".repeat(60));
76
+ if (commits.length === 0) {
77
+ console.log(c.dim(" No commits in this period."));
154
78
  }
155
- console.log(SEP);
156
- if (allCommits.length > 0) {
157
- console.log("");
158
- console.log(c.bold(`Git Commits (${allCommits.length} matching)`));
159
- for (const line of allCommits) {
160
- console.log(` ${line}`);
79
+ else {
80
+ for (const line of commits) {
81
+ const sha = line.slice(0, 7);
82
+ const msg = line.slice(8);
83
+ console.log(` ${c.cyan(sha)} ${msg}`);
161
84
  }
162
85
  }
163
- if (wikiEntries.length > 0) {
164
- console.log("");
165
- console.log(c.bold(`Wiki Activity (last ${days} days)`));
86
+ console.log("");
87
+ console.log(c.bold(`Wiki Activity (last ${days} days)`));
88
+ console.log("─".repeat(60));
89
+ if (wikiEntries.length === 0) {
90
+ console.log(c.dim(" No wiki activity in this period."));
91
+ }
92
+ else {
166
93
  for (const e of wikiEntries) {
167
- console.log(` ${e.date} ${e.operation} ${e.file}`);
94
+ console.log(` ${c.dim(e.date)} ${e.operation}${e.file ? " " + c.dim(e.file) : ""}`);
168
95
  }
169
96
  }
97
+ console.log("");
170
98
  }
171
- function renderMarkdown(tasks, allCommits, wikiEntries, days, fromDate, toDate) {
172
- console.log(`# Recent Work last ${days} days (${fromDate} → ${toDate})`);
99
+ function renderMarkdown(commits, wikiEntries, days) {
100
+ const fromDate = formatDateYMD(new Date(Date.now() - days * 86400000));
101
+ const toDate = formatDateYMD(new Date());
102
+ console.log(`# DocuFlow — Recent Activity (${fromDate} → ${toDate})`);
103
+ console.log("");
104
+ console.log(`## Git Commits (last ${days} days)`);
173
105
  console.log("");
174
- console.log("| TASK | TITLE | STATUS | SCORE |");
175
- console.log("|------|-------|--------|-------|");
176
- for (const t of tasks) {
177
- const title = truncate(t.title || t.feature, 40);
178
- const score = t.score ?? "—";
179
- console.log(`| ${t.id} | ${title} | ${t.status} | ${score} |`);
106
+ if (commits.length === 0) {
107
+ console.log("_No commits in this period._");
180
108
  }
181
- if (allCommits.length > 0) {
182
- console.log("");
183
- console.log(`## Git Commits (${allCommits.length} matching)`);
184
- console.log("");
185
- for (const line of allCommits) {
109
+ else {
110
+ for (const line of commits) {
186
111
  console.log(`- ${line}`);
187
112
  }
188
113
  }
189
- if (wikiEntries.length > 0) {
190
- console.log("");
191
- console.log(`## Wiki Activity (last ${days} days)`);
192
- console.log("");
114
+ console.log("");
115
+ console.log(`## Wiki Activity (last ${days} days)`);
116
+ console.log("");
117
+ if (wikiEntries.length === 0) {
118
+ console.log("_No wiki activity in this period._");
119
+ }
120
+ else {
193
121
  console.log("| Date | Operation | File |");
194
122
  console.log("|------|-----------|------|");
195
123
  for (const e of wikiEntries) {
@@ -197,80 +125,19 @@ function renderMarkdown(tasks, allCommits, wikiEntries, days, fromDate, toDate)
197
125
  }
198
126
  }
199
127
  }
200
- // ── Main entry point ─────────────────────────────────────────────────────────
128
+ // ── Main entry point ──────────────────────────────────────────────────────────
201
129
  async function run(opts = { days: 7, format: "table" }) {
202
130
  const days = Math.max(1, isNaN(opts.days) ? 7 : opts.days);
203
131
  const format = opts.format ?? "table";
204
- const isMd = format === "md";
205
132
  const cwd = process.cwd();
206
- const specsDir = node_path_1.default.join(cwd, ".devloop", "specs");
207
133
  const logPath = node_path_1.default.join(cwd, ".docuflow", "log.md");
208
- const now = new Date();
209
- const since = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
210
- // Collect spec files
211
- let specFiles = [];
212
- try {
213
- const entries = await promises_1.default.readdir(specsDir);
214
- specFiles = entries
215
- .filter(f => /^TASK-\d{8}-\d{6}\.md$/.test(f))
216
- .map(f => node_path_1.default.join(specsDir, f));
217
- }
218
- catch {
219
- console.log(`No tasks found in the last ${days} days.`);
220
- return;
221
- }
222
- // Filter by mtime and parse each spec
223
- const tasks = [];
224
- for (const specPath of specFiles) {
225
- let stat;
226
- try {
227
- stat = await promises_1.default.stat(specPath);
228
- }
229
- catch {
230
- continue;
231
- }
232
- if (stat.mtime < since)
233
- continue;
234
- const stem = node_path_1.default.basename(specPath, ".md"); // TASK-YYYYMMDD-HHMMSS
235
- const specFields = await parseSpec(specPath);
236
- if (!specFields.title && !specFields.feature)
237
- continue; // unreadable
238
- const reviewPath = node_path_1.default.join(specsDir, `${stem}-review.md`);
239
- const { score, reviewVerdict } = await parseReview(reviewPath);
240
- // Override status from review verdict if present
241
- let status = specFields.status ?? "pending";
242
- if (reviewVerdict === "APPROVED")
243
- status = "approved";
244
- else if (reviewVerdict === "NEEDS_WORK")
245
- status = "needs-work";
246
- else if (reviewVerdict === "REJECTED")
247
- status = "rejected";
248
- const commits = gitLog(stem);
249
- tasks.push({
250
- id: stem,
251
- title: specFields.title ?? "",
252
- feature: specFields.feature ?? "",
253
- status,
254
- score,
255
- reviewVerdict,
256
- commits,
257
- specMtime: stat.mtime,
258
- });
259
- }
260
- // Sort newest first
261
- tasks.sort((a, b) => b.specMtime.getTime() - a.specMtime.getTime());
262
- if (tasks.length === 0) {
263
- console.log(`No tasks found in the last ${days} days.`);
264
- return;
265
- }
266
- const fromDate = formatDateYMD(since);
267
- const toDate = formatDateYMD(now);
268
- const allCommits = tasks.flatMap(t => t.commits);
134
+ const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
135
+ const commits = recentCommits(days);
269
136
  const wikiEntries = await parseWikiLog(logPath, since);
270
- if (isMd) {
271
- renderMarkdown(tasks, allCommits, wikiEntries, days, fromDate, toDate);
137
+ if (format === "md") {
138
+ renderMarkdown(commits, wikiEntries, days);
272
139
  }
273
140
  else {
274
- renderTable(tasks, allCommits, wikiEntries, days, fromDate, toDate);
141
+ renderTable(commits, wikiEntries, days);
275
142
  }
276
143
  }
@@ -36,9 +36,12 @@ const c = {
36
36
  // ─── Dynamic server tool loader (mirrors sync.ts pattern) ─────────────────────
37
37
  function loadServerTool(toolFile) {
38
38
  const candidates = [
39
- () => require(`@doquflow/server/dist/tools/${toolFile}`),
40
- () => require(node_path_1.default.resolve(__dirname, "../../../server/dist/tools", toolFile)),
41
- () => require(node_path_1.default.resolve(__dirname, "../../server/dist/tools", toolFile)),
39
+ () => require(`@doquflow/core/dist/tools/${toolFile}`),
40
+ () => require(node_path_1.default.resolve(__dirname, "../../../core/dist/tools", toolFile)),
41
+ () => require(node_path_1.default.resolve(__dirname, "../../core/dist/tools", toolFile)),
42
+ () => require(`@doquflow/studio/dist/tools/${toolFile}`),
43
+ () => require(node_path_1.default.resolve(__dirname, "../../../studio/dist/tools", toolFile)),
44
+ () => require(node_path_1.default.resolve(__dirname, "../../studio/dist/tools", toolFile)),
42
45
  ];
43
46
  for (const attempt of candidates) {
44
47
  try {
@@ -39,9 +39,14 @@ const c = {
39
39
  // ─── Dynamic server tool loader ────────────────────────────────────────────────
40
40
  function loadServerTool(toolFile) {
41
41
  const candidates = [
42
- () => require(`@doquflow/server/dist/tools/${toolFile}`),
43
- () => require(node_path_1.default.resolve(__dirname, "../../../server/dist/tools", toolFile)),
44
- () => require(node_path_1.default.resolve(__dirname, "../../server/dist/tools", toolFile)),
42
+ // v2.0 — 4 core tools live in @doquflow/core
43
+ () => require(`@doquflow/core/dist/tools/${toolFile}`),
44
+ () => require(node_path_1.default.resolve(__dirname, "../../../core/dist/tools", toolFile)),
45
+ () => require(node_path_1.default.resolve(__dirname, "../../core/dist/tools", toolFile)),
46
+ // v2.0 — 11 advanced tools live in @doquflow/studio
47
+ () => require(`@doquflow/studio/dist/tools/${toolFile}`),
48
+ () => require(node_path_1.default.resolve(__dirname, "../../../studio/dist/tools", toolFile)),
49
+ () => require(node_path_1.default.resolve(__dirname, "../../studio/dist/tools", toolFile)),
45
50
  ];
46
51
  for (const attempt of candidates) {
47
52
  try {
@@ -135,10 +140,10 @@ function runClaudeSync(prompt, projectPath, allowDangerousPermissions = false) {
135
140
  // Build the MCP config pointing to the local server binary
136
141
  let serverBin;
137
142
  try {
138
- serverBin = require.resolve("@doquflow/server/dist/index.js");
143
+ serverBin = require.resolve("@doquflow/studio/dist/mcp/index.js");
139
144
  }
140
145
  catch {
141
- serverBin = node_path_1.default.resolve(__dirname, "../../server/dist/index.js");
146
+ serverBin = node_path_1.default.resolve(__dirname, "../../studio/dist/mcp/index.js");
142
147
  }
143
148
  const mcpConfig = JSON.stringify({
144
149
  mcpServers: {
@@ -27,7 +27,7 @@ const init_1 = require("./init");
27
27
  const watch_1 = require("./watch");
28
28
  function loadTool(file, exportName) {
29
29
  // eslint-disable-next-line @typescript-eslint/no-require-imports
30
- return require(`@doquflow/server/dist/tools/${file}`)[exportName];
30
+ return require(`@doquflow/studio/dist/tools/${file}`)[exportName];
31
31
  }
32
32
  // ── Helpers ───────────────────────────────────────────────────────────────────
33
33
  async function findDocuflowProjects(scanRoot) {
@@ -102,7 +102,7 @@ async function run(opts = {}) {
102
102
  process.exit(result.status ?? 1);
103
103
  }
104
104
  console.log(`\n✓ Updated to ${latest}.`);
105
- console.log(` This refreshed the CLI, bundled UI (ui-dist), and the @doquflow/server dependency.`);
105
+ console.log(` This refreshed the CLI, bundled UI (ui-dist), and the @doquflow/core + @doquflow/studio dependencies.`);
106
106
  const stale = await isPortInUse(DEFAULT_PORT);
107
107
  if (stale) {
108
108
  console.log('');
@@ -54,9 +54,12 @@ const node_child_process_1 = require("node:child_process");
54
54
  // ─── Dynamic server tool loader ────────────────────────────────────────────────
55
55
  function loadServerTool(toolFile) {
56
56
  const candidates = [
57
- () => require(`@doquflow/server/dist/tools/${toolFile}`),
58
- () => require(node_path_1.default.resolve(__dirname, "../../../server/dist/tools", toolFile)),
59
- () => require(node_path_1.default.resolve(__dirname, "../../server/dist/tools", toolFile)),
57
+ () => require(`@doquflow/core/dist/tools/${toolFile}`),
58
+ () => require(node_path_1.default.resolve(__dirname, "../../../core/dist/tools", toolFile)),
59
+ () => require(node_path_1.default.resolve(__dirname, "../../core/dist/tools", toolFile)),
60
+ () => require(`@doquflow/studio/dist/tools/${toolFile}`),
61
+ () => require(node_path_1.default.resolve(__dirname, "../../../studio/dist/tools", toolFile)),
62
+ () => require(node_path_1.default.resolve(__dirname, "../../studio/dist/tools", toolFile)),
60
63
  ];
61
64
  for (const attempt of candidates) {
62
65
  try {
@@ -202,10 +205,10 @@ let _allowDangerousPermissions = false;
202
205
  function runClaudeCLI(prompt, timeoutMs = 120_000) {
203
206
  let serverBin;
204
207
  try {
205
- serverBin = require.resolve("@doquflow/server/dist/index.js");
208
+ serverBin = require.resolve("@doquflow/studio/dist/mcp/index.js");
206
209
  }
207
210
  catch {
208
- serverBin = node_path_1.default.resolve(__dirname, "../../server/dist/index.js");
211
+ serverBin = node_path_1.default.resolve(__dirname, "../../studio/dist/mcp/index.js");
209
212
  }
210
213
  const mcpConfig = JSON.stringify({
211
214
  mcpServers: { docuflow: { type: "stdio", command: process.execPath, args: [serverBin] } }