rrce-workflow 0.3.10 → 0.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +717 -830
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2708,10 +2708,6 @@ function getExposedProjects() {
2708
2708
  }
2709
2709
  return potentialProjects.filter((project) => isProjectExposed(config, project.name, project.sourcePath || project.path));
2710
2710
  }
2711
- function getRAGIndexPath(project) {
2712
- const scanRoot = project.path || project.dataPath;
2713
- return path17.join(project.knowledgePath || path17.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
2714
- }
2715
2711
  function getCodeIndexPath(project) {
2716
2712
  const scanRoot = project.path || project.dataPath;
2717
2713
  return path17.join(project.knowledgePath || path17.join(scanRoot, ".rrce-workflow", "knowledge"), "code-embeddings.json");
@@ -4217,242 +4213,13 @@ var Header;
4217
4213
  var init_Header = __esm({
4218
4214
  "src/mcp/ui/Header.tsx"() {
4219
4215
  "use strict";
4220
- Header = () => /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingBottom: 1, children: /* @__PURE__ */ jsx(Box, { borderStyle: "double", borderColor: "cyan", paddingX: 2, justifyContent: "center", children: /* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: " RRCE MCP Hub " }) }) });
4221
- }
4222
- });
4223
-
4224
- // src/mcp/ui/Overview.tsx
4225
- import { useMemo } from "react";
4226
- import { Box as Box2, Text as Text2 } from "ink";
4227
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
4228
- var Overview;
4229
- var init_Overview = __esm({
4230
- "src/mcp/ui/Overview.tsx"() {
4231
- "use strict";
4232
- init_Header();
4233
- init_prompts2();
4234
- Overview = ({ serverStatus, stats }) => {
4235
- const agents = useMemo(() => getAllPrompts(), []);
4236
- return /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", flexGrow: 1, children: [
4237
- /* @__PURE__ */ jsx2(Header, {}),
4238
- /* @__PURE__ */ jsxs(Box2, { borderStyle: "round", padding: 1, borderColor: "white", flexDirection: "column", flexGrow: 1, children: [
4239
- /* @__PURE__ */ jsxs(Box2, { justifyContent: "space-between", children: [
4240
- /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", children: [
4241
- /* @__PURE__ */ jsx2(Text2, { bold: true, underline: true, children: "System Status" }),
4242
- /* @__PURE__ */ jsxs(Box2, { marginTop: 1, children: [
4243
- /* @__PURE__ */ jsx2(Text2, { children: "Integrations Installed: " }),
4244
- /* @__PURE__ */ jsx2(Text2, { color: stats.installedIntegrations > 0 ? "green" : "yellow", children: stats.installedIntegrations })
4245
- ] }),
4246
- /* @__PURE__ */ jsxs(Box2, { children: [
4247
- /* @__PURE__ */ jsx2(Text2, { children: "Server Port: " }),
4248
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: serverStatus.port })
4249
- ] })
4250
- ] }),
4251
- /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", marginLeft: 4, children: [
4252
- /* @__PURE__ */ jsx2(Text2, { bold: true, underline: true, children: "Quick Start" }),
4253
- /* @__PURE__ */ jsxs(Box2, { marginTop: 1, flexDirection: "column", children: [
4254
- /* @__PURE__ */ jsx2(Text2, { children: '1. Install "MCP" extension in VSCode / Antigravity' }),
4255
- /* @__PURE__ */ jsx2(Text2, { children: "2. Configure Extension to use this server:" }),
4256
- /* @__PURE__ */ jsx2(Text2, { color: "dim", children: " (This is handled automatically by 'Install to IDE')" }),
4257
- /* @__PURE__ */ jsx2(Text2, { children: "3. In your Agent IDE, ask:" }),
4258
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: ' "Use the rrce tools to analyze this project"' })
4259
- ] })
4260
- ] })
4261
- ] }),
4262
- /* @__PURE__ */ jsxs(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
4263
- /* @__PURE__ */ jsx2(Text2, { bold: true, children: "Available Agents & Instructions:" }),
4264
- agents.map((agent) => /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", marginTop: 1, children: [
4265
- /* @__PURE__ */ jsxs(Text2, { color: "yellow", children: [
4266
- "\u27A4 ",
4267
- agent.name,
4268
- " ",
4269
- /* @__PURE__ */ jsxs(Text2, { color: "dim", children: [
4270
- "(",
4271
- agent.id,
4272
- ")"
4273
- ] })
4274
- ] }),
4275
- /* @__PURE__ */ jsxs(Text2, { color: "white", children: [
4276
- " ",
4277
- agent.description
4278
- ] }),
4279
- agent.arguments.length > 0 && /* @__PURE__ */ jsxs(Text2, { color: "dim", children: [
4280
- " Args: ",
4281
- agent.arguments.map((a) => a.name + (a.required ? "*" : "")).join(", ")
4282
- ] }),
4283
- /* @__PURE__ */ jsxs(Text2, { color: "cyan", children: [
4284
- ' Instruction: "Use the ',
4285
- agent.name,
4286
- ' to..."'
4287
- ] })
4288
- ] }, agent.id))
4289
- ] }),
4290
- /* @__PURE__ */ jsxs(Box2, { marginTop: 1, flexDirection: "column", children: [
4291
- /* @__PURE__ */ jsx2(Text2, { color: "dim", children: "Controls:" }),
4292
- /* @__PURE__ */ jsx2(Text2, { color: "dim", children: " \u2022 Press 'r' to restart server" }),
4293
- /* @__PURE__ */ jsx2(Text2, { color: "dim", children: " \u2022 Use 1-4 or \u25C4/\u25BA to navigate tabs" }),
4294
- /* @__PURE__ */ jsx2(Text2, { color: "dim", children: " \u2022 Press 'q' to stop server and exit" })
4295
- ] })
4296
- ] })
4297
- ] });
4298
- };
4299
- }
4300
- });
4301
-
4302
- // src/mcp/ui/components/SimpleSelect.tsx
4303
- import { useState } from "react";
4304
- import { Box as Box3, Text as Text3, useInput } from "ink";
4305
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
4306
- function SimpleSelect({
4307
- items,
4308
- onSelect,
4309
- isMulti = false,
4310
- initialSelected = [],
4311
- onSubmit,
4312
- onCancel,
4313
- message
4314
- }) {
4315
- const [selectedIndex, setSelectedIndex] = useState(0);
4316
- const [selectedValues, setSelectedValues] = useState(new Set(initialSelected));
4317
- useInput((input, key) => {
4318
- if (key.upArrow) {
4319
- setSelectedIndex((prev) => prev > 0 ? prev - 1 : items.length - 1);
4320
- }
4321
- if (key.downArrow) {
4322
- setSelectedIndex((prev) => prev < items.length - 1 ? prev + 1 : 0);
4323
- }
4324
- if (input === " " && isMulti) {
4325
- const item = items[selectedIndex];
4326
- if (item) {
4327
- const newSet = new Set(selectedValues);
4328
- if (newSet.has(item.value)) {
4329
- newSet.delete(item.value);
4330
- } else {
4331
- newSet.add(item.value);
4332
- }
4333
- setSelectedValues(newSet);
4334
- }
4335
- }
4336
- if (key.return) {
4337
- if (isMulti) {
4338
- onSubmit?.(Array.from(selectedValues));
4339
- } else {
4340
- const item = items[selectedIndex];
4341
- if (item) onSelect(item);
4342
- }
4343
- }
4344
- if (key.escape) {
4345
- onCancel?.();
4346
- }
4347
- });
4348
- return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, children: [
4349
- message && /* @__PURE__ */ jsx3(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsx3(Text3, { bold: true, children: message }) }),
4350
- items.map((item, index) => {
4351
- const isSelected = index === selectedIndex;
4352
- const isChecked = isMulti && selectedValues.has(item.value);
4353
- return /* @__PURE__ */ jsxs2(Box3, { children: [
4354
- /* @__PURE__ */ jsx3(Text3, { color: isSelected ? "cyan" : "white", children: isSelected ? "> " : " " }),
4355
- isMulti && /* @__PURE__ */ jsx3(Text3, { color: isChecked ? "green" : "gray", children: isChecked ? "[x] " : "[ ] " }),
4356
- /* @__PURE__ */ jsx3(Text3, { color: isSelected ? "cyan" : "white", children: item.label })
4357
- ] }, item.key || String(item.value));
4358
- }),
4359
- /* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text3, { color: "gray", children: isMulti ? "Space to toggle, Enter to confirm, Esc to cancel" : "Enter to select, Esc to cancel" }) })
4360
- ] });
4361
- }
4362
- var init_SimpleSelect = __esm({
4363
- "src/mcp/ui/components/SimpleSelect.tsx"() {
4364
- "use strict";
4216
+ Header = () => /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingBottom: 1, children: /* @__PURE__ */ jsx(Box, { borderStyle: "double", borderColor: "white", paddingX: 2, justifyContent: "center", children: /* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: " RRCE MCP Hub " }) }) });
4365
4217
  }
4366
4218
  });
4367
4219
 
4368
- // src/mcp/ui/lib/tasks-fs.ts
4220
+ // src/lib/drift-service.ts
4369
4221
  import * as fs17 from "fs";
4370
4222
  import * as path19 from "path";
4371
- function detectStorageModeFromConfig(workspaceRoot) {
4372
- const configPath = getConfigPath(workspaceRoot);
4373
- try {
4374
- const rrceHome = getEffectiveGlobalBase();
4375
- if (configPath.startsWith(rrceHome)) {
4376
- return "global";
4377
- }
4378
- if (fs17.existsSync(configPath)) {
4379
- const content = fs17.readFileSync(configPath, "utf-8");
4380
- if (content.includes("mode: workspace")) return "workspace";
4381
- if (content.includes("mode: global")) return "global";
4382
- }
4383
- } catch {
4384
- }
4385
- return "global";
4386
- }
4387
- function getEffectiveGlobalBase() {
4388
- const dummy = resolveDataPath("global", "__rrce_dummy__", "");
4389
- return path19.dirname(path19.dirname(dummy));
4390
- }
4391
- function getProjectRRCEData(project) {
4392
- const workspaceRoot = project.sourcePath || project.path;
4393
- const mode = detectStorageModeFromConfig(workspaceRoot);
4394
- return resolveDataPath(mode, project.name, workspaceRoot);
4395
- }
4396
- function listProjectTasks(project) {
4397
- const rrceData = getProjectRRCEData(project);
4398
- const tasksPath = path19.join(rrceData, "tasks");
4399
- if (!fs17.existsSync(tasksPath)) {
4400
- return { projectName: project.name, tasksPath, tasks: [] };
4401
- }
4402
- const tasks = [];
4403
- try {
4404
- const entries = fs17.readdirSync(tasksPath, { withFileTypes: true });
4405
- for (const entry of entries) {
4406
- if (!entry.isDirectory()) continue;
4407
- const metaPath = path19.join(tasksPath, entry.name, "meta.json");
4408
- if (!fs17.existsSync(metaPath)) continue;
4409
- try {
4410
- const raw = fs17.readFileSync(metaPath, "utf-8");
4411
- const meta = JSON.parse(raw);
4412
- if (!meta.task_slug) meta.task_slug = entry.name;
4413
- tasks.push(meta);
4414
- } catch {
4415
- }
4416
- }
4417
- } catch {
4418
- }
4419
- tasks.sort((a, b) => {
4420
- const aTime = Date.parse(a.updated_at || a.created_at || "") || 0;
4421
- const bTime = Date.parse(b.updated_at || b.created_at || "") || 0;
4422
- if (aTime !== bTime) return bTime - aTime;
4423
- return String(a.task_slug).localeCompare(String(b.task_slug));
4424
- });
4425
- return { projectName: project.name, tasksPath, tasks };
4426
- }
4427
- function updateTaskStatus(project, taskSlug, status) {
4428
- const rrceData = getProjectRRCEData(project);
4429
- const metaPath = path19.join(rrceData, "tasks", taskSlug, "meta.json");
4430
- if (!fs17.existsSync(metaPath)) {
4431
- return { ok: false, error: `meta.json not found for task '${taskSlug}'` };
4432
- }
4433
- try {
4434
- const meta = JSON.parse(fs17.readFileSync(metaPath, "utf-8"));
4435
- const next = {
4436
- ...meta,
4437
- status,
4438
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
4439
- };
4440
- fs17.writeFileSync(metaPath, JSON.stringify(next, null, 2));
4441
- return { ok: true, meta: next };
4442
- } catch (e) {
4443
- return { ok: false, error: String(e) };
4444
- }
4445
- }
4446
- var init_tasks_fs = __esm({
4447
- "src/mcp/ui/lib/tasks-fs.ts"() {
4448
- "use strict";
4449
- init_paths();
4450
- }
4451
- });
4452
-
4453
- // src/lib/drift-service.ts
4454
- import * as fs18 from "fs";
4455
- import * as path20 from "path";
4456
4223
  import * as crypto2 from "crypto";
4457
4224
  var DriftService;
4458
4225
  var init_drift_service = __esm({
@@ -4461,26 +4228,26 @@ var init_drift_service = __esm({
4461
4228
  DriftService = class {
4462
4229
  static CHECKSUM_FILENAME = ".rrce-checksums.json";
4463
4230
  static calculateHash(filePath) {
4464
- const content = fs18.readFileSync(filePath);
4231
+ const content = fs17.readFileSync(filePath);
4465
4232
  return crypto2.createHash("md5").update(content).digest("hex");
4466
4233
  }
4467
4234
  static getManifestPath(projectPath) {
4468
- return path20.join(projectPath, this.CHECKSUM_FILENAME);
4235
+ return path19.join(projectPath, this.CHECKSUM_FILENAME);
4469
4236
  }
4470
4237
  static loadManifest(projectPath) {
4471
4238
  const manifestPath = this.getManifestPath(projectPath);
4472
- if (!fs18.existsSync(manifestPath)) {
4239
+ if (!fs17.existsSync(manifestPath)) {
4473
4240
  return {};
4474
4241
  }
4475
4242
  try {
4476
- return JSON.parse(fs18.readFileSync(manifestPath, "utf8"));
4243
+ return JSON.parse(fs17.readFileSync(manifestPath, "utf8"));
4477
4244
  } catch (e) {
4478
4245
  return {};
4479
4246
  }
4480
4247
  }
4481
4248
  static saveManifest(projectPath, manifest) {
4482
4249
  const manifestPath = this.getManifestPath(projectPath);
4483
- fs18.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
4250
+ fs17.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
4484
4251
  }
4485
4252
  /**
4486
4253
  * Generates a manifest for the current state of files in the project
@@ -4488,9 +4255,9 @@ var init_drift_service = __esm({
4488
4255
  static generateManifest(projectPath, files) {
4489
4256
  const manifest = {};
4490
4257
  for (const file of files) {
4491
- const fullPath = path20.join(projectPath, file);
4492
- if (fs18.existsSync(fullPath)) {
4493
- const stats = fs18.statSync(fullPath);
4258
+ const fullPath = path19.join(projectPath, file);
4259
+ if (fs17.existsSync(fullPath)) {
4260
+ const stats = fs17.statSync(fullPath);
4494
4261
  manifest[file] = {
4495
4262
  hash: this.calculateHash(fullPath),
4496
4263
  mtime: stats.mtimeMs
@@ -4506,11 +4273,11 @@ var init_drift_service = __esm({
4506
4273
  const manifest = this.loadManifest(projectPath);
4507
4274
  const modifiedFiles = [];
4508
4275
  for (const [relPath, entry] of Object.entries(manifest)) {
4509
- const fullPath = path20.join(projectPath, relPath);
4510
- if (!fs18.existsSync(fullPath)) {
4276
+ const fullPath = path19.join(projectPath, relPath);
4277
+ if (!fs17.existsSync(fullPath)) {
4511
4278
  continue;
4512
4279
  }
4513
- const stats = fs18.statSync(fullPath);
4280
+ const stats = fs17.statSync(fullPath);
4514
4281
  if (stats.mtimeMs === entry.mtime) {
4515
4282
  continue;
4516
4283
  }
@@ -4556,16 +4323,16 @@ __export(ConfigContext_exports, {
4556
4323
  ConfigProvider: () => ConfigProvider,
4557
4324
  useConfig: () => useConfig
4558
4325
  });
4559
- import { createContext, useContext, useState as useState2, useCallback, useMemo as useMemo2, useEffect as useEffect2 } from "react";
4560
- import * as fs19 from "fs";
4561
- import * as path21 from "path";
4562
- import { jsx as jsx4 } from "react/jsx-runtime";
4326
+ import { createContext, useContext, useState, useCallback, useMemo, useEffect } from "react";
4327
+ import * as fs18 from "fs";
4328
+ import * as path20 from "path";
4329
+ import { jsx as jsx2 } from "react/jsx-runtime";
4563
4330
  function getPackageVersion() {
4564
4331
  try {
4565
4332
  const agentCoreDir = getAgentCoreDir();
4566
- const packageJsonPath = path21.join(path21.dirname(agentCoreDir), "package.json");
4567
- if (fs19.existsSync(packageJsonPath)) {
4568
- return JSON.parse(fs19.readFileSync(packageJsonPath, "utf8")).version;
4333
+ const packageJsonPath = path20.join(path20.dirname(agentCoreDir), "package.json");
4334
+ if (fs18.existsSync(packageJsonPath)) {
4335
+ return JSON.parse(fs18.readFileSync(packageJsonPath, "utf8")).version;
4569
4336
  }
4570
4337
  } catch (e) {
4571
4338
  }
@@ -4589,9 +4356,9 @@ var init_ConfigContext = __esm({
4589
4356
  init_prompts();
4590
4357
  ConfigContext = createContext(null);
4591
4358
  ConfigProvider = ({ children }) => {
4592
- const [config, setConfig] = useState2(() => loadMCPConfig());
4593
- const [projects, setProjects] = useState2(() => scanForProjects());
4594
- const [driftReports, setDriftReports] = useState2({});
4359
+ const [config, setConfig] = useState(() => loadMCPConfig());
4360
+ const [projects, setProjects] = useState(() => scanForProjects());
4361
+ const [driftReports, setDriftReports] = useState({});
4595
4362
  const refresh = useCallback(() => {
4596
4363
  const newConfig = loadMCPConfig();
4597
4364
  const newProjects = scanForProjects();
@@ -4608,17 +4375,17 @@ var init_ConfigContext = __esm({
4608
4375
  }
4609
4376
  setDriftReports(reports);
4610
4377
  }, [projects, config]);
4611
- useEffect2(() => {
4378
+ useEffect(() => {
4612
4379
  checkAllDrift();
4613
4380
  }, [checkAllDrift]);
4614
- const exposedProjects = useMemo2(
4381
+ const exposedProjects = useMemo(
4615
4382
  () => projects.filter((p) => {
4616
4383
  const cfg = findProjectConfig(config, { name: p.name, path: p.path });
4617
4384
  return cfg?.expose ?? config.defaults.includeNew;
4618
4385
  }),
4619
4386
  [projects, config]
4620
4387
  );
4621
- const value = useMemo2(() => ({
4388
+ const value = useMemo(() => ({
4622
4389
  config,
4623
4390
  projects,
4624
4391
  exposedProjects,
@@ -4626,208 +4393,381 @@ var init_ConfigContext = __esm({
4626
4393
  refresh,
4627
4394
  checkAllDrift
4628
4395
  }), [config, projects, exposedProjects, driftReports, refresh, checkAllDrift]);
4629
- return /* @__PURE__ */ jsx4(ConfigContext.Provider, { value, children });
4396
+ return /* @__PURE__ */ jsx2(ConfigContext.Provider, { value, children });
4630
4397
  };
4631
4398
  }
4632
4399
  });
