rrce-workflow 0.2.77 → 0.2.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1032,14 +1032,15 @@ function isVSCodeInstalled() {
1032
1032
  const configDir = path6.join(os.homedir(), ".config/Code/User");
1033
1033
  return fs5.existsSync(configDir);
1034
1034
  }
1035
- var ANTIGRAVITY_CONFIG, CLAUDE_CONFIG, VSCODE_GLOBAL_CONFIG, OPENCODE_CONFIG;
1035
+ var ANTIGRAVITY_CONFIG, CLAUDE_CONFIG, VSCODE_GLOBAL_CONFIG, OPENCODE_CONFIG_DIR, OPENCODE_CONFIG;
1036
1036
  var init_install = __esm({
1037
1037
  "src/mcp/install.ts"() {
1038
1038
  "use strict";
1039
1039
  ANTIGRAVITY_CONFIG = path6.join(os.homedir(), ".gemini/antigravity/mcp_config.json");
1040
1040
  CLAUDE_CONFIG = path6.join(os.homedir(), ".config/claude/claude_desktop_config.json");
1041
1041
  VSCODE_GLOBAL_CONFIG = path6.join(os.homedir(), ".config/Code/User/settings.json");
1042
- OPENCODE_CONFIG = path6.join(os.homedir(), ".config/opencode/opencode.json");
1042
+ OPENCODE_CONFIG_DIR = path6.join(os.homedir(), ".config/opencode");
1043
+ OPENCODE_CONFIG = path6.join(OPENCODE_CONFIG_DIR, "opencode.json");
1043
1044
  }
1044
1045
  });
1045
1046
 