4633
4400
 
4634
- // src/mcp/ui/ui-helpers.ts
4635
- var getStatusIcon, getStatusColor, getChecklistProgress, getCheckbox, getProgressBar, getFolderIcon;
4636
- var init_ui_helpers = __esm({
4637
- "src/mcp/ui/ui-helpers.ts"() {
4638
- "use strict";
4639
- getStatusIcon = (status) => {
4640
- const icons = {
4641
- pending: "\u23F3",
4642
- in_progress: "\u{1F504}",
4643
- blocked: "\u{1F6AB}",
4644
- complete: "\u2705"
4645
- };
4646
- return icons[status] || "\u25CB";
4647
- };
4648
- getStatusColor = (status) => {
4649
- const colors = {
4650
- pending: "yellow",
4651
- in_progress: "yellow",
4652
- blocked: "red",
4653
- complete: "green"
4654
- };
4655
- return colors[status] || "white";
4656
- };
4657
- getChecklistProgress = (checklist) => {
4658
- if (!checklist || checklist.length === 0) {
4659
- return { completed: 0, total: 0, percentage: 0 };
4660
- }
4661
- const completed = checklist.filter((item) => item.status === "done").length;
4662
- return {
4663
- completed,
4664
- total: checklist.length,
4665
- percentage: Math.round(completed / checklist.length * 100)
4666
- };
4667
- };
4668
- getCheckbox = (status) => {
4669
- return status === "done" ? "\u2611" : "\u2610";
4670
- };
4671
- getProgressBar = (percentage, length = 10) => {
4672
- const filled = Math.floor(percentage / 100 * length);
4673
- const empty = length - filled;
4674
- return "\u2588".repeat(filled) + "\u2591".repeat(empty);
4675
- };
4676
- getFolderIcon = (isOpen) => {
4677
- return isOpen ? "\u{1F4C2}" : "\u{1F4C1}";
4678
- };
4401
+ // src/mcp/ui/lib/tasks-fs.ts
4402
+ import * as fs19 from "fs";
4403
+ import * as path21 from "path";
4404
+ function detectStorageModeFromConfig(workspaceRoot) {
4405
+ const configPath = getConfigPath(workspaceRoot);
4406
+ try {
4407
+ const rrceHome = getEffectiveGlobalBase();
4408
+ if (configPath.startsWith(rrceHome)) {
4409
+ return "global";
4410
+ }
4411
+ if (fs19.existsSync(configPath)) {
4412
+ const content = fs19.readFileSync(configPath, "utf-8");
4413
+ if (content.includes("mode: workspace")) return "workspace";
4414
+ if (content.includes("mode: global")) return "global";
4415
+ }
4416
+ } catch {
4679
4417
  }
4680
- });
4681
-
4682
- // src/mcp/ui/ProjectsView.tsx
4683
- import { useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
4684
- import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
4685
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
4686
- function nextStatus(current) {
4687
- const idx = STATUS_CYCLE.indexOf(current || "");
4688
- if (idx === -1) return STATUS_CYCLE[0];
4689
- return STATUS_CYCLE[(idx + 1) % STATUS_CYCLE.length];
4418
+ return "global";
4690
4419
  }
4691
- function projectKey(p) {
4692
- return p.sourcePath ?? p.path;
4420
+ function getEffectiveGlobalBase() {
4421
+ const dummy = resolveDataPath("global", "__rrce_dummy__", "");
4422
+ return path21.dirname(path21.dirname(dummy));
4693
4423
  }
4694
- function formatProjectLabel(p, drift) {
4695
- const root = p.sourcePath ?? p.path;
4696
- const label = `${p.name} (${p.source})${root ? ` - ${root}` : ""}`;
4697
- return label;
4424
+ function getProjectRRCEData(project) {
4425
+ const workspaceRoot = project.sourcePath || project.path;
4426
+ const mode = detectStorageModeFromConfig(workspaceRoot);
4427
+ return resolveDataPath(mode, project.name, workspaceRoot);
4698
4428
  }
4699
- var STATUS_CYCLE, ProjectsView;
4700
- var init_ProjectsView = __esm({
4701
- "src/mcp/ui/ProjectsView.tsx"() {
4702
- "use strict";
4703
- init_SimpleSelect();
4704
- init_config();
4705
- init_tasks_fs();
4706
- init_ConfigContext();
4707
- init_ui_helpers();
4708
- STATUS_CYCLE = ["pending", "in_progress", "blocked", "complete"];
4709
- ProjectsView = ({ config: initialConfig, projects: allProjects, onConfigChange }) => {
4429
+ function listProjectTasks(project) {
4430
+ const rrceData = getProjectRRCEData(project);
4431
+ const tasksPath = path21.join(rrceData, "tasks");
4432
+ if (!fs19.existsSync(tasksPath)) {
4433
+ return { projectName: project.name, tasksPath, tasks: [] };
4434
+ }
4435
+ const tasks = [];
4436
+ try {
4437
+ const entries = fs19.readdirSync(tasksPath, { withFileTypes: true });
4438
+ for (const entry of entries) {
4439
+ if (!entry.isDirectory()) continue;
4440
+ const metaPath = path21.join(tasksPath, entry.name, "meta.json");
4441
+ if (!fs19.existsSync(metaPath)) continue;
4442
+ try {
4443
+ const raw = fs19.readFileSync(metaPath, "utf-8");
4444
+ const meta = JSON.parse(raw);
4445
+ if (!meta.task_slug) meta.task_slug = entry.name;
4446
+ tasks.push(meta);
4447
+ } catch {
4448
+ }
4449
+ }
4450
+ } catch {
4451
+ }
4452
+ tasks.sort((a, b) => {
4453
+ const aTime = Date.parse(a.updated_at || a.created_at || "") || 0;
4454
+ const bTime = Date.parse(b.updated_at || b.created_at || "") || 0;
4455
+ if (aTime !== bTime) return bTime - aTime;
4456
+ return String(a.task_slug).localeCompare(String(b.task_slug));
4457
+ });
4458
+ return { projectName: project.name, tasksPath, tasks };
4459
+ }
4460
+ function updateTaskStatus(project, taskSlug, status) {
4461
+ const rrceData = getProjectRRCEData(project);
4462
+ const metaPath = path21.join(rrceData, "tasks", taskSlug, "meta.json");
4463
+ if (!fs19.existsSync(metaPath)) {
4464
+ return { ok: false, error: `meta.json not found for task '${taskSlug}'` };
4465
+ }
4466
+ try {
4467
+ const meta = JSON.parse(fs19.readFileSync(metaPath, "utf-8"));
4468
+ const next = {
4469
+ ...meta,
4470
+ status,
4471
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
4472
+ };
4473
+ fs19.writeFileSync(metaPath, JSON.stringify(next, null, 2));
4474
+ return { ok: true, meta: next };
4475
+ } catch (e) {
4476
+ return { ok: false, error: String(e) };
4477
+ }
4478
+ }
4479
+ var init_tasks_fs = __esm({
4480
+ "src/mcp/ui/lib/tasks-fs.ts"() {
4481
+ "use strict";
4482
+ init_paths();
4483
+ }
4484
+ });
4485
+
4486
+ // src/mcp/ui/Overview.tsx
4487
+ import { useMemo as useMemo2 } from "react";
4488
+ import { Box as Box2, Text as Text2 } from "ink";
4489
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
4490
+ var Overview;
4491
+ var init_Overview = __esm({
4492
+ "src/mcp/ui/Overview.tsx"() {
4493
+ "use strict";
4494
+ init_Header();
4495
+ init_ConfigContext();
4496
+ init_tasks_fs();
4497
+ Overview = ({ serverStatus, stats, logs }) => {
4498
+ const { projects } = useConfig();
4499
+ const activeTasks = useMemo2(() => {
4500
+ const active = [];
4501
+ for (const p of projects) {
4502
+ const { tasks } = listProjectTasks(p);
4503
+ const inProgress = tasks.filter((t) => t.status === "in_progress");
4504
+ for (const t of inProgress) {
4505
+ active.push({ project: p.name, title: t.title || t.task_slug, slug: t.task_slug });
4506
+ }
4507
+ }
4508
+ return active;
4509
+ }, [projects]);
4510
+ const recentLogs = useMemo2(() => {
4511
+ return logs.slice(-5).reverse();
4512
+ }, [logs]);
4513
+ return /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", flexGrow: 1, children: [
4514
+ /* @__PURE__ */ jsx3(Header, {}),
4515
+ /* @__PURE__ */ jsxs(Box2, { borderStyle: "round", paddingX: 1, borderColor: "white", flexDirection: "column", flexGrow: 1, children: [
4516
+ /* @__PURE__ */ jsxs(Box2, { justifyContent: "space-between", children: [
4517
+ /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", width: "50%", children: [
4518
+ /* @__PURE__ */ jsx3(Text2, { bold: true, color: "cyan", children: "\u{1F680} System Cockpit" }),
4519
+ /* @__PURE__ */ jsxs(Box2, { marginTop: 1, children: [
4520
+ /* @__PURE__ */ jsx3(Text2, { children: "Integrations: " }),
4521
+ /* @__PURE__ */ jsxs(Text2, { color: stats.installedIntegrations > 0 ? "green" : "yellow", children: [
4522
+ stats.installedIntegrations,
4523
+ " active"
4524
+ ] })
4525
+ ] }),
4526
+ /* @__PURE__ */ jsxs(Box2, { children: [
4527
+ /* @__PURE__ */ jsx3(Text2, { children: "MCP Server: " }),
4528
+ /* @__PURE__ */ jsx3(Text2, { color: "green", children: "Running" }),
4529
+ /* @__PURE__ */ jsxs(Text2, { color: "dim", children: [
4530
+ " (Port: ",
4531
+ serverStatus.port,
4532
+ ")"
4533
+ ] })
4534
+ ] }),
4535
+ /* @__PURE__ */ jsxs(Box2, { children: [
4536
+ /* @__PURE__ */ jsx3(Text2, { children: "Projects: " }),
4537
+ /* @__PURE__ */ jsxs(Text2, { children: [
4538
+ stats.exposedProjects,
4539
+ " / ",
4540
+ stats.totalProjects,
4541
+ " exposed"
4542
+ ] })
4543
+ ] })
4544
+ ] }),
4545
+ /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", width: "50%", paddingLeft: 2, children: [
4546
+ /* @__PURE__ */ jsx3(Text2, { bold: true, color: "magenta", children: "\u26A1 Slash Commands" }),
4547
+ /* @__PURE__ */ jsxs(Box2, { marginTop: 1, flexDirection: "column", children: [
4548
+ /* @__PURE__ */ jsxs(Text2, { color: "cyan", children: [
4549
+ "/rrce_init ",
4550
+ /* @__PURE__ */ jsx3(Text2, { color: "dim", children: "- Setup workspace" })
4551
+ ] }),
4552
+ /* @__PURE__ */ jsxs(Text2, { color: "cyan", children: [
4553
+ "/rrce_research ",
4554
+ /* @__PURE__ */ jsx3(Text2, { color: "dim", children: "- Clarify requirements" })
4555
+ ] }),
4556
+ /* @__PURE__ */ jsxs(Text2, { color: "cyan", children: [
4557
+ "/rrce_plan ",
4558
+ /* @__PURE__ */ jsx3(Text2, { color: "dim", children: "- Generate plan" })
4559
+ ] }),
4560
+ /* @__PURE__ */ jsxs(Text2, { color: "cyan", children: [
4561
+ "/rrce_execute ",
4562
+ /* @__PURE__ */ jsx3(Text2, { color: "dim", children: "- Run executor" })
4563
+ ] })
4564
+ ] })
4565
+ ] })
4566
+ ] }),
4567
+ /* @__PURE__ */ jsxs(Box2, { marginTop: 1, borderStyle: "single", borderColor: "blue", flexDirection: "column", paddingX: 1, children: [
4568
+ /* @__PURE__ */ jsx3(Text2, { bold: true, color: "blue", children: "\u{1F3C3} Active Tasks" }),
4569
+ activeTasks.length === 0 ? /* @__PURE__ */ jsx3(Box2, { paddingY: 1, children: /* @__PURE__ */ jsx3(Text2, { color: "dim", children: "No tasks currently in progress." }) }) : activeTasks.slice(0, 3).map((t, i) => /* @__PURE__ */ jsxs(Box2, { marginTop: i === 0 ? 0 : 0, children: [
4570
+ /* @__PURE__ */ jsxs(Text2, { color: "yellow", children: [
4571
+ "\u{1F504} ",
4572
+ t.project,
4573
+ ": "
4574
+ ] }),
4575
+ /* @__PURE__ */ jsx3(Text2, { children: t.title })
4576
+ ] }, `${t.project}-${t.slug}`)),
4577
+ activeTasks.length > 3 && /* @__PURE__ */ jsxs(Text2, { color: "dim", children: [
4578
+ " ...and ",
4579
+ activeTasks.length - 3,
4580
+ " more"
4581
+ ] })
4582
+ ] }),
4583
+ /* @__PURE__ */ jsxs(Box2, { marginTop: 1, borderStyle: "single", borderColor: "dim", flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
4584
+ /* @__PURE__ */ jsx3(Text2, { bold: true, color: "dim", children: "\u{1F4DC} Recent Activity" }),
4585
+ /* @__PURE__ */ jsx3(Box2, { flexDirection: "column", marginTop: 0, children: recentLogs.length === 0 ? /* @__PURE__ */ jsx3(Text2, { color: "dim", children: "Waiting for activity..." }) : recentLogs.map((log, i) => /* @__PURE__ */ jsx3(Text2, { color: "white", wrap: "truncate-end", children: log.length > 80 ? log.substring(0, 77) + "..." : log }, i)) })
4586
+ ] }),
4587
+ /* @__PURE__ */ jsxs(Box2, { marginTop: 0, justifyContent: "space-between", children: [
4588
+ /* @__PURE__ */ jsx3(Box2, { children: /* @__PURE__ */ jsx3(Text2, { color: "dim", children: "r:Restart q:Quit 1-4/\u25C4 \u25BA:Tabs" }) }),
4589
+ /* @__PURE__ */ jsx3(Box2, { children: /* @__PURE__ */ jsx3(Text2, { color: "dim", children: "RRCE MCP Hub v0.3.7" }) })
4590
+ ] })
4591
+ ] })
4592
+ ] });
4593
+ };
4594
+ }
4595
+ });
4596
+
4597
+ // src/mcp/ui/components/SimpleSelect.tsx
4598
+ import { useState as useState2 } from "react";
4599
+ import { Box as Box3, Text as Text3, useInput } from "ink";
4600
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
4601
+ function SimpleSelect({
4602
+ items,
4603
+ onSelect,
4604
+ isMulti = false,
4605
+ initialSelected = [],
4606
+ onSubmit,
4607
+ onCancel,
4608
+ message
4609
+ }) {
4610
+ const [selectedIndex, setSelectedIndex] = useState2(0);
4611
+ const [selectedValues, setSelectedValues] = useState2(new Set(initialSelected));
4612
+ useInput((input, key) => {
4613
+ if (key.upArrow) {
4614
+ setSelectedIndex((prev) => prev > 0 ? prev - 1 : items.length - 1);
4615
+ }
4616
+ if (key.downArrow) {
4617
+ setSelectedIndex((prev) => prev < items.length - 1 ? prev + 1 : 0);
4618
+ }
4619
+ if (input === " " && isMulti) {
4620
+ const item = items[selectedIndex];
4621
+ if (item) {
4622
+ const newSet = new Set(selectedValues);
4623
+ if (newSet.has(item.value)) {
4624
+ newSet.delete(item.value);
4625
+ } else {
4626
+ newSet.add(item.value);
4627
+ }
4628
+ setSelectedValues(newSet);
4629
+ }
4630
+ }
4631
+ if (key.return) {
4632
+ if (isMulti) {
4633
+ onSubmit?.(Array.from(selectedValues));
4634
+ } else {
4635
+ const item = items[selectedIndex];
4636
+ if (item) onSelect(item);
4637
+ }
4638
+ }
4639
+ if (key.escape) {
4640
+ onCancel?.();
4641
+ }
4642
+ });
4643
+ return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "white", padding: 1, children: [
4644
+ message && /* @__PURE__ */ jsx4(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsx4(Text3, { bold: true, children: message }) }),
4645
+ items.map((item, index) => {
4646
+ const isSelected = index === selectedIndex;
4647
+ const isChecked = isMulti && selectedValues.has(item.value);
4648
+ return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", children: [
4649
+ /* @__PURE__ */ jsxs2(Box3, { children: [
4650
+ /* @__PURE__ */ jsx4(Text3, { color: isSelected ? "cyan" : "white", children: isSelected ? "> " : " " }),
4651
+ isMulti && /* @__PURE__ */ jsx4(Text3, { color: isChecked ? "green" : "gray", children: isChecked ? "[x] " : "[ ] " }),
4652
+ /* @__PURE__ */ jsx4(Text3, { color: isSelected ? "cyan" : "white", children: item.label.split("\n")[0] })
4653
+ ] }),
4654
+ item.label.includes("\n") && /* @__PURE__ */ jsxs2(Box3, { paddingLeft: isSelected ? 2 : 2, children: [
4655
+ isMulti && /* @__PURE__ */ jsx4(Text3, { children: " " }),
4656
+ /* @__PURE__ */ jsx4(Text3, { dimColor: true, children: item.label.split("\n").slice(1).join("\n") })
4657
+ ] })
4658
+ ] }, item.key || String(item.value));
4659
+ }),
4660
+ /* @__PURE__ */ jsx4(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text3, { color: "gray", children: isMulti ? "Space to toggle, Enter to confirm, Esc to cancel" : "Enter to select, Esc to cancel" }) })
4661
+ ] });
4662
+ }
4663
+ var init_SimpleSelect = __esm({
4664
+ "src/mcp/ui/components/SimpleSelect.tsx"() {
4665
+ "use strict";
4666
+ }
4667
+ });
4668
+
4669
+ // src/mcp/ui/ProjectsView.tsx
4670
+ import { useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
4671
+ import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
4672
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
4673
+ function projectKey(p) {
4674
+ return p.sourcePath ?? p.path;
4675
+ }
4676
+ function formatProjectLabel(p) {
4677
+ const root = p.sourcePath ?? p.path;
4678
+ return `${p.name} (${p.source})${root ? ` - ${root}` : ""}`;
4679
+ }
4680
+ var ProjectsView;
4681
+ var init_ProjectsView = __esm({
4682
+ "src/mcp/ui/ProjectsView.tsx"() {
4683
+ "use strict";
4684
+ init_SimpleSelect();
4685
+ init_config();
4686
+ init_ConfigContext();
4687
+ init_indexing_jobs();
4688
+ init_config_utils();
4689
+ ProjectsView = ({ config: initialConfig, projects: allProjects, onConfigChange, workspacePath }) => {
4710
4690
  const { driftReports, checkAllDrift } = useConfig();
4711
4691
  const [config, setConfig] = useState3(initialConfig);
4712
- const [mode, setMode] = useState3("expose");
4713
- const [expanded, setExpanded] = useState3(() => /* @__PURE__ */ new Set());
4714
- const [selectedIndex, setSelectedIndex] = useState3(0);
4715
- const [taskCache, setTaskCache] = useState3({});
4716
- const [errorLine, setErrorLine] = useState3(null);
4692
+ const [indexingStats, setIndexingStats] = useState3({});
4717
4693
  const sortedProjects = useMemo3(() => {
4718
4694
  return [...allProjects].sort((a, b) => {
4695
+ const aIsCurrent = a.path === workspacePath;
4696
+ const bIsCurrent = b.path === workspacePath;
4697
+ if (aIsCurrent && !bIsCurrent) return -1;
4698
+ if (!aIsCurrent && bIsCurrent) return 1;
4719
4699
  const byName = a.name.localeCompare(b.name);
4720
4700
  if (byName !== 0) return byName;
4721
4701
  return projectKey(a).localeCompare(projectKey(b));
4722
4702
  });
4723
- }, [allProjects]);
4724
- const refreshTasksForProject = (project) => {
4725
- const res = listProjectTasks(project);
4726
- setTaskCache((prev) => ({ ...prev, [projectKey(project)]: res.tasks }));
4727
- };
4728
- const refreshAllTasks = () => {
4729
- const next = {};
4730
- for (const p of sortedProjects) {
4731
- next[projectKey(p)] = listProjectTasks(p).tasks;
4732
- }
4733
- setTaskCache(next);
4734
- };
4703
+ }, [allProjects, workspacePath]);
4704
+ useEffect3(() => {
4705
+ const updateStats = () => {
4706
+ const next = {};
4707
+ for (const p of allProjects) {
4708
+ let projConfig = findProjectConfig(config, { name: p.name, path: p.path });
4709
+ if (!projConfig && p.source === "global") {
4710
+ projConfig = config.projects.find((c) => c.name === p.name);
4711
+ }
4712
+ const enabled = projConfig?.semanticSearch?.enabled || p.semanticSearchEnabled || false;
4713
+ const prog = indexingJobs.getProgress(p.name);
4714
+ next[p.name] = { enabled, ...prog };
4715
+ }
4716
+ setIndexingStats(next);
4717
+ };
4718
+ updateStats();
4719
+ const interval = setInterval(updateStats, 2e3);
4720
+ return () => clearInterval(interval);
4721
+ }, [allProjects, config]);
4735
4722
  useInput2((input, key) => {
4736
- if (input === "t") {
4737
- setErrorLine(null);
4738
- setMode((prev) => prev === "expose" ? "tasks" : "expose");
4739
- return;
4740
- }
4741
4723
  if (input === "u") {
4742
4724
  checkAllDrift();
4743
4725
  return;
4744
4726
  }
4745
- if (mode === "expose") {
4746
- if (input === "a") {
4747
- const newConfig = {
4748
- ...config,
4749
- defaults: {
4750
- ...config.defaults,
4751
- includeNew: !config.defaults.includeNew
4752
- }
4753
- };
4754
- saveMCPConfig(newConfig);
4755
- setConfig(newConfig);
4756
- onConfigChange?.();
4757
- }
4758
- return;
4759
- }
4760
- if (mode === "tasks") {
4761
- if (input === "R") {
4762
- setErrorLine(null);
4763
- refreshAllTasks();
4764
- return;
4765
- }
4766
- if (key.upArrow) {
4767
- setSelectedIndex((prev) => prev > 0 ? prev - 1 : Math.max(0, flattenedRows.length - 1));
4768
- return;
4769
- }
4770
- if (key.downArrow) {
4771
- setSelectedIndex((prev) => prev < flattenedRows.length - 1 ? prev + 1 : 0);
4772
- return;
4773
- }
4774
- if (key.return) {
4775
- const row = flattenedRows[selectedIndex];
4776
- if (row?.kind === "project") {
4777
- const k = projectKey(row.project);
4778
- const next = new Set(expanded);
4779
- if (next.has(k)) {
4780
- next.delete(k);
4781
- } else {
4782
- next.add(k);
4783
- refreshTasksForProject(row.project);
4784
- }
4785
- setExpanded(next);
4786
- }
4787
- return;
4788
- }
4789
- if (input === "s") {
4790
- const row = flattenedRows[selectedIndex];
4791
- if (row?.kind === "task") {
4792
- setErrorLine(null);
4793
- const desired = nextStatus(row.task.status);
4794
- const result = updateTaskStatus(row.project, row.task.task_slug, desired);
4795
- if (!result.ok) {
4796
- setErrorLine(`Failed to update status: ${result.error}`);
4797
- return;
4798
- }
4799
- setTaskCache((prev) => {
4800
- const k = projectKey(row.project);
4801
- const tasks = prev[k] || [];
4802
- const updated = tasks.map((t) => t.task_slug === row.task.task_slug ? result.meta : t);
4803
- return { ...prev, [k]: updated };
4804
- });
4727
+ if (input === "a") {
4728
+ const newConfig = {
4729
+ ...config,
4730
+ defaults: {
4731
+ ...config.defaults,
4732
+ includeNew: !config.defaults.includeNew
4805
4733
  }
4806
- return;
4807
- }
4734
+ };
4735
+ saveMCPConfig(newConfig);
4736
+ setConfig(newConfig);
4737
+ onConfigChange?.();
4808
4738
  }
4809
4739
  });
4810
- useEffect3(() => {
4811
- setSelectedIndex((prev) => {
4812
- if (flattenedRows.length === 0) return 0;
4813
- return Math.min(prev, flattenedRows.length - 1);
4814
- });
4815
- }, [mode, allProjects, expanded, taskCache]);
4816
4740
  const projectItems = useMemo3(() => {
4817
- return allProjects.map((p) => {
4741
+ return sortedProjects.map((p) => {
4818
4742
  const projectConfig = config.projects.find(
4819
4743
  (c) => c.path && c.path === p.path || p.source === "global" && c.name === p.name || !c.path && c.name === p.name
4820
4744
  );
4821
4745
  const isExposed = projectConfig ? projectConfig.expose : config.defaults.includeNew;
4822
4746
  const drift = driftReports[p.path];
4747
+ const idx = indexingStats[p.name];
4748
+ let label = formatProjectLabel(p);
4749
+ if (drift?.hasDrift) {
4750
+ label += ` \u26A0`;
4751
+ }
4752
+ if (idx?.state === "running") {
4753
+ label += `
4754
+ \u27F3 Indexing ${idx.itemsDone}/${idx.itemsTotal ?? "?"}`;
4755
+ } else if (idx?.state === "failed") {
4756
+ label += `
4757
+ \u2715 Index Fail`;
4758
+ } else if (idx?.enabled && idx?.state === "complete") {
4759
+ label += `
4760
+ \u2713 Indexed`;
4761
+ }
4823
4762
  return {
4824
- label: formatProjectLabel(p, drift),
4763
+ label,
4825
4764
  value: p.path,
4826
4765
  key: p.path,
4827
- exposed: isExposed
4766
+ exposed: isExposed,
4767
+ indexing: idx
4828
4768
  };
4829
4769
  });
4830
- }, [allProjects, config, driftReports]);
4770
+ }, [sortedProjects, config, driftReports, indexingStats]);
4831
4771
  const initialSelected = useMemo3(() => {
4832
4772
  return projectItems.filter((p) => p.exposed).map((p) => p.value);
4833
4773
  }, [projectItems]);
@@ -4852,11 +4792,158 @@ var init_ProjectsView = __esm({
4852
4792
  setConfig(newConfig);
4853
4793
  onConfigChange?.();
4854
4794
  };
4855
- const flattenedRows = useMemo3(() => {
4795
+ return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "white", flexGrow: 1, children: [
4796
+ /* @__PURE__ */ jsxs3(Box4, { justifyContent: "space-between", children: [
4797
+ /* @__PURE__ */ jsxs3(Box4, { children: [
4798
+ /* @__PURE__ */ jsx5(Text4, { bold: true, color: "cyan", children: " Projects " }),
4799
+ /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: " \u2022 " }),
4800
+ /* @__PURE__ */ jsxs3(Text4, { color: config.defaults.includeNew ? "green" : "red", children: [
4801
+ "Auto-expose: ",
4802
+ config.defaults.includeNew ? "ON" : "OFF"
4803
+ ] })
4804
+ ] }),
4805
+ /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "a:Toggle Auto u:Drift Space:Select Enter:Save" }) })
4806
+ ] }),
4807
+ /* @__PURE__ */ jsx5(Text4, { color: "dim", children: " Manage which projects are exposed to the MCP server." }),
4808
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx5(
4809
+ SimpleSelect,
4810
+ {
4811
+ message: "",
4812
+ items: projectItems,
4813
+ isMulti: true,
4814
+ initialSelected,
4815
+ onSelect: () => {
4816
+ },
4817
+ onSubmit: handleSubmit,
4818
+ onCancel: () => {
4819
+ }
4820
+ },
4821
+ JSON.stringify(initialSelected) + config.defaults.includeNew + JSON.stringify(indexingStats)
4822
+ ) }),
4823
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, borderStyle: "single", borderColor: "dim", paddingX: 1, children: /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Use 'rrce-workflow wizard' to manage project exposures and settings." }) })
4824
+ ] });
4825
+ };
4826
+ }
4827
+ });
4828
+
4829
+ // src/mcp/ui/ui-helpers.ts
4830
+ var getStatusIcon, getStatusColor, getChecklistProgress, getCheckbox, getProgressBar, getFolderIcon;
4831
+ var init_ui_helpers = __esm({
4832
+ "src/mcp/ui/ui-helpers.ts"() {
4833
+ "use strict";
4834
+ getStatusIcon = (status) => {
4835
+ const icons = {
4836
+ pending: "\u23F3",
4837
+ in_progress: "\u{1F504}",
4838
+ blocked: "\u{1F6AB}",
4839
+ complete: "\u2705"
4840
+ };
4841
+ return icons[status] || "\u25CB";
4842
+ };
4843
+ getStatusColor = (status) => {
4844
+ const colors = {
4845
+ pending: "yellow",
4846
+ in_progress: "yellow",
4847
+ blocked: "red",
4848
+ complete: "green"
4849
+ };
4850
+ return colors[status] || "white";
4851
+ };
4852
+ getChecklistProgress = (checklist) => {
4853
+ if (!checklist || checklist.length === 0) {
4854
+ return { completed: 0, total: 0, percentage: 0 };
4855
+ }
4856
+ const completed = checklist.filter((item) => item.status === "done").length;
4857
+ return {
4858
+ completed,
4859
+ total: checklist.length,
4860
+ percentage: Math.round(completed / checklist.length * 100)
4861
+ };
4862
+ };
4863
+ getCheckbox = (status) => {
4864
+ return status === "done" ? "\u2611" : "\u2610";
4865
+ };
4866
+ getProgressBar = (percentage, length = 10) => {
4867
+ const filled = Math.floor(percentage / 100 * length);
4868
+ const empty = length - filled;
4869
+ return "\u2588".repeat(filled) + "\u2591".repeat(empty);
4870
+ };
4871
+ getFolderIcon = (isOpen) => {
4872
+ return isOpen ? "\u{1F4C2}" : "\u{1F4C1}";
4873
+ };
4874
+ }
4875
+ });
4876
+
4877
+ // src/mcp/ui/TasksView.tsx
4878
+ import { useEffect as useEffect4, useMemo as useMemo4, useState as useState4 } from "react";
4879
+ import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
4880
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
4881
+ function nextStatus(current) {
4882
+ const idx = STATUS_CYCLE.indexOf(current || "");
4883
+ if (idx === -1) return STATUS_CYCLE[0];
4884
+ return STATUS_CYCLE[(idx + 1) % STATUS_CYCLE.length];
4885
+ }
4886
+ function projectKey2(p) {
4887
+ return p.sourcePath ?? p.path;
4888
+ }
4889
+ function formatProjectLabel2(p) {
4890
+ return `${p.name} (${p.source})`;
4891
+ }
4892
+ var STATUS_CYCLE, TasksView;
4893
+ var init_TasksView = __esm({
4894
+ "src/mcp/ui/TasksView.tsx"() {
4895
+ "use strict";
4896
+ init_tasks_fs();
4897
+ init_ConfigContext();
4898
+ init_ui_helpers();
4899
+ STATUS_CYCLE = ["pending", "in_progress", "blocked", "complete"];
4900
+ TasksView = ({ projects: allProjects, workspacePath }) => {
4901
+ const { driftReports } = useConfig();
4902
+ const [expanded, setExpanded] = useState4(() => /* @__PURE__ */ new Set());
4903
+ const [selectedIndex, setSelectedIndex] = useState4(0);
4904
+ const [taskCache, setTaskCache] = useState4({});
4905
+ const [errorLine, setErrorLine] = useState4(null);
4906
+ const sortedProjects = useMemo4(() => {
4907
+ return [...allProjects].sort((a, b) => {
4908
+ const aIsCurrent = a.path === workspacePath;
4909
+ const bIsCurrent = b.path === workspacePath;
4910
+ if (aIsCurrent && !bIsCurrent) return -1;
4911
+ if (!aIsCurrent && bIsCurrent) return 1;
4912
+ const byName = a.name.localeCompare(b.name);
4913
+ if (byName !== 0) return byName;
4914
+ return projectKey2(a).localeCompare(projectKey2(b));
4915
+ });
4916
+ }, [allProjects, workspacePath]);
4917
+ useEffect4(() => {
4918
+ const current = sortedProjects.find((p) => p.path === workspacePath);
4919
+ if (current) {
4920
+ const k = projectKey2(current);
4921
+ setExpanded((prev) => {
4922
+ const next = new Set(prev);
4923
+ if (!next.has(k)) {
4924
+ next.add(k);
4925
+ refreshTasksForProject(current);
4926
+ }
4927
+ return next;
4928
+ });
4929
+ }
4930
+ }, [sortedProjects, workspacePath]);
4931
+ const refreshTasksForProject = (project) => {
4932
+ const res = listProjectTasks(project);
4933
+ setTaskCache((prev) => ({ ...prev, [projectKey2(project)]: res.tasks }));
4934
+ };
4935
+ const refreshAllTasks = () => {
4936
+ const next = {};
4937
+ for (const p of sortedProjects) {
4938
+ next[projectKey2(p)] = listProjectTasks(p).tasks;
4939
+ }
4940
+ setTaskCache(next);
4941
+ };
4942
+ const flattenedRows = useMemo4(() => {
4856
4943
  const rows = [];
4857
4944
  for (const p of sortedProjects) {
4858
4945
  rows.push({ kind: "project", project: p });
4859
- const k = projectKey(p);
4946
+ const k = projectKey2(p);
4860
4947
  if (!expanded.has(k)) continue;
4861
4948
  const tasks = taskCache[k] || [];
4862
4949
  for (const t of tasks) {
@@ -4868,133 +4955,158 @@ var init_ProjectsView = __esm({
4868
4955
  }
4869
4956
  return rows;
4870
4957
  }, [sortedProjects, expanded, taskCache]);
4958
+ useInput3((input, key) => {
4959
+ if (input === "R") {
4960
+ setErrorLine(null);
4961
+ refreshAllTasks();
4962
+ return;
4963
+ }
4964
+ if (key.upArrow) {
4965
+ setSelectedIndex((prev) => prev > 0 ? prev - 1 : Math.max(0, flattenedRows.length - 1));
4966
+ return;
4967
+ }
4968
+ if (key.downArrow) {
4969
+ setSelectedIndex((prev) => prev < flattenedRows.length - 1 ? prev + 1 : 0);
4970
+ return;
4971
+ }
4972
+ if (key.return) {
4973
+ const row = flattenedRows[selectedIndex];
4974
+ if (row?.kind === "project") {
4975
+ const k = projectKey2(row.project);
4976
+ const next = new Set(expanded);
4977
+ if (next.has(k)) {
4978
+ next.delete(k);
4979
+ } else {
4980
+ next.add(k);
4981
+ refreshTasksForProject(row.project);
4982
+ }
4983
+ setExpanded(next);
4984
+ }
4985
+ return;
4986
+ }
4987
+ if (input === "s") {
4988
+ const row = flattenedRows[selectedIndex];
4989
+ if (row?.kind === "task") {
4990
+ setErrorLine(null);
4991
+ const desired = nextStatus(row.task.status);
4992
+ const result = updateTaskStatus(row.project, row.task.task_slug, desired);
4993
+ if (!result.ok) {
4994
+ setErrorLine(`Failed to update status: ${result.error}`);
4995
+ return;
4996
+ }
4997
+ setTaskCache((prev) => {
4998
+ const k = projectKey2(row.project);
4999
+ const tasks = prev[k] || [];
5000
+ const updated = tasks.map((t) => t.task_slug === row.task.task_slug ? result.meta : t);
5001
+ return { ...prev, [k]: updated };
5002
+ });
5003
+ }
5004
+ return;
5005
+ }
5006
+ });
5007
+ useEffect4(() => {
5008
+ setSelectedIndex((prev) => {
5009
+ if (flattenedRows.length === 0) return 0;
5010
+ return Math.min(prev, flattenedRows.length - 1);
5011
+ });
5012
+ }, [flattenedRows]);
4871
5013
  const selectedRow = flattenedRows[selectedIndex];
4872
5014
  const selectedTask = selectedRow?.kind === "task" && selectedRow.task.task_slug !== "__none__" ? selectedRow.task : null;
4873
- if (mode === "expose") {
4874
- return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan", flexGrow: 1, children: [
4875
- /* @__PURE__ */ jsxs3(Box4, { justifyContent: "space-between", children: [
4876
- /* @__PURE__ */ jsx5(Text4, { bold: true, color: "cyan", children: " Projects (Expose Mode) " }),
4877
- /* @__PURE__ */ jsxs3(Box4, { children: [
4878
- /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "Auto-expose new: " }),
4879
- /* @__PURE__ */ jsx5(Text4, { color: config.defaults.includeNew ? "green" : "red", children: config.defaults.includeNew ? "ON" : "OFF" }),
4880
- /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: " (Press 'a' to toggle)" })
4881
- ] })
4882
- ] }),
4883
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: " Space toggles, Enter saves. Press 't' to switch to Tasks Mode." }),
4884
- /* @__PURE__ */ jsx5(Box4, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx5(
4885
- SimpleSelect,
4886
- {
4887
- message: "",
4888
- items: projectItems,
4889
- isMulti: true,
4890
- initialSelected,
4891
- onSelect: () => {
4892
- },
4893
- onSubmit: handleSubmit,
4894
- onCancel: () => {
4895
- }
4896
- },
4897
- JSON.stringify(initialSelected) + config.defaults.includeNew
4898
- ) })
4899
- ] });
4900
- }
4901
- return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan", flexGrow: 1, children: [
4902
- /* @__PURE__ */ jsxs3(Box4, { justifyContent: "space-between", children: [
4903
- /* @__PURE__ */ jsxs3(Box4, { children: [
4904
- /* @__PURE__ */ jsx5(Text4, { bold: true, color: "cyan", children: "\u2699 Tasks Mode" }),
4905
- /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: " \u2022 " }),
4906
- /* @__PURE__ */ jsxs3(Text4, { children: [
5015
+ return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "white", flexGrow: 1, children: [
5016
+ /* @__PURE__ */ jsxs4(Box5, { justifyContent: "space-between", children: [
5017
+ /* @__PURE__ */ jsxs4(Box5, { children: [
5018
+ /* @__PURE__ */ jsx6(Text5, { bold: true, color: "cyan", children: "\u2699 Tasks" }),
5019
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: " \u2022 " }),
5020
+ /* @__PURE__ */ jsxs4(Text5, { children: [
4907
5021
  sortedProjects.length,
4908
5022
  " projects"
4909
5023
  ] }),
4910
- /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: " \u2022 " }),
4911
- /* @__PURE__ */ jsxs3(Text4, { children: [
5024
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: " \u2022 " }),
5025
+ /* @__PURE__ */ jsxs4(Text5, { children: [
4912
5026
  Object.values(taskCache).flat().length,
4913
5027
  " tasks"
4914
5028
  ] })
4915
5029
  ] }),
4916
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "t:Expose \u2191/\u2193:Nav Enter:Expand s:Status R:Refresh u:Drift" })
5030
+ /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "\u2191/\u2193:Nav Enter:Expand s:Status R:Refresh" })
4917
5031
  ] }),
4918
- errorLine && /* @__PURE__ */ jsx5(Box4, { marginTop: 0, children: /* @__PURE__ */ jsx5(Text4, { color: "red", children: errorLine }) }),
4919
- /* @__PURE__ */ jsxs3(Box4, { marginTop: 1, flexDirection: "row", flexGrow: 1, children: [
4920
- /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", width: "55%", children: [
4921
- flattenedRows.length === 0 ? /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "No projects detected." }) : flattenedRows.map((row, idx) => {
5032
+ errorLine && /* @__PURE__ */ jsx6(Box5, { marginTop: 0, children: /* @__PURE__ */ jsx6(Text5, { color: "red", children: errorLine }) }),
5033
+ /* @__PURE__ */ jsxs4(Box5, { marginTop: 1, flexDirection: "row", flexGrow: 1, children: [
5034
+ /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", width: "55%", children: [
5035
+ flattenedRows.length === 0 ? /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "No projects detected." }) : flattenedRows.map((row, idx) => {
4922
5036
  const isSel = idx === selectedIndex;
4923
5037
  if (row.kind === "project") {
4924
- const k = projectKey(row.project);
5038
+ const k = projectKey2(row.project);
4925
5039
  const isOpen = expanded.has(k);
4926
5040
  const count = (taskCache[k] || []).length;
4927
5041
  const drift = driftReports[row.project.path];
4928
- return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
4929
- /* @__PURE__ */ jsxs3(Box4, { children: [
4930
- /* @__PURE__ */ jsx5(Text4, { color: isSel ? "cyan" : "white", children: isSel ? "> " : " " }),
4931
- /* @__PURE__ */ jsxs3(Text4, { color: isSel ? "cyan" : "white", children: [
4932
- getFolderIcon(isOpen),
4933
- " ",
4934
- formatProjectLabel(row.project, drift)
4935
- ] }),
4936
- drift?.hasDrift && /* @__PURE__ */ jsx5(Text4, { color: "magenta", children: " \u26A0" }),
4937
- /* @__PURE__ */ jsxs3(Text4, { color: "dim", children: [
4938
- " ",
4939
- count > 0 ? `(${count})` : ""
4940
- ] })
5042
+ return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsxs4(Box5, { children: [
5043
+ /* @__PURE__ */ jsx6(Text5, { color: isSel ? "cyan" : "white", children: isSel ? "> " : " " }),
5044
+ /* @__PURE__ */ jsxs4(Text5, { color: isSel ? "cyan" : "white", children: [
5045
+ getFolderIcon(isOpen),
5046
+ " ",
5047
+ formatProjectLabel2(row.project)
4941
5048
  ] }),
4942
- isSel && drift?.hasDrift && /* @__PURE__ */ jsx5(Box4, { marginLeft: 4, children: /* @__PURE__ */ jsxs3(Text4, { color: "magenta", dimColor: true, italic: true, children: [
4943
- drift.type === "version" ? "New version available. " : "Modifications detected. ",
4944
- "Run 'rrce-workflow wizard' to update."
4945
- ] }) })
4946
- ] }, `p:${k}`);
5049
+ drift?.hasDrift && /* @__PURE__ */ jsx6(Text5, { color: "magenta", children: " \u26A0" }),
5050
+ /* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
5051
+ " ",
5052
+ count > 0 ? `(${count})` : ""
5053
+ ] })
5054
+ ] }) }, `p:${k}`);
4947
5055
  }
4948
5056
  const taskLabel = row.task.title || row.task.task_slug;
4949
5057
  const status = row.task.status || "";
4950
- return /* @__PURE__ */ jsxs3(Box4, { children: [
4951
- /* @__PURE__ */ jsx5(Text4, { color: isSel ? "cyan" : "white", children: isSel ? "> " : " " }),
4952
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: " - " }),
4953
- /* @__PURE__ */ jsx5(Text4, { color: isSel ? "cyan" : "white", children: taskLabel }),
4954
- row.task.task_slug !== "__none__" && /* @__PURE__ */ jsx5(Text4, { backgroundColor: getStatusColor(status), color: "black", children: ` ${getStatusIcon(status)} ${status.toUpperCase().replace("_", " ")} ` })
4955
- ] }, `t:${projectKey(row.project)}:${row.task.task_slug}`);
5058
+ return /* @__PURE__ */ jsxs4(Box5, { children: [
5059
+ /* @__PURE__ */ jsx6(Text5, { color: isSel ? "cyan" : "white", children: isSel ? "> " : " " }),
5060
+ /* @__PURE__ */ jsx6(Text5, { color: "dim", children: " - " }),
5061
+ /* @__PURE__ */ jsx6(Text5, { color: isSel ? "cyan" : "white", children: taskLabel }),
5062
+ row.task.task_slug !== "__none__" && /* @__PURE__ */ jsx6(Text5, { backgroundColor: getStatusColor(status), color: "black", children: ` ${getStatusIcon(status)} ${status.toUpperCase().replace("_", " ")} ` })
5063
+ ] }, `t:${projectKey2(row.project)}:${row.task.task_slug}`);
4956
5064
  }),
4957
- /* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text4, { color: "gray", children: "\u25B2/\u25BC navigate \u2022 Enter expand/collapse \u2022 s cycle status \u2022 R refresh \u2022 t expose mode" }) })
5065
+ /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text5, { color: "gray", children: "\u25B2/\u25BC navigate \u2022 Enter expand/collapse \u2022 s cycle status \u2022 R refresh" }) })
4958
5066
  ] }),
4959
- /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", width: "45%", paddingLeft: 2, children: !selectedTask ? /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", justifyContent: "center", alignItems: "center", gap: 1, children: [
4960
- /* @__PURE__ */ jsx5(Text4, { bold: true, color: "dim", children: "\u2500 No Task Selected \u2500" }),
4961
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Use \u2191/\u2193 to navigate, Enter to expand projects" }),
4962
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Press 's' to cycle task status, 't' to switch modes" })
4963
- ] }) : /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
4964
- /* @__PURE__ */ jsx5(Text4, { bold: true, color: "cyan", children: selectedTask.title || selectedTask.task_slug }),
4965
- selectedTask.summary && /* @__PURE__ */ jsx5(Text4, { children: selectedTask.summary }),
4966
- /* @__PURE__ */ jsxs3(Box4, { marginTop: 1, borderStyle: "single", borderColor: "dim", padding: 1, flexDirection: "column", children: [
4967
- /* @__PURE__ */ jsx5(Text4, { bold: true, color: "cyan", children: "\u{1F4CB} Status" }),
4968
- /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", marginTop: 0, children: [
4969
- /* @__PURE__ */ jsxs3(Text4, { children: [
4970
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Status:" }),
5067
+ /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", width: "45%", paddingLeft: 2, children: !selectedTask ? /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", justifyContent: "center", alignItems: "center", gap: 1, flexGrow: 1, children: [
5068
+ /* @__PURE__ */ jsx6(Text5, { bold: true, color: "dim", children: "\u2500 No Task Selected \u2500" }),
5069
+ /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "Use \u2191/\u2193 to navigate, Enter to expand projects" }),
5070
+ /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "Press 's' to cycle task status" })
5071
+ ] }) : /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
5072
+ /* @__PURE__ */ jsxs4(Box5, { marginBottom: 1, flexDirection: "column", children: [
5073
+ /* @__PURE__ */ jsx6(Text5, { bold: true, color: "cyan", children: selectedTask.title || selectedTask.task_slug }),
5074
+ selectedTask.summary && /* @__PURE__ */ jsx6(Text5, { color: "white", children: selectedTask.summary })
5075
+ ] }),
5076
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: "\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
5077
+ /* @__PURE__ */ jsxs4(Box5, { marginTop: 1, paddingX: 1, flexDirection: "column", children: [
5078
+ /* @__PURE__ */ jsx6(Text5, { bold: true, color: "white", children: "\u{1F4CB} STATUS" }),
5079
+ /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", marginTop: 1, children: [
5080
+ /* @__PURE__ */ jsxs4(Text5, { children: [
5081
+ /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "Status: " }),
4971
5082
  " ",
4972
- /* @__PURE__ */ jsx5(Text4, { children: selectedTask.status || "unknown" })
5083
+ /* @__PURE__ */ jsx6(Text5, { color: getStatusColor(selectedTask.status || ""), children: selectedTask.status || "unknown" })
4973
5084
  ] }),
4974
- /* @__PURE__ */ jsxs3(Text4, { children: [
4975
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Updated:" }),
5085
+ /* @__PURE__ */ jsxs4(Text5, { children: [
5086
+ /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "Updated:" }),
4976
5087
  " ",
4977
- /* @__PURE__ */ jsx5(Text4, { children: selectedTask.updated_at || "\u2014" })
5088
+ /* @__PURE__ */ jsx6(Text5, { children: selectedTask.updated_at || "\u2014" })
4978
5089
  ] }),
4979
- /* @__PURE__ */ jsxs3(Text4, { children: [
4980
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Tags:" }),
5090
+ /* @__PURE__ */ jsxs4(Text5, { children: [
5091
+ /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "Tags: " }),
4981
5092
  " ",
4982
5093
  " ",
4983
5094
  (() => {
4984
5095
  const tags = selectedTask.tags || [];
4985
- return tags.length > 0 ? tags.map((tag, i) => /* @__PURE__ */ jsxs3(Text4, { children: [
4986
- /* @__PURE__ */ jsx5(Text4, { color: "cyan", children: tag }),
4987
- i < tags.length - 1 && /* @__PURE__ */ jsx5(Text4, { color: "dim", children: ", " })
4988
- ] }, tag)) : /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "\u2014" });
5096
+ return tags.length > 0 ? tags.map((tag, i) => /* @__PURE__ */ jsxs4(Text5, { children: [
5097
+ /* @__PURE__ */ jsx6(Text5, { color: "cyan", children: tag }),
5098
+ i < tags.length - 1 && /* @__PURE__ */ jsx6(Text5, { color: "dim", children: ", " })
5099
+ ] }, tag)) : /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "\u2014" });
4989
5100
  })()
4990
5101
  ] })
4991
5102
  ] })
4992
5103
  ] }),
4993
- /* @__PURE__ */ jsxs3(Box4, { marginTop: 1, borderStyle: "single", borderColor: "dim", padding: 1, flexDirection: "column", children: [
4994
- /* @__PURE__ */ jsx5(Text4, { bold: true, color: "cyan", children: "\u{1F4CB} Checklist" }),
4995
- selectedTask.checklist && selectedTask.checklist.length > 0 && /* @__PURE__ */ jsx5(Box4, { marginTop: 0, flexDirection: "column", children: /* @__PURE__ */ jsxs3(Box4, { children: [
4996
- /* @__PURE__ */ jsx5(Text4, { backgroundColor: "white", children: getProgressBar(getChecklistProgress(selectedTask.checklist).percentage) }),
4997
- /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
5104
+ /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: "\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }),
5105
+ /* @__PURE__ */ jsxs4(Box5, { marginTop: 1, paddingX: 1, flexDirection: "column", children: [
5106
+ /* @__PURE__ */ jsx6(Text5, { bold: true, color: "white", children: "\u{1F4CB} CHECKLIST" }),
5107
+ selectedTask.checklist && selectedTask.checklist.length > 0 && /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsxs4(Box5, { marginBottom: 1, children: [
5108
+ /* @__PURE__ */ jsx6(Text5, { backgroundColor: "white", children: getProgressBar(getChecklistProgress(selectedTask.checklist).percentage) }),
5109
+ /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
4998
5110
  " ",
4999
5111
  " ",
5000
5112
  getChecklistProgress(selectedTask.checklist).completed,
@@ -5005,36 +5117,40 @@ var init_ProjectsView = __esm({
5005
5117
  "%)"
5006
5118
  ] })
5007
5119
  ] }) }),
5008
- (selectedTask.checklist || []).length === 0 ? /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "\u2014" }) : (selectedTask.checklist || []).slice(0, 12).map((c, i) => /* @__PURE__ */ jsxs3(Text4, { children: [
5009
- /* @__PURE__ */ jsxs3(Text4, { color: "dim", children: [
5010
- getCheckbox(c.status || "pending"),
5011
- " "
5012
- ] }),
5013
- c.label || c.id || "item"
5014
- ] }, c.id || i))
5120
+ (selectedTask.checklist || []).length === 0 ? /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "\u2014" }) : (selectedTask.checklist || []).slice(0, 12).map((c, i) => {
5121
+ const isDone = c.status === "done";
5122
+ return /* @__PURE__ */ jsxs4(Text5, { color: isDone ? "dim" : "white", children: [
5123
+ /* @__PURE__ */ jsxs4(Text5, { color: isDone ? "green" : "dim", children: [
5124
+ getCheckbox(c.status || "pending"),
5125
+ " "
5126
+ ] }),
5127
+ c.label || c.id || "item"
5128
+ ] }, c.id || i);
5129
+ })
5015
5130
  ] }),
5016
- /* @__PURE__ */ jsxs3(Box4, { marginTop: 1, borderStyle: "single", borderColor: "dim", padding: 1, flexDirection: "column", children: [
5017
- /* @__PURE__ */ jsx5(Text4, { bold: true, color: "cyan", children: "\u{1F916} Agents" }),
5018
- !selectedTask.agents ? /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "\u2014" }) : Object.entries(selectedTask.agents).map(([agent, info]) => /* @__PURE__ */ jsxs3(Text4, { children: [
5019
- /* @__PURE__ */ jsxs3(Text4, { color: "dim", children: [
5131
+ /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: "\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }),
5132
+ /* @__PURE__ */ jsxs4(Box5, { marginTop: 1, paddingX: 1, flexDirection: "column", children: [
5133
+ /* @__PURE__ */ jsx6(Text5, { bold: true, color: "white", children: "\u{1F916} AGENTS" }),
5134
+ /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "column", children: !selectedTask.agents ? /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "\u2014" }) : Object.entries(selectedTask.agents).map(([agent, info]) => /* @__PURE__ */ jsxs4(Text5, { children: [
5135
+ /* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
5020
5136
  "- ",
5021
5137
  agent,
5022
5138
  ": "
5023
5139
  ] }),
5024
- info?.status === "complete" && /* @__PURE__ */ jsx5(Text4, { color: "green", children: "\u2713" }),
5025
- info?.status === "in_progress" && /* @__PURE__ */ jsx5(Text4, { color: "yellow", children: "\u27F3" }),
5026
- info?.status === "pending" && /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "\u25CB" }),
5027
- info?.blocked && /* @__PURE__ */ jsx5(Text4, { color: "red", children: "\u2715" }),
5028
- /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
5140
+ info?.status === "complete" && /* @__PURE__ */ jsx6(Text5, { color: "green", children: "\u2713" }),
5141
+ info?.status === "in_progress" && /* @__PURE__ */ jsx6(Text5, { color: "yellow", children: "\u27F3" }),
5142
+ info?.status === "pending" && /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "\u25CB" }),
5143
+ info?.blocked && /* @__PURE__ */ jsx6(Text5, { color: "red", children: "\u2715" }),
5144
+ /* @__PURE__ */ jsxs4(Text5, { color: info?.status === "complete" ? "dim" : "white", children: [
5029
5145
  " ",
5030
5146
  info?.status || "\u2014"
5031
5147
  ] }),
5032
- info?.artifact && /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
5033
- "(",
5148
+ info?.artifact && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
5149
+ " (",
5034
5150
  info.artifact,
5035
5151
  ")"
5036
5152
  ] })
5037
- ] }, agent))
5153
+ ] }, agent)) })
5038
5154
  ] })