@@ -1249,7 +1250,7 @@ var init_prompts = __esm({
1249
1250
  // src/commands/wizard/utils.ts
1250
1251
  import * as fs7 from "fs";
1251
1252
  import * as path8 from "path";
1252
- import { stringify } from "yaml";
1253
+ import "yaml";
1253
1254
  function copyPromptsToDir(prompts, targetDir, extension) {
1254
1255
  for (const prompt of prompts) {
1255
1256
  const baseName = path8.basename(prompt.filePath, ".md");
@@ -1261,29 +1262,24 @@ function copyPromptsToDir(prompts, targetDir, extension) {
1261
1262
  }
1262
1263
  function convertToOpenCodeAgent(prompt) {
1263
1264
  const { frontmatter, content } = prompt;
1264
- const tools = {
1265
- // Enable standard host tools by default
1266
- "read": true,
1267
- "write": true,
1268
- "edit": true,
1269
- "bash": true,
1270
- "grep": true,
1271
- "glob": true,
1272
- "webfetch": true
1273
- };
1265
+ const tools = {};
1266
+ const hostTools = ["read", "write", "edit", "bash", "grep", "glob", "webfetch", "terminalLastCommand"];
1274
1267
  if (frontmatter.tools) {
1275
1268
  for (const tool of frontmatter.tools) {
1276
- tools[`rrce_${tool}`] = true;
1269
+ if (hostTools.includes(tool)) {
1270
+ tools[tool] = true;
1271
+ } else {
1272
+ tools[`rrce_${tool}`] = true;
1273
+ }
1277
1274
  }
1278
1275
  }
1279
- const opencodeFrontmatter = {
1276
+ tools["webfetch"] = true;
1277
+ return {
1280
1278
  description: frontmatter.description,
1281
1279
  mode: "primary",
1280
+ prompt: content,
1282
1281
  tools
1283
1282
  };
1284
- return `---
1285
- ${stringify(opencodeFrontmatter)}---
1286
- ${content}`;
1287
1283
  }
1288
1284
  function copyDirRecursive(src, dest) {
1289
1285
  const entries = fs7.readdirSync(src, { withFileTypes: true });
@@ -1657,6 +1653,7 @@ import * as fs10 from "fs";
1657
1653
  import * as path12 from "path";
1658
1654
  import pc4 from "picocolors";
1659
1655
  import { note as note2 } from "@clack/prompts";
1656
+ import { stringify as stringify2 } from "yaml";
1660
1657
  function createDirectoryStructure(dataPaths) {
1661
1658
  for (const dataPath of dataPaths) {
1662
1659
  ensureDir(dataPath);
@@ -1666,7 +1663,7 @@ function createDirectoryStructure(dataPaths) {
1666
1663
  ensureDir(path12.join(dataPath, "templates"));
1667
1664
  }
1668
1665
  }
1669
- function installAgentPrompts(config, workspacePath, dataPaths) {
1666
+ async function installAgentPrompts(config, workspacePath, dataPaths) {
1670
1667
  const agentCoreDir = getAgentCoreDir();
1671
1668
  syncMetadataToAll(agentCoreDir, dataPaths);
1672
1669
  copyDirToAllStoragePaths(path12.join(agentCoreDir, "templates"), "templates", dataPaths);
@@ -1695,30 +1692,36 @@ function installAgentPrompts(config, workspacePath, dataPaths) {
1695
1692
  if (config.tools.includes("opencode")) {
1696
1693
  const primaryDataPath = dataPaths[0];
1697
1694
  if (primaryDataPath) {
1698
- const opencodePath = path12.join(primaryDataPath, ".opencode", "agent");
1699
- ensureDir(opencodePath);
1700
- for (const prompt of prompts) {
1701
- const baseName = path12.basename(prompt.filePath, ".md");
1702
- const content = convertToOpenCodeAgent(prompt);
1703
- fs10.writeFileSync(path12.join(opencodePath, `${baseName}.md`), content);
1704
- }
1705
1695
  if (config.storageMode === "global") {
1706
- const workspaceOpencode = path12.join(workspacePath, ".opencode");
1707
- const globalOpencode = path12.join(primaryDataPath, ".opencode");
1708
1696
  try {
1709
- if (fs10.existsSync(workspaceOpencode)) {
1710
- fs10.rmSync(workspaceOpencode, { recursive: true, force: true });
1711
- } else {
1712
- try {
1713
- if (fs10.lstatSync(workspaceOpencode).isSymbolicLink()) {
1714
- fs10.unlinkSync(workspaceOpencode);
1715
- }
1716
- } catch (e) {
1717
- }
1697
+ let opencodeConfig = { $schema: "https://opencode.ai/config.json" };
1698
+ if (fs10.existsSync(OPENCODE_CONFIG)) {
1699
+ opencodeConfig = JSON.parse(fs10.readFileSync(OPENCODE_CONFIG, "utf-8"));
1718
1700
  }
1719
- fs10.symlinkSync(globalOpencode, workspaceOpencode, "dir");
1701
+ if (!opencodeConfig.agent) opencodeConfig.agent = {};
1702
+ for (const prompt of prompts) {
1703
+ const baseName = path12.basename(prompt.filePath, ".md");
1704
+ const agentConfig = convertToOpenCodeAgent(prompt);
1705
+ opencodeConfig.agent[baseName] = agentConfig;
1706
+ }
1707
+ fs10.writeFileSync(OPENCODE_CONFIG, JSON.stringify(opencodeConfig, null, 2) + "\n");
1720
1708
  } catch (e) {
1721
- console.error(`Warning: Could not create OpenCode symlink at ${workspaceOpencode}:`, e instanceof Error ? e.message : String(e));
1709
+ console.error("Failed to update global OpenCode config with agents:", e);
1710
+ }
1711
+ } else {
1712
+ const opencodeBaseDir = path12.join(primaryDataPath, ".opencode", "agent");
1713
+ ensureDir(opencodeBaseDir);
1714
+ for (const prompt of prompts) {
1715
+ const baseName = path12.basename(prompt.filePath, ".md");
1716
+ const agentConfig = convertToOpenCodeAgent(prompt);
1717
+ const content = `---
1718
+ ${stringify2({
1719
+ description: agentConfig.description,
1720
+ mode: agentConfig.mode,
1721
+ tools: agentConfig.tools
1722
+ })}---
1723
+ ${agentConfig.prompt}`;
1724
+ fs10.writeFileSync(path12.join(opencodeBaseDir, `${baseName}.md`), content);
1722
1725
  }
1723
1726
  }
1724
1727
  }
@@ -1857,13 +1860,15 @@ function updateGitignore(workspacePath, storageMode, tools) {
1857
1860
  const entries = [];
1858
1861
  if (storageMode === "workspace") {
1859
1862
  entries.push(".rrce-workflow/");
1860
- }
1861
- entries.push(".opencode/");
1862
- if (tools.includes("copilot")) {
1863
- entries.push(".github/agents/");
1864
- }
1865
- if (tools.includes("antigravity")) {
1866
- entries.push(".agent/workflows/");
1863
+ if (tools.includes("opencode")) {
1864
+ entries.push(".opencode/");
1865
+ }
1866
+ if (tools.includes("copilot")) {
1867
+ entries.push(".github/agents/");
1868
+ }
1869
+ if (tools.includes("antigravity")) {
1870
+ entries.push(".agent/workflows/");
1871
+ }
1867
1872
  }
1868
1873
  entries.push("*.code-workspace");
1869
1874
  if (entries.length === 0) {
@@ -2206,6 +2211,7 @@ var init_rag = __esm({
2206
2211
  // src/mcp/resources.ts
2207
2212
  import * as fs14 from "fs";
2208
2213
  import * as path16 from "path";
2214
+ import * as crypto from "crypto";
2209
2215
  function getExposedProjects() {
2210
2216
  const config = loadMCPConfig();
2211
2217
  const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
@@ -2526,9 +2532,101 @@ All file operations should be relative to WORKSPACE_ROOT shown above.
2526
2532
  `;
2527
2533
  return contextPreamble;
2528
2534
  }
2535
+ function getTask(projectName, taskSlug) {
2536
+ const config = loadMCPConfig();
2537
+ const projects = projectService.scan();
2538
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.path));
2539
+ if (!project || !project.tasksPath) return null;
2540
+ const metaPath = path16.join(project.tasksPath, taskSlug, "meta.json");
2541
+ if (!fs14.existsSync(metaPath)) return null;
2542
+ try {
2543
+ return JSON.parse(fs14.readFileSync(metaPath, "utf-8"));
2544
+ } catch {
2545
+ return null;
2546
+ }
2547
+ }
2548
+ async function createTask(projectName, taskSlug, taskData) {
2549
+ const config = loadMCPConfig();
2550
+ const projects = projectService.scan();
2551
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.path));
2552
+ if (!project || !project.tasksPath) {
2553
+ throw new Error(`Project '${projectName}' not found or not configured with a tasks path.`);
2554
+ }
2555
+ const taskDir = path16.join(project.tasksPath, taskSlug);
2556
+ if (fs14.existsSync(taskDir)) {
2557
+ throw new Error(`Task with slug '${taskSlug}' already exists.`);
2558
+ }
2559
+ fs14.mkdirSync(taskDir, { recursive: true });
2560
+ fs14.mkdirSync(path16.join(taskDir, "research"), { recursive: true });
2561
+ fs14.mkdirSync(path16.join(taskDir, "planning"), { recursive: true });
2562
+ fs14.mkdirSync(path16.join(taskDir, "execution"), { recursive: true });
2563
+ fs14.mkdirSync(path16.join(taskDir, "docs"), { recursive: true });
2564
+ const rrceHome = process.env.RRCE_HOME || path16.join(__require("os").homedir(), ".rrce-workflow");
2565
+ const templatePath = path16.join(rrceHome, "templates", "meta.template.json");
2566
+ let meta = {
2567
+ task_id: crypto.randomUUID(),
2568
+ task_slug: taskSlug,
2569
+ status: "draft",
2570
+ agents: {}
2571
+ };
2572
+ if (fs14.existsSync(templatePath)) {
2573
+ try {
2574
+ const template = JSON.parse(fs14.readFileSync(templatePath, "utf-8"));
2575
+ meta = { ...template, ...meta };
2576
+ } catch (e) {
2577
+ logger.error("Failed to load meta template", e);
2578
+ }
2579
+ }
2580
+ meta.created_at = (/* @__PURE__ */ new Date()).toISOString();
2581
+ meta.updated_at = meta.created_at;
2582
+ meta.workspace = {
2583
+ name: project.name,
2584
+ path: project.path || project.dataPath,
2585
+ hash: project.name
2586
+ };
2587
+ Object.assign(meta, taskData);
2588
+ const metaPath = path16.join(taskDir, "meta.json");
2589
+ fs14.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
2590
+ return meta;
2591
+ }
2592
+ async function updateTask(projectName, taskSlug, taskData) {
2593
+ const meta = getTask(projectName, taskSlug);
2594
+ if (!meta) throw new Error(`Task '${taskSlug}' not found.`);
2595
+ const updatedMeta = {
2596
+ ...meta,
2597
+ ...taskData,
2598
+ updated_at: (/* @__PURE__ */ new Date()).toISOString(),
2599
+ // Ensure nested objects are merged if they exist in taskData
2600
+ agents: taskData.agents ? { ...meta.agents, ...taskData.agents } : meta.agents,
2601
+ workspace: meta.workspace
2602
+ // Protect workspace metadata
2603
+ };
2604
+ const config = loadMCPConfig();
2605
+ const projects = projectService.scan();
2606
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.path));
2607
+ if (!project || !project.tasksPath) return null;
2608
+ const metaPath = path16.join(project.tasksPath, taskSlug, "meta.json");
2609
+ fs14.writeFileSync(metaPath, JSON.stringify(updatedMeta, null, 2));
2610
+ return updatedMeta;
2611
+ }
2612
+ function deleteTask(projectName, taskSlug) {
2613
+ const config = loadMCPConfig();
2614
+ const projects = projectService.scan();
2615
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.path));
2616
+ if (!project || !project.tasksPath) return false;
2617
+ const taskDir = path16.join(project.tasksPath, taskSlug);
2618
+ if (!fs14.existsSync(taskDir)) return false;
2619
+ if (fs14.rmSync) {
2620
+ fs14.rmSync(taskDir, { recursive: true, force: true });
2621
+ } else {
2622
+ fs14.rmdirSync(taskDir, { recursive: true });
2623
+ }
2624
+ return true;
2625
+ }
2529
2626
  var init_resources = __esm({
2530
2627
  "src/mcp/resources.ts"() {
2531
2628
  "use strict";
2629
+ init_logger();
2532
2630
  init_config();
2533
2631
  init_config_utils();
2534
2632
  init_detection();
@@ -2771,6 +2869,66 @@ function registerToolHandlers(server) {
2771
2869
  },
2772
2870
  required: ["agent"]
2773
2871
  }
2872
+ },
2873
+ {
2874
+ name: "list_tasks",
2875
+ description: "List all tasks for a project",
2876
+ inputSchema: {
2877
+ type: "object",
2878
+ properties: { project: { type: "string", description: "Name of the project" } },
2879
+ required: ["project"]
2880
+ }
2881
+ },
2882
+ {
2883
+ name: "get_task",
2884
+ description: "Get details of a specific task",
2885
+ inputSchema: {
2886
+ type: "object",
2887
+ properties: {
2888
+ project: { type: "string", description: "Name of the project" },
2889
+ task_slug: { type: "string", description: "The slug of the task" }
2890
+ },
2891
+ required: ["project", "task_slug"]
2892
+ }
2893
+ },
2894
+ {
2895
+ name: "create_task",
2896
+ description: "Create a new task in the project",
2897
+ inputSchema: {
2898
+ type: "object",
2899
+ properties: {
2900
+ project: { type: "string", description: "Name of the project" },
2901
+ task_slug: { type: "string", description: "The slug for the new task (kebab-case)" },
2902
+ title: { type: "string", description: "The title of the task" },
2903
+ summary: { type: "string", description: "Brief summary of the task" }
2904
+ },
2905
+ required: ["project", "task_slug"]
2906
+ }
2907
+ },
2908
+ {
2909
+ name: "update_task",
2910
+ description: "Update an existing task",
2911
+ inputSchema: {
2912
+ type: "object",
2913
+ properties: {
2914
+ project: { type: "string", description: "Name of the project" },
2915
+ task_slug: { type: "string", description: "The slug of the task" },
2916
+ updates: { type: "object", description: "The fields to update in meta.json", additionalProperties: true }
2917
+ },
2918
+ required: ["project", "task_slug", "updates"]
2919
+ }
2920
+ },
2921
+ {
2922
+ name: "delete_task",
2923
+ description: "Delete a task from the project",
2924
+ inputSchema: {
2925
+ type: "object",
2926
+ properties: {
2927
+ project: { type: "string", description: "Name of the project" },
2928
+ task_slug: { type: "string", description: "The slug of the task to delete" }
2929
+ },
2930
+ required: ["project", "task_slug"]
2931
+ }
2774
2932
  }
2775
2933
  ];
2776
2934
  const projects = getExposedProjects();
@@ -2858,6 +3016,38 @@ The system has pre-resolved the configuration for this project. Use these values
2858
3016
  `;
2859
3017
  return { content: [{ type: "text", text: contextPreamble + rendered }] };
2860
3018
  }
3019
+ case "list_tasks": {
3020
+ const params = args;
3021
+ const tasks = getProjectTasks(params.project);
3022
+ return { content: [{ type: "text", text: JSON.stringify(tasks, null, 2) }] };
3023
+ }
3024
+ case "get_task": {
3025
+ const params = args;
3026
+ const task = getTask(params.project, params.task_slug);
3027
+ if (!task) {
3028
+ return { content: [{ type: "text", text: `Task '${params.task_slug}' not found in project '${params.project}'.` }], isError: true };
3029
+ }
3030
+ return { content: [{ type: "text", text: JSON.stringify(task, null, 2) }] };
3031
+ }
3032
+ case "create_task": {
3033
+ const params = args;
3034
+ const taskData = {
3035
+ title: params.title || params.task_slug,
3036
+ summary: params.summary || ""
3037
+ };
3038
+ const task = await createTask(params.project, params.task_slug, taskData);
3039
+ return { content: [{ type: "text", text: JSON.stringify(task, null, 2) }] };
3040
+ }
3041
+ case "update_task": {
3042
+ const params = args;
3043
+ const task = await updateTask(params.project, params.task_slug, params.updates);
3044
+ return { content: [{ type: "text", text: JSON.stringify(task, null, 2) }] };
3045
+ }
3046
+ case "delete_task": {
3047
+ const params = args;
3048
+ const success = deleteTask(params.project, params.task_slug);
3049
+ return { content: [{ type: "text", text: success ? `Task '${params.task_slug}' deleted.` : `Failed to delete task '${params.task_slug}'.` }] };
3050
+ }
2861
3051
  case "help_setup": {
2862
3052
  const msg = `
2863
3053
  RRCE MCP Server is running, but no projects are configured/exposed.
@@ -4363,8 +4553,8 @@ async function runExpressSetup(workspacePath, workspaceName, existingProjects, s
4363
4553
  \u2022 Storage: ${storageMode === "global" ? "Global" : "Workspace"}
4364
4554
  \u2022 MCP Server: Enabled
4365
4555
  \u2022 Semantic Search (RAG): Enabled
4366
- \u2022 Git ignore entries: Added
4367
- \u2022 AI Tools: ${toolsText}`,
4556
+ ` + (storageMode === "workspace" ? `\u2022 Git ignore entries: Added
4557
+ ` : "") + `\u2022 AI Tools: ${toolsText}`,
4368
4558
  "Configuration Preview"
4369
4559
  );
4370
4560
  const confirmed = await confirm6({
@@ -4389,6 +4579,10 @@ async function runExpressSetup(workspacePath, workspaceName, existingProjects, s
4389
4579
  enableRAG: true
4390
4580
  };
4391
4581
  await executeSetup(config, workspacePath, workspaceName, existingProjects, s);
4582
+ if (config.storageMode === "workspace") {
4583
+ const { updateGitignore: updateGitignore2 } = await Promise.resolve().then(() => (init_gitignore(), gitignore_exports));
4584
+ updateGitignore2(workspacePath, config.storageMode, config.tools);
4585
+ }
4392
4586
  const startMCP = await confirm6({
4393
4587
  message: "Start MCP server now?",
4394
4588
  initialValue: true
@@ -4432,7 +4626,7 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
4432
4626
  if (storageMode !== "global") {
4433
4627
  linkedProjects = await promptLinkedProjects(existingProjects);
4434
4628
  }
4435
- const addToGitignore = await promptGitignore();
4629
+ const addToGitignore = storageMode === "workspace" ? await promptGitignore() : false;
4436
4630
  const enableRAG = await promptRAG();
4437
4631
  const confirmed = await promptConfirmation();
4438
4632
  if (!confirmed) {
@@ -4449,6 +4643,10 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
4449
4643
  enableRAG
4450
4644
  };
4451
4645
  await executeSetup(config, workspacePath, workspaceName, existingProjects, s);
4646
+ if (config.storageMode === "workspace" && config.addToGitignore) {
4647
+ const { updateGitignore: updateGitignore2 } = await Promise.resolve().then(() => (init_gitignore(), gitignore_exports));
4648
+ updateGitignore2(workspacePath, config.storageMode, config.tools);
4649
+ }
4452
4650
  await handlePostSetup(config, workspacePath, workspaceName, linkedProjects);
4453
4651
  }
4454
4652
  async function executeSetup(config, workspacePath, workspaceName, allProjects, s) {
@@ -4456,9 +4654,9 @@ async function executeSetup(config, workspacePath, workspaceName, allProjects, s
4456
4654
  try {
4457
4655
  const dataPaths = getDataPaths(config.storageMode, workspaceName, workspacePath, config.globalPath);
4458
4656
  createDirectoryStructure(dataPaths);
4459
- installAgentPrompts(config, workspacePath, dataPaths);
4657
+ await installAgentPrompts(config, workspacePath, dataPaths);
4460
4658
  createWorkspaceConfig(config, workspacePath, workspaceName);
4461
- if (config.addToGitignore) {
4659
+ if (config.storageMode === "workspace" && config.addToGitignore) {
4462
4660
  const { updateGitignore: updateGitignore2 } = await Promise.resolve().then(() => (init_gitignore(), gitignore_exports));
4463
4661
  updateGitignore2(workspacePath, config.storageMode, config.tools);
4464
4662
  }
@@ -4713,6 +4911,7 @@ import { confirm as confirm9, spinner as spinner6, note as note12, outro as outr
4713
4911
  import pc14 from "picocolors";
4714
4912
  import * as fs18 from "fs";
4715
4913
  import * as path19 from "path";
4914
+ import { stringify as stringify3 } from "yaml";
4716
4915
  async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
4717
4916
  const s = spinner6();
4718
4917
  s.start("Checking for updates");
@@ -4723,10 +4922,25 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
4723
4922
  const customGlobalPath = getEffectiveRRCEHome(workspacePath);
4724
4923
  const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
4725
4924
  s.stop("Updates found");
4925
+ const updateTargets = [
4926
+ ` \u2022 prompts/ (${prompts.length} agent prompts)`,
4927
+ ` \u2022 templates/ (output templates)`,
4928
+ ` \u2022 docs/ (documentation)`
4929
+ ];
4930
+ const configFilePath = getConfigPath(workspacePath);
4931
+ const ideTargets = [];
4932
+ if (fs18.existsSync(configFilePath)) {
4933
+ const configContent = fs18.readFileSync(configFilePath, "utf-8");
4934
+ if (configContent.includes("opencode: true")) ideTargets.push("OpenCode agents");
4935
+ if (configContent.includes("copilot: true")) ideTargets.push("GitHub Copilot");
4936
+ if (configContent.includes("antigravity: true")) ideTargets.push("Antigravity");
4937
+ }
4938
+ if (ideTargets.length > 0) {
4939
+ updateTargets.push(` \u2022 IDE integrations: ${ideTargets.join(", ")}`);
4940
+ }
4726
4941
  note12(
4727
4942
  `The following will be updated from the package:
4728
- \u2022 prompts/ (${prompts.length} agent prompts)
4729
- \u2022 templates/ (output templates)
4943
+ ${updateTargets.join("\n")}
4730
4944
 
4731
4945
  Target locations:
4732
4946
  ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
@@ -4743,29 +4957,51 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
4743
4957
  s.start("Updating from package");
4744
4958
  for (const dataPath of dataPaths) {
4745
4959
  copyDirToAllStoragePaths(path19.join(agentCoreDir, "templates"), "templates", [dataPath]);
4960
+ copyDirToAllStoragePaths(path19.join(agentCoreDir, "prompts"), "prompts", [dataPath]);
4961
+ copyDirToAllStoragePaths(path19.join(agentCoreDir, "docs"), "docs", [dataPath]);
4746
4962
  }
4747
- const configFilePath = getConfigPath(workspacePath);
4963
+ const rrceHome = customGlobalPath || getDefaultRRCEHome2();
4964
+ ensureDir(path19.join(rrceHome, "templates"));
4965
+ ensureDir(path19.join(rrceHome, "docs"));
4966
+ copyDirRecursive(path19.join(agentCoreDir, "templates"), path19.join(rrceHome, "templates"));
4967
+ copyDirRecursive(path19.join(agentCoreDir, "docs"), path19.join(rrceHome, "docs"));
4748
4968
  if (fs18.existsSync(configFilePath)) {
4749
4969
  const configContent = fs18.readFileSync(configFilePath, "utf-8");
4750
4970
  if (configContent.includes("copilot: true")) {
4751
4971
  const copilotPath = getAgentPromptPath(workspacePath, "copilot");
4752
4972
  ensureDir(copilotPath);
4973
+ clearDirectory(copilotPath);
4753
4974
  copyPromptsToDir(prompts, copilotPath, ".agent.md");
4754
4975
  }
4755
4976
  if (configContent.includes("antigravity: true")) {
4756
4977
  const antigravityPath = getAgentPromptPath(workspacePath, "antigravity");
4757
4978
  ensureDir(antigravityPath);
4979
+ clearDirectory(antigravityPath);
4758
4980
  copyPromptsToDir(prompts, antigravityPath, ".md");
4759
4981
  }
4982
+ if (configContent.includes("opencode: true")) {
4983
+ const primaryDataPath = dataPaths[0];
4984
+ if (primaryDataPath) {
4985
+ updateOpenCodeAgents(prompts, mode, primaryDataPath);
4986
+ }
4987
+ }
4760
4988
  }
4761
4989
  s.stop("Update complete");
4762
4990
  const summary = [
4763
4991
  `Updated:`,
4764
4992
  ` \u2713 ${prompts.length} agent prompts`,
4765
4993
  ` \u2713 Output templates`,
4766
- ``,
4767
- `Your configuration and knowledge files were preserved.`
4994
+ ` \u2713 Documentation`
4768
4995
  ];
4996
+ if (ideTargets.length > 0) {
4997
+ summary.push(` \u2713 IDE integrations: ${ideTargets.join(", ")}`);
4998
+ }
4999
+ summary.push(
5000
+ ``,
5001
+ `Your configuration and knowledge files were preserved.`,
5002
+ ``,
5003
+ pc14.dim(`\u{1F4A1} If using OpenCode, you may need to reload for changes to take effect.`)
5004
+ );
4769
5005
  note12(summary.join("\n"), "Update Summary");
4770
5006
  outro5(pc14.green("\u2713 Successfully updated from package!"));
4771
5007
  } catch (error) {
@@ -4774,6 +5010,60 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
4774
5010
  process.exit(1);
4775
5011
  }
4776
5012
  }
5013
+ function updateOpenCodeAgents(prompts, mode, primaryDataPath) {
5014
+ if (mode === "global") {
5015
+ try {
5016
+ let opencodeConfig = { $schema: "https://opencode.ai/config.json" };
5017
+ if (fs18.existsSync(OPENCODE_CONFIG)) {
5018
+ opencodeConfig = JSON.parse(fs18.readFileSync(OPENCODE_CONFIG, "utf-8"));
5019
+ }
5020
+ if (!opencodeConfig.agent) opencodeConfig.agent = {};
5021
+ const currentAgentNames = prompts.map((p) => path19.basename(p.filePath, ".md"));
5022
+ const existingAgentNames = Object.keys(opencodeConfig.agent);
5023
+ const rrceAgentPrefixes = ["init", "research", "planning", "executor", "doctor", "documentation", "sync"];
5024
+ for (const existingName of existingAgentNames) {
5025
+ const isRrceAgent = rrceAgentPrefixes.some((prefix) => existingName.startsWith(prefix));
5026
+ const stillExists = currentAgentNames.includes(existingName);
5027
+ if (isRrceAgent && !stillExists) {
5028
+ delete opencodeConfig.agent[existingName];
5029
+ }
5030
+ }
5031
+ for (const prompt of prompts) {
5032
+ const baseName = path19.basename(prompt.filePath, ".md");
5033
+ const agentConfig = convertToOpenCodeAgent(prompt);
5034
+ opencodeConfig.agent[baseName] = agentConfig;
5035
+ }
5036
+ fs18.writeFileSync(OPENCODE_CONFIG, JSON.stringify(opencodeConfig, null, 2) + "\n");
5037
+ } catch (e) {
5038
+ console.error("Failed to update global OpenCode config with agents:", e);
5039
+ }
5040
+ } else {
5041
+ const opencodeBaseDir = path19.join(primaryDataPath, ".opencode", "agent");
5042
+ ensureDir(opencodeBaseDir);
5043
+ clearDirectory(opencodeBaseDir);
5044
+ for (const prompt of prompts) {
5045
+ const baseName = path19.basename(prompt.filePath, ".md");
5046
+ const agentConfig = convertToOpenCodeAgent(prompt);
5047
+ const content = `---
5048
+ ${stringify3({
5049
+ description: agentConfig.description,
5050
+ mode: agentConfig.mode,
5051
+ tools: agentConfig.tools
5052
+ })}---
5053
+ ${agentConfig.prompt}`;
5054
+ fs18.writeFileSync(path19.join(opencodeBaseDir, `${baseName}.md`), content);
5055
+ }
5056
+ }
5057
+ }
5058
+ function clearDirectory(dirPath) {
5059
+ if (!fs18.existsSync(dirPath)) return;
5060
+ const entries = fs18.readdirSync(dirPath, { withFileTypes: true });
5061
+ for (const entry of entries) {
5062
+ if (entry.isFile()) {
5063
+ fs18.unlinkSync(path19.join(dirPath, entry.name));
5064
+ }
5065
+ }
5066
+ }
4777
5067
  function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
4778
5068
  const globalPath = path19.join(customGlobalPath, "workspaces", workspaceName);
4779
5069
  const workspacePath = path19.join(workspaceRoot, ".rrce-workflow");
@@ -4792,6 +5082,7 @@ var init_update_flow = __esm({
4792
5082
  init_paths();
4793
5083
  init_prompts();
4794
5084
  init_utils();
5085
+ init_install();
4795
5086
  }
4796
5087
  });
4797
5088
 
@@ -7,7 +7,9 @@
7
7
  RRCE-Workflow is a TUI-based agentic code workflow generator designed to work seamlessly across:
8
8
  - **GitHub Copilot CLI**
9
9
  - **Antigravity IDE** (Google's agentic coding environment)
10
+ - **OpenCode** (Native agentic TUI environment)
10
11
  - **VS Code** (with Copilot and other AI extensions)
12
+ - **Claude Desktop**
11
13
 
12
14
  The system provides a structured multi-agent pipeline for software development tasks, with persistent knowledge caching and workspace-aware context management.
13
15
 
@@ -243,6 +245,7 @@ RRCE-Workflow prompts are designed to work across multiple AI coding tools:
243
245
  | Tool | Prompt Location | Extension | Notes |
244
246
  |------|----------------|-----------|-------|
245
247
  | **Antigravity IDE** | `.agent/workflows/` | `.md` | Native workflow support |
248
+ | **OpenCode** | `.opencode/agent/` | `.md` | Custom Primary Agents |
246
249
  | **GitHub Copilot (VSCode)** | `.github/agents/` | `.agent.md` | Custom agents format |
247
250
  | **Copilot CLI** | Any location | `.md` | Reference via file path |
248
251
 
@@ -298,6 +301,17 @@ When you run `rrce-workflow wizard`, it creates:
298
301
  └── sync.md
299
302
  ```
300
303
 
304
+ **For OpenCode:**
305
+ ```
306
+ .opencode/agent/
307
+ ├── rrce-init.md
308
+ ├── rrce-research.md
309
+ ├── rrce-planning.md
310
+ ├── rrce-executor.md
311
+ ├── rrce-documentation.md
312
+ └── rrce-sync.md
313
+ ```
314
+
301
315
  ### Copilot-Specific Features
302
316
 
303
317
  Our prompts include Copilot-compatible frontmatter:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rrce-workflow",
3
- "version": "0.2.77",
3
+ "version": "0.2.79",
4
4
  "description": "RRCE-Workflow TUI - Agentic code workflow generator for AI-assisted development",
5
5
  "author": "RRCE Team",
6
6
  "license": "MIT",