5039
5155
  ] }) })
5040
5156
  ] })
@@ -5043,126 +5159,10 @@ var init_ProjectsView = __esm({
5043
5159
  }
5044
5160
  });
5045
5161
 
5046
- // src/mcp/ui/components/InstallWizard.tsx
5047
- import { useState as useState4 } from "react";
5048
- import { Box as Box5, Text as Text5 } from "ink";
5049
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
5050
- var InstallWizard;
5051
- var init_InstallWizard = __esm({
5052
- "src/mcp/ui/components/InstallWizard.tsx"() {
5053
- "use strict";
5054
- init_SimpleSelect();
5055
- init_install();
5056
- InstallWizard = ({ workspacePath, onComplete, onCancel }) => {
5057
- const [status, setStatus] = useState4(checkInstallStatus(workspacePath));
5058
- const [message, setMessage] = useState4("");
5059
- const options = [
5060
- {
5061
- value: "opencode",
5062
- label: "OpenCode",
5063
- hint: status.opencode ? "INSTALLED" : "Not installed"
5064
- },
5065
- {
5066
- value: "antigravity",
5067
- label: "Antigravity IDE",
5068
- hint: status.antigravity ? "INSTALLED" : "Not installed"
5069
- },
5070
- {
5071
- value: "vscode-global",
5072
- label: "VSCode (Global Settings)",
5073
- hint: status.vscodeGlobal ? "INSTALLED" : "Not installed"
5074
- },
5075
- {
5076
- value: "vscode-workspace",
5077
- label: "VSCode (Workspace Config)",
5078
- hint: status.vscodeWorkspace ? "INSTALLED" : "Not installed"
5079
- },
5080
- {
5081
- value: "claude",
5082
- label: "Claude Desktop",
5083
- hint: status.claude ? "INSTALLED" : "Not installed"
5084
- }
5085
- ];
5086
- const initialSelected = [
5087
- ...status.opencode ? ["opencode"] : [],
5088
- ...status.antigravity ? ["antigravity"] : [],
5089
- ...status.vscodeGlobal ? ["vscode-global"] : [],
5090
- ...status.vscodeWorkspace ? ["vscode-workspace"] : [],
5091
- ...status.claude ? ["claude"] : []
5092
- ];
5093
- const handleSubmit = (selectedIds) => {
5094
- const targets = selectedIds;
5095
- let results = [];
5096
- targets.forEach((target) => {
5097
- const success = installToConfig(target, workspacePath);
5098
- const label = getTargetLabel(target);
5099
- results.push(`${label}: ${success ? "Success" : "Failed"}`);
5100
- });
5101
- setStatus(checkInstallStatus(workspacePath));
5102
- setMessage(`Installation updated: ${results.join(", ")}`);
5103
- setTimeout(() => {
5104
- setMessage("");
5105
- onComplete();
5106
- }, 2e3);
5107
- };
5108
- return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
5109
- message && /* @__PURE__ */ jsx6(Text5, { color: "green", children: message }),
5110
- /* @__PURE__ */ jsx6(
5111
- SimpleSelect,
5112
- {
5113
- message: "Select integrations to install:",
5114
- items: options.map((o) => ({
5115
- value: o.value,
5116
- label: o.label + (o.hint === "INSTALLED" ? " (Installed)" : ""),
5117
- key: o.value
5118
- })),
5119
- isMulti: true,
5120
- initialSelected,
5121
- onSelect: () => {
5122
- },
5123
- onSubmit: handleSubmit,
5124
- onCancel
5125
- }
5126
- )
5127
- ] });
5128
- };
5129
- }
5130
- });
5131
-
5132
- // src/mcp/ui/InstallView.tsx
5162
+ // src/mcp/ui/LogViewer.tsx
5133
5163
  import "react";
5134
5164
  import { Box as Box6, Text as Text6 } from "ink";
5135
5165
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
5136
- var InstallView;
5137
- var init_InstallView = __esm({
5138
- "src/mcp/ui/InstallView.tsx"() {
5139
- "use strict";
5140
- init_InstallWizard();
5141
- init_paths();
5142
- InstallView = () => {
5143
- const workspacePath = detectWorkspaceRoot();
5144
- return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "magenta", flexGrow: 1, children: [
5145
- /* @__PURE__ */ jsx7(Text6, { bold: true, color: "magenta", children: " Installation & Configuration " }),
5146
- /* @__PURE__ */ jsx7(Text6, { color: "dim", children: " Configure IDE integrations for OpenCode, VSCode, Claude, and Antigravity." }),
5147
- /* @__PURE__ */ jsx7(Box6, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx7(
5148
- InstallWizard,
5149
- {
5150
- workspacePath,
5151
- onComplete: () => {
5152
- },
5153
- onCancel: () => {
5154
- }
5155
- }
5156
- ) })
5157
- ] });
5158
- };
5159
- }
5160
- });
5161
-
5162
- // src/mcp/ui/LogViewer.tsx
5163
- import "react";
5164
- import { Box as Box7, Text as Text7 } from "ink";
5165
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
5166
5166
  var LogViewer;
5167
5167
  var init_LogViewer = __esm({
5168
5168
  "src/mcp/ui/LogViewer.tsx"() {
@@ -5172,16 +5172,16 @@ var init_LogViewer = __esm({
5172
5172
  const emptyLines = Math.max(0, height - visibleLogs.length);
5173
5173
  const padding = Array(emptyLines).fill("");
5174
5174
  const formatLog = (log) => {
5175
- if (log.includes("[RAG]")) return /* @__PURE__ */ jsx8(Text7, { color: "cyan", children: log });
5176
- if (log.includes("[ERROR]")) return /* @__PURE__ */ jsx8(Text7, { color: "red", children: log });
5177
- if (log.includes("[WARN]")) return /* @__PURE__ */ jsx8(Text7, { color: "yellow", children: log });
5178
- if (log.includes("[INFO]")) return /* @__PURE__ */ jsx8(Text7, { color: "green", children: log });
5179
- if (log.includes("Success")) return /* @__PURE__ */ jsx8(Text7, { color: "green", children: log });
5180
- return /* @__PURE__ */ jsx8(Text7, { children: log });
5175
+ if (log.includes("[RAG]")) return /* @__PURE__ */ jsx7(Text6, { color: "cyan", children: log });
5176
+ if (log.includes("[ERROR]")) return /* @__PURE__ */ jsx7(Text6, { color: "red", children: log });
5177
+ if (log.includes("[WARN]")) return /* @__PURE__ */ jsx7(Text6, { color: "yellow", children: log });
5178
+ if (log.includes("[INFO]")) return /* @__PURE__ */ jsx7(Text6, { color: "green", children: log });
5179
+ if (log.includes("Success")) return /* @__PURE__ */ jsx7(Text6, { color: "green", children: log });
5180
+ return /* @__PURE__ */ jsx7(Text6, { children: log });
5181
5181
  };
5182
- return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "dim", paddingX: 1, height: height + 2, flexGrow: 1, children: [
5183
- padding.map((_, i) => /* @__PURE__ */ jsx8(Text7, { children: " " }, `empty-${i}`)),
5184
- visibleLogs.map((log, i) => /* @__PURE__ */ jsx8(Box7, { children: formatLog(log) }, `log-${i}`))
5182
+ return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "white", paddingX: 1, height: height + 2, flexGrow: 1, children: [
5183
+ padding.map((_, i) => /* @__PURE__ */ jsx7(Text6, { children: " " }, `empty-${i}`)),
5184
+ visibleLogs.map((log, i) => /* @__PURE__ */ jsx7(Box6, { children: formatLog(log) }, `log-${i}`))
5185
5185
  ] });
5186
5186
  };
5187
5187
  }
@@ -5189,28 +5189,28 @@ var init_LogViewer = __esm({
5189
5189
 
5190
5190
  // src/mcp/ui/StatusBoard.tsx
5191
5191
  import "react";
5192
- import { Box as Box8, Text as Text8 } from "ink";
5193
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
5192
+ import { Box as Box7, Text as Text7 } from "ink";
5193
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
5194
5194
  var StatusBoard;
5195
5195
  var init_StatusBoard = __esm({
5196
5196
  "src/mcp/ui/StatusBoard.tsx"() {
5197
5197
  "use strict";
5198
5198
  StatusBoard = ({ exposedLabel, port, pid, running, hasDrift }) => {
5199
- return /* @__PURE__ */ jsx9(Box8, { borderStyle: "single", borderColor: "cyan", paddingX: 1, flexGrow: 1, children: /* @__PURE__ */ jsxs7(Text8, { children: [
5200
- running ? /* @__PURE__ */ jsx9(Text8, { color: "green", children: "\u25CF RUNNING" }) : /* @__PURE__ */ jsx9(Text8, { color: "red", children: "\u25CF STOPPED" }),
5199
+ return /* @__PURE__ */ jsx8(Box7, { borderStyle: "single", borderColor: "white", paddingX: 1, flexGrow: 1, children: /* @__PURE__ */ jsxs6(Text7, { children: [
5200
+ running ? /* @__PURE__ */ jsx8(Text7, { color: "green", children: "\u25CF RUNNING" }) : /* @__PURE__ */ jsx8(Text7, { color: "red", children: "\u25CF STOPPED" }),
5201
5201
  " ",
5202
5202
  "\u2502",
5203
5203
  " \u{1F4CB} ",
5204
- /* @__PURE__ */ jsx9(Text8, { color: "yellow", children: exposedLabel }),
5204
+ /* @__PURE__ */ jsx8(Text7, { color: "yellow", children: exposedLabel }),
5205
5205
  " ",
5206
5206
  "\u2502",
5207
5207
  " Port: ",
5208
- /* @__PURE__ */ jsx9(Text8, { color: "green", children: port }),
5208
+ /* @__PURE__ */ jsx8(Text7, { color: "green", children: port }),
5209
5209
  " ",
5210
5210
  "\u2502",
5211
5211
  " PID: ",
5212
- /* @__PURE__ */ jsx9(Text8, { color: "green", children: pid }),
5213
- hasDrift && /* @__PURE__ */ jsxs7(Text8, { color: "magenta", bold: true, children: [
5212
+ /* @__PURE__ */ jsx8(Text7, { color: "green", children: pid }),
5213
+ hasDrift && /* @__PURE__ */ jsxs6(Text7, { color: "magenta", bold: true, children: [
5214
5214
  " ",
5215
5215
  "\u2502",
5216
5216
  " \u2B06 UPDATE AVAILABLE"
@@ -5220,121 +5220,16 @@ var init_StatusBoard = __esm({
5220
5220
  }
5221
5221
  });
5222
5222
 
5223
- // src/mcp/ui/IndexingStatus.tsx
5224
- import { useState as useState5, useEffect as useEffect5 } from "react";
5225
- import { Box as Box9, Text as Text9 } from "ink";
5226
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
5227
- var IndexingStatus;
5228
- var init_IndexingStatus = __esm({
5229
- "src/mcp/ui/IndexingStatus.tsx"() {
5230
- "use strict";
5231
- init_indexing_jobs();
5232
- init_rag();
5233
- init_resources();
5234
- init_config_utils();
5235
- IndexingStatus = ({ projects, config }) => {
5236
- const [stats, setStats] = useState5([]);
5237
- const [loading, setLoading] = useState5(true);
5238
- useEffect5(() => {
5239
- const fetchStats = async () => {
5240
- const newStats = [];
5241
- for (const project of projects) {
5242
- let projConfig = findProjectConfig(config, { name: project.name, path: project.path });
5243
- if (!projConfig && project.source === "global") {
5244
- projConfig = config.projects.find((p) => p.name === project.name);
5245
- }
5246
- const enabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled || false;
5247
- if (!enabled) {
5248
- const prog = indexingJobs.getProgress(project.name);
5249
- newStats.push({
5250
- projectName: project.name,
5251
- enabled: false,
5252
- state: prog.state,
5253
- itemsDone: prog.itemsDone,
5254
- itemsTotal: prog.itemsTotal,
5255
- currentItem: prog.currentItem,
5256
- totalFiles: 0,
5257
- totalChunks: 0
5258
- });
5259
- continue;
5260
- }
5261
- try {
5262
- const indexPath = getRAGIndexPath(project);
5263
- const rag = new RAGService(indexPath, "dummy");
5264
- const s = rag.getStats();
5265
- const prog = indexingJobs.getProgress(project.name);
5266
- newStats.push({
5267
- projectName: project.name,
5268
- enabled: true,
5269
- state: prog.state,
5270
- itemsDone: prog.itemsDone,
5271
- itemsTotal: prog.itemsTotal,
5272
- currentItem: prog.currentItem,
5273
- totalFiles: s.totalFiles,
5274
- totalChunks: s.totalChunks,
5275
- lastFullIndex: s.lastFullIndex
5276
- });
5277
- } catch (e) {
5278
- const prog = indexingJobs.getProgress(project.name);
5279
- newStats.push({
5280
- projectName: project.name,
5281
- enabled: true,
5282
- state: prog.state,
5283
- itemsDone: prog.itemsDone,
5284
- itemsTotal: prog.itemsTotal,
5285
- currentItem: prog.currentItem,
5286
- totalFiles: 0,
5287
- totalChunks: 0,
5288
- error: String(e)
5289
- });
5290
- }
5291
- }
5292
- setStats(newStats);
5293
- setLoading(false);
5294
- };
5295
- fetchStats();
5296
- const interval = setInterval(fetchStats, 5e3);
5297
- return () => clearInterval(interval);
5298
- }, [projects, config]);
5299
- if (loading && stats.length === 0) {
5300
- return /* @__PURE__ */ jsx10(Text9, { children: "Loading indexing status..." });
5301
- }
5302
- return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "blue", flexGrow: 1, children: [
5303
- /* @__PURE__ */ jsx10(Text9, { bold: true, color: "blue", children: " RAG Indexing Status " }),
5304
- /* @__PURE__ */ jsxs8(Box9, { marginTop: 1, flexDirection: "column", children: [
5305
- /* @__PURE__ */ jsxs8(Box9, { children: [
5306
- /* @__PURE__ */ jsx10(Box9, { width: 25, children: /* @__PURE__ */ jsx10(Text9, { underline: true, children: "Project" }) }),
5307
- /* @__PURE__ */ jsx10(Box9, { width: 15, children: /* @__PURE__ */ jsx10(Text9, { underline: true, children: "Status" }) }),
5308
- /* @__PURE__ */ jsx10(Box9, { width: 15, children: /* @__PURE__ */ jsx10(Text9, { underline: true, children: "State" }) }),
5309
- /* @__PURE__ */ jsx10(Box9, { width: 18, children: /* @__PURE__ */ jsx10(Text9, { underline: true, children: "Progress" }) }),
5310
- /* @__PURE__ */ jsx10(Box9, { width: 15, children: /* @__PURE__ */ jsx10(Text9, { underline: true, children: "Indexed Files" }) }),
5311
- /* @__PURE__ */ jsx10(Box9, { width: 15, children: /* @__PURE__ */ jsx10(Text9, { underline: true, children: "Total Chunks" }) }),
5312
- /* @__PURE__ */ jsx10(Box9, { children: /* @__PURE__ */ jsx10(Text9, { underline: true, children: "Last Index" }) })
5313
- ] }),
5314
- stats.length === 0 ? /* @__PURE__ */ jsx10(Text9, { color: "dim", children: "No exposed projects found." }) : stats.map((s) => /* @__PURE__ */ jsxs8(Box9, { marginTop: 0, children: [
5315
- /* @__PURE__ */ jsx10(Box9, { width: 25, children: /* @__PURE__ */ jsx10(Text9, { color: "white", children: s.projectName }) }),
5316
- /* @__PURE__ */ jsx10(Box9, { width: 15, children: /* @__PURE__ */ jsx10(Text9, { color: s.state === "running" ? "yellow" : s.state === "failed" ? "red" : s.enabled ? "green" : "dim", children: s.enabled ? s.state : "disabled" }) }),
5317
- /* @__PURE__ */ jsx10(Box9, { width: 18, children: /* @__PURE__ */ jsx10(Text9, { children: s.state === "running" ? `${s.itemsDone}/${s.itemsTotal ?? "?"}` : "-" }) }),
5318
- /* @__PURE__ */ jsx10(Box9, { width: 15, children: /* @__PURE__ */ jsx10(Text9, { children: s.enabled ? s.totalFiles : "-" }) }),
5319
- /* @__PURE__ */ jsx10(Box9, { width: 15, children: /* @__PURE__ */ jsx10(Text9, { children: s.enabled ? s.totalChunks : "-" }) }),
5320
- /* @__PURE__ */ jsx10(Box9, { children: /* @__PURE__ */ jsx10(Text9, { children: s.lastFullIndex ? new Date(s.lastFullIndex).toLocaleTimeString() : "-" }) })
5321
- ] }, s.projectName))
5322
- ] })
5323
- ] });
5324
- };
5325
- }
5326
- });
5327
-
5328
5223
  // src/mcp/ui/components/TabBar.tsx
5329
5224
  import "react";
5330
- import { Box as Box10, Text as Text10, useInput as useInput3 } from "ink";
5331
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
5225
+ import { Box as Box8, Text as Text8, useInput as useInput4 } from "ink";
5226
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
5332
5227
  var TabBar;
5333
5228
  var init_TabBar = __esm({
5334
5229
  "src/mcp/ui/components/TabBar.tsx"() {
5335
5230
  "use strict";
5336
5231
  TabBar = ({ tabs, activeTab, onChange }) => {
5337
- useInput3((input, key) => {
5232
+ useInput4((input, key) => {
5338
5233
  if (key.leftArrow) {
5339
5234
  const index = tabs.findIndex((t) => t.id === activeTab);
5340
5235
  if (index !== -1) {
@@ -5355,11 +5250,11 @@ var init_TabBar = __esm({
5355
5250
  if (tab) onChange(tab.id);
5356
5251
  }
5357
5252
  });
5358
- return /* @__PURE__ */ jsxs9(Box10, { borderStyle: "single", paddingX: 1, borderColor: "gray", children: [
5253
+ return /* @__PURE__ */ jsxs7(Box8, { borderStyle: "single", paddingX: 1, borderColor: "gray", children: [
5359
5254
  tabs.map((tab, index) => {
5360
5255
  const isActive = tab.id === activeTab;
5361
- return /* @__PURE__ */ jsx11(Box10, { marginRight: 2, children: /* @__PURE__ */ jsx11(
5362
- Text10,
5256
+ return /* @__PURE__ */ jsx9(Box8, { marginRight: 2, children: /* @__PURE__ */ jsx9(
5257
+ Text8,
5363
5258
  {
5364
5259
  color: isActive ? "cyan" : "white",
5365
5260
  bold: isActive,
@@ -5368,8 +5263,8 @@ var init_TabBar = __esm({
5368
5263
  }
5369
5264
  ) }, tab.id);
5370
5265
  }),
5371
- /* @__PURE__ */ jsx11(Box10, { flexGrow: 1 }),
5372
- /* @__PURE__ */ jsx11(Text10, { color: "dim", children: "Use \u25C4/\u25BA arrows to navigate" })
5266
+ /* @__PURE__ */ jsx9(Box8, { flexGrow: 1 }),
5267
+ /* @__PURE__ */ jsx9(Text8, { color: "dim", children: "Use \u25C4/\u25BA arrows to navigate" })
5373
5268
  ] });
5374
5269
  };
5375
5270
  }
@@ -5380,63 +5275,55 @@ var App_exports = {};
5380
5275
  __export(App_exports, {
5381
5276
  App: () => App
5382
5277
  });
5383
- import { useState as useState6, useEffect as useEffect6, useMemo as useMemo4, useCallback as useCallback3 } from "react";
5384
- import { Box as Box11, useInput as useInput4, useApp } from "ink";
5278
+ import { useState as useState5, useEffect as useEffect6, useMemo as useMemo5, useCallback as useCallback3 } from "react";
5279
+ import { Box as Box9, useInput as useInput5, useApp } from "ink";
5385
5280
  import fs20 from "fs";
5386
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
5281
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
5387
5282
  var App;
5388
5283
  var init_App = __esm({
5389
5284
  "src/mcp/ui/App.tsx"() {
5390
5285
  "use strict";
5391
5286
  init_Overview();
5392
5287
  init_ProjectsView();
5393
- init_InstallView();
5288
+ init_TasksView();
5394
5289
  init_LogViewer();
5395
5290
  init_StatusBoard();
5396
- init_IndexingStatus();
5397
5291
  init_TabBar();
5398
- init_config();
5399
5292
  init_config_utils();
5400
- init_detection();
5401
5293
  init_logger();
5402
5294
  init_server();
5403
- init_resources();
5404
- init_install();
5405
5295
  init_paths();
5296
+ init_install();
5406
5297
  init_ConfigContext();
5407
5298
  App = ({ onExit, initialPort }) => {
5408
5299
  const { exit } = useApp();
5409
5300
  const { config, projects, exposedProjects, driftReports, refresh: refreshData } = useConfig();
5410
- const [activeTab, setActiveTab] = useState6("overview");
5411
- const [logs, setLogs] = useState6([]);
5412
- const [serverInfo, setServerInfo] = useState6({
5301
+ const [activeTab, setActiveTab] = useState5("overview");
5302
+ const [logs, setLogs] = useState5([]);
5303
+ const [serverInfo, setServerInfo] = useState5({
5413
5304
  port: initialPort,
5414
5305
  pid: process.pid,
5415
5306
  running: false
5416
5307
  });
5417
- const isRAGEnabled = useMemo4(() => {
5308
+ const workspacePath = useMemo5(() => detectWorkspaceRoot(), []);
5309
+ const isRAGEnabled = useMemo5(() => {
5418
5310
  return exposedProjects.some((p) => {
5419
5311
  const cfg = findProjectConfig(config, { name: p.name, path: p.path });
5420
5312
  return cfg?.semanticSearch?.enabled || p.semanticSearchEnabled;
5421
5313
  });
5422
5314
  }, [exposedProjects, config]);
5423
- const hasAnyDrift = useMemo4(
5315
+ const hasAnyDrift = useMemo5(
5424
5316
  () => Object.values(driftReports).some((r) => r.hasDrift),
5425
5317
  [driftReports]
5426
5318
  );
5427
- const tabs = useMemo4(() => {
5428
- const baseTabs = [
5319
+ const tabs = useMemo5(() => {
5320
+ return [
5429
5321
  { id: "overview", label: "Overview" },
5430
5322
  { id: "logs", label: "Logs" },
5431
- { id: "projects", label: "Projects" },
5432
- { id: "install", label: "Install" }
5323
+ { id: "tasks", label: "Tasks" },
5324
+ { id: "projects", label: "Projects" }
5433
5325
  ];
5434
- if (isRAGEnabled) {
5435
- baseTabs.splice(3, 0, { id: "indexing", label: "Indexing" });
5436
- }
5437
- return baseTabs;
5438
- }, [isRAGEnabled]);
5439
- const workspacePath = detectWorkspaceRoot();
5326
+ }, []);
5440
5327
  const installStatus = checkInstallStatus(workspacePath);
5441
5328
  const installedCount = [
5442
5329
  installStatus.antigravity,
@@ -5487,7 +5374,7 @@ var init_App = __esm({
5487
5374
  }, 500);
5488
5375
  return () => clearInterval(interval);
5489
5376
  }, []);
5490
- useInput4(async (input, key) => {
5377
+ useInput5(async (input, key) => {
5491
5378
  if (input === "q" || key.ctrl && input === "c") {
5492
5379
  stopMCPServer();
5493
5380
  onExit();
@@ -5511,10 +5398,10 @@ var init_App = __esm({
5511
5398
  const handleConfigChange = useCallback3(() => {
5512
5399
  refreshData();
5513
5400
  }, [refreshData]);
5514
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", padding: 0, height: termHeight, children: [
5515
- /* @__PURE__ */ jsx12(TabBar, { tabs, activeTab, onChange: setActiveTab }),
5516
- /* @__PURE__ */ jsxs10(Box11, { marginTop: 1, flexGrow: 1, children: [
5517
- activeTab === "overview" && /* @__PURE__ */ jsx12(
5401
+ return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", padding: 0, height: termHeight, children: [
5402
+ /* @__PURE__ */ jsx10(TabBar, { tabs, activeTab, onChange: setActiveTab }),
5403
+ /* @__PURE__ */ jsxs8(Box9, { marginTop: 1, flexGrow: 1, children: [
5404
+ activeTab === "overview" && /* @__PURE__ */ jsx10(
5518
5405
  Overview,
5519
5406
  {
5520
5407
  serverStatus: serverInfo,
@@ -5522,15 +5409,15 @@ var init_App = __esm({
5522
5409
  exposedProjects: exposedProjects.length,
5523
5410
  totalProjects: projects.length,
5524
5411
  installedIntegrations: installedCount
5525
- }
5412
+ },
5413
+ logs
5526
5414
  }
5527
5415
  ),
5528
- activeTab === "projects" && /* @__PURE__ */ jsx12(ProjectsView, { config, projects, onConfigChange: handleConfigChange }),
5529
- activeTab === "indexing" && /* @__PURE__ */ jsx12(IndexingStatus, { config, projects: exposedProjects }),
5530
- activeTab === "install" && /* @__PURE__ */ jsx12(InstallView, {}),
5531
- activeTab === "logs" && /* @__PURE__ */ jsx12(LogViewer, { logs, height: contentHeight })
5416
+ activeTab === "logs" && /* @__PURE__ */ jsx10(LogViewer, { logs, height: contentHeight }),
5417
+ activeTab === "tasks" && /* @__PURE__ */ jsx10(TasksView, { projects, workspacePath }),
5418
+ activeTab === "projects" && /* @__PURE__ */ jsx10(ProjectsView, { config, projects, onConfigChange: handleConfigChange, workspacePath })
5532
5419
  ] }),
5533
- /* @__PURE__ */ jsx12(Box11, { marginTop: 0, children: /* @__PURE__ */ jsx12(
5420
+ /* @__PURE__ */ jsx10(Box9, { marginTop: 0, children: /* @__PURE__ */ jsx10(
5534
5421
  StatusBoard,
5535
5422
  {
5536
5423
  exposedLabel: `${exposedProjects.length} / ${projects.length} projects`,
@@ -5548,7 +5435,7 @@ var init_App = __esm({
5548
5435
  // src/mcp/commands/start.ts
5549
5436
  import { confirm as confirm3, isCancel as isCancel5, text } from "@clack/prompts";
5550
5437
  async function handleStartServer() {
5551
- const React13 = await import("react");
5438
+ const React11 = await import("react");
5552
5439
  const { render } = await import("ink");
5553
5440
  const { App: App2 } = await Promise.resolve().then(() => (init_App(), App_exports));
5554
5441
  const { ConfigProvider: ConfigProvider2 } = await Promise.resolve().then(() => (init_ConfigContext(), ConfigContext_exports));
@@ -5591,10 +5478,10 @@ async function handleStartServer() {
5591
5478
  }
5592
5479
  process.stdin.resume();
5593
5480
  const app = render(
5594
- React13.createElement(
5481
+ React11.createElement(
5595
5482
  ConfigProvider2,
5596
5483
  null,
5597
- React13.createElement(App2, {
5484
+ React11.createElement(App2, {
5598
5485
  initialPort,
5599
5486
  onExit: () => {
5600
5487
  }
@@ -6407,8 +6294,8 @@ linked_projects:
6407
6294
  async function registerWithMCP(config, workspacePath, workspaceName) {
6408
6295
  if (!config.exposeToMCP) return;
6409
6296
  try {
6410
- const { loadMCPConfig: loadMCPConfig3, saveMCPConfig: saveMCPConfig2, setProjectConfig: setProjectConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
6411
- const mcpConfig = loadMCPConfig3();
6297
+ const { loadMCPConfig: loadMCPConfig2, saveMCPConfig: saveMCPConfig2, setProjectConfig: setProjectConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
6298
+ const mcpConfig = loadMCPConfig2();
6412
6299
  setProjectConfig2(
6413
6300
  mcpConfig,
6414
6301
  workspaceName,
@@ -6801,8 +6688,8 @@ linked_projects:
6801
6688
  });
6802
6689
  if (shouldExpose && !isCancel9(shouldExpose)) {
6803
6690
  try {
6804
- const { loadMCPConfig: loadMCPConfig3, saveMCPConfig: saveMCPConfig2, setProjectConfig: setProjectConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
6805
- const mcpConfig = loadMCPConfig3();
6691
+ const { loadMCPConfig: loadMCPConfig2, saveMCPConfig: saveMCPConfig2, setProjectConfig: setProjectConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
6692
+ const mcpConfig = loadMCPConfig2();
6806
6693
  for (const project of selectedProjects) {
6807
6694
  setProjectConfig2(mcpConfig, project.name, true, void 0, project.dataPath);
6808
6695
  }