rrce-workflow 0.2.18 → 0.2.19
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 +253 -120
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/commands/wizard/index.ts
|
|
2
2
|
import { intro, select as select2, spinner as spinner5, note as note5, outro as outro5, isCancel as isCancel5 } from "@clack/prompts";
|
|
3
|
-
import
|
|
4
|
-
import * as
|
|
3
|
+
import pc6 from "picocolors";
|
|
4
|
+
import * as fs11 from "fs";
|
|
5
5
|
|
|
6
6
|
// src/lib/git.ts
|
|
7
7
|
import { execSync } from "child_process";
|
|
@@ -136,24 +136,42 @@ function getEffectiveRRCEHome(workspaceRoot) {
|
|
|
136
136
|
// src/lib/detection.ts
|
|
137
137
|
import * as fs2 from "fs";
|
|
138
138
|
import * as path2 from "path";
|
|
139
|
+
var SKIP_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
140
|
+
"node_modules",
|
|
141
|
+
".git",
|
|
142
|
+
".cache",
|
|
143
|
+
".npm",
|
|
144
|
+
".yarn",
|
|
145
|
+
".pnpm",
|
|
146
|
+
".local",
|
|
147
|
+
".config",
|
|
148
|
+
".vscode",
|
|
149
|
+
".vscode-server",
|
|
150
|
+
"Library",
|
|
151
|
+
"Applications",
|
|
152
|
+
".Trash",
|
|
153
|
+
"snap",
|
|
154
|
+
".cargo",
|
|
155
|
+
".rustup",
|
|
156
|
+
".go",
|
|
157
|
+
".docker"
|
|
158
|
+
]);
|
|
139
159
|
function scanForProjects(options = {}) {
|
|
140
|
-
const { excludeWorkspace, workspacePath
|
|
160
|
+
const { excludeWorkspace, workspacePath } = options;
|
|
141
161
|
const projects = [];
|
|
142
162
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
143
163
|
const globalProjects = scanGlobalStorage(excludeWorkspace);
|
|
144
164
|
for (const project of globalProjects) {
|
|
145
|
-
if (!seenPaths.has(project.
|
|
146
|
-
seenPaths.add(project.
|
|
165
|
+
if (!seenPaths.has(project.dataPath)) {
|
|
166
|
+
seenPaths.add(project.dataPath);
|
|
147
167
|
projects.push(project);
|
|
148
168
|
}
|
|
149
169
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
projects.push(project);
|
|
156
|
-
}
|
|
170
|
+
const homeProjects = scanHomeDirectory(workspacePath);
|
|
171
|
+
for (const project of homeProjects) {
|
|
172
|
+
if (!seenPaths.has(project.dataPath)) {
|
|
173
|
+
seenPaths.add(project.dataPath);
|
|
174
|
+
projects.push(project);
|
|
157
175
|
}
|
|
158
176
|
}
|
|
159
177
|
return projects;
|
|
@@ -189,37 +207,49 @@ function scanGlobalStorage(excludeWorkspace) {
|
|
|
189
207
|
}
|
|
190
208
|
return projects;
|
|
191
209
|
}
|
|
192
|
-
function
|
|
193
|
-
const
|
|
210
|
+
function scanHomeDirectory(excludePath) {
|
|
211
|
+
const home = process.env.HOME;
|
|
212
|
+
if (!home) return [];
|
|
194
213
|
const projects = [];
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
const maxDepth = 5;
|
|
215
|
+
function scanDir(dirPath, depth) {
|
|
216
|
+
if (depth > maxDepth) return;
|
|
217
|
+
try {
|
|
218
|
+
const entries = fs2.readdirSync(dirPath, { withFileTypes: true });
|
|
219
|
+
for (const entry of entries) {
|
|
220
|
+
if (!entry.isDirectory()) continue;
|
|
221
|
+
const fullPath = path2.join(dirPath, entry.name);
|
|
222
|
+
if (excludePath && fullPath === excludePath) continue;
|
|
223
|
+
if (entry.name === ".rrce-workflow") {
|
|
224
|
+
const configPath = path2.join(fullPath, "config.yaml");
|
|
225
|
+
if (fs2.existsSync(configPath)) {
|
|
226
|
+
const projectPath = dirPath;
|
|
227
|
+
const projectName = path2.basename(projectPath);
|
|
228
|
+
const config = parseWorkspaceConfig(configPath);
|
|
229
|
+
const knowledgePath = path2.join(fullPath, "knowledge");
|
|
230
|
+
const refsPath = path2.join(fullPath, "refs");
|
|
231
|
+
const tasksPath = path2.join(fullPath, "tasks");
|
|
232
|
+
projects.push({
|
|
233
|
+
name: config?.name || projectName,
|
|
234
|
+
path: projectPath,
|
|
235
|
+
dataPath: fullPath,
|
|
236
|
+
source: "local",
|
|
237
|
+
storageMode: config?.storageMode,
|
|
238
|
+
knowledgePath: fs2.existsSync(knowledgePath) ? knowledgePath : void 0,
|
|
239
|
+
refsPath: fs2.existsSync(refsPath) ? refsPath : void 0,
|
|
240
|
+
tasksPath: fs2.existsSync(tasksPath) ? tasksPath : void 0
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (SKIP_DIRECTORIES.has(entry.name)) continue;
|
|
246
|
+
if (entry.name.startsWith(".") && entry.name !== ".rrce-workflow") continue;
|
|
247
|
+
scanDir(fullPath, depth + 1);
|
|
248
|
+
}
|
|
249
|
+
} catch {
|
|
220
250
|
}
|
|
221
|
-
} catch {
|
|
222
251
|
}
|
|
252
|
+
scanDir(home, 0);
|
|
223
253
|
return projects;
|
|
224
254
|
}
|
|
225
255
|
function parseWorkspaceConfig(configPath) {
|
|
@@ -249,10 +279,10 @@ function parseWorkspaceConfig(configPath) {
|
|
|
249
279
|
}
|
|
250
280
|
|
|
251
281
|
// src/commands/wizard/setup-flow.ts
|
|
252
|
-
import { group,
|
|
253
|
-
import
|
|
254
|
-
import * as
|
|
255
|
-
import * as
|
|
282
|
+
import { group, select, multiselect, confirm, spinner, note, outro, cancel, isCancel } from "@clack/prompts";
|
|
283
|
+
import pc2 from "picocolors";
|
|
284
|
+
import * as fs7 from "fs";
|
|
285
|
+
import * as path7 from "path";
|
|
256
286
|
|
|
257
287
|
// src/lib/prompts.ts
|
|
258
288
|
import * as fs3 from "fs";
|
|
@@ -433,6 +463,113 @@ function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, c
|
|
|
433
463
|
fs5.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
|
|
434
464
|
}
|
|
435
465
|
|
|
466
|
+
// src/lib/autocomplete-prompt.ts
|
|
467
|
+
import * as fs6 from "fs";
|
|
468
|
+
import * as path6 from "path";
|
|
469
|
+
import * as readline from "readline";
|
|
470
|
+
import pc from "picocolors";
|
|
471
|
+
function directoryPrompt(opts) {
|
|
472
|
+
return new Promise((resolve) => {
|
|
473
|
+
process.stdout.write(`${pc.cyan("\u25C6")} ${opts.message}
|
|
474
|
+
`);
|
|
475
|
+
process.stdout.write(`${pc.cyan("\u2502")} `);
|
|
476
|
+
const rl = readline.createInterface({
|
|
477
|
+
input: process.stdin,
|
|
478
|
+
output: process.stdout,
|
|
479
|
+
completer: completeDirectory,
|
|
480
|
+
terminal: true
|
|
481
|
+
});
|
|
482
|
+
if (opts.defaultValue) {
|
|
483
|
+
rl.write(opts.defaultValue);
|
|
484
|
+
}
|
|
485
|
+
rl.on("line", (input) => {
|
|
486
|
+
const value = input.trim();
|
|
487
|
+
const expandedPath = value.startsWith("~") ? value.replace(/^~/, process.env.HOME || "") : value;
|
|
488
|
+
if (opts.validate) {
|
|
489
|
+
const error = opts.validate(expandedPath);
|
|
490
|
+
if (error) {
|
|
491
|
+
process.stdout.write(`${pc.yellow("\u2502")} ${pc.yellow(error)}
|
|
492
|
+
`);
|
|
493
|
+
process.stdout.write(`${pc.cyan("\u2502")} `);
|
|
494
|
+
rl.write(value);
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
rl.close();
|
|
499
|
+
process.stdout.write(`${pc.green("\u2713")} ${pc.dim(expandedPath)}
|
|
500
|
+
`);
|
|
501
|
+
resolve(expandedPath);
|
|
502
|
+
});
|
|
503
|
+
rl.on("close", () => {
|
|
504
|
+
});
|
|
505
|
+
rl.on("SIGINT", () => {
|
|
506
|
+
rl.close();
|
|
507
|
+
process.stdout.write("\n");
|
|
508
|
+
resolve(/* @__PURE__ */ Symbol("cancel"));
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
function completeDirectory(line) {
|
|
513
|
+
const expanded = line.startsWith("~") ? line.replace(/^~/, process.env.HOME || "") : line;
|
|
514
|
+
try {
|
|
515
|
+
let dirToScan;
|
|
516
|
+
let prefix;
|
|
517
|
+
let basePath;
|
|
518
|
+
if (expanded === "" || expanded === "/") {
|
|
519
|
+
dirToScan = expanded || "/";
|
|
520
|
+
prefix = "";
|
|
521
|
+
basePath = expanded;
|
|
522
|
+
} else if (expanded.endsWith("/")) {
|
|
523
|
+
dirToScan = expanded;
|
|
524
|
+
prefix = "";
|
|
525
|
+
basePath = expanded;
|
|
526
|
+
} else {
|
|
527
|
+
dirToScan = path6.dirname(expanded);
|
|
528
|
+
prefix = path6.basename(expanded).toLowerCase();
|
|
529
|
+
basePath = dirToScan === "/" ? "/" : dirToScan + "/";
|
|
530
|
+
}
|
|
531
|
+
if (!fs6.existsSync(dirToScan)) {
|
|
532
|
+
return [[], line];
|
|
533
|
+
}
|
|
534
|
+
const entries = fs6.readdirSync(dirToScan, { withFileTypes: true }).filter((entry) => {
|
|
535
|
+
if (!entry.isDirectory()) return false;
|
|
536
|
+
if (entry.name.startsWith(".") && !prefix.startsWith(".")) return false;
|
|
537
|
+
return prefix === "" || entry.name.toLowerCase().startsWith(prefix);
|
|
538
|
+
}).map((entry) => {
|
|
539
|
+
const fullPath = path6.join(dirToScan, entry.name);
|
|
540
|
+
const displayPath = fullPath.startsWith(process.env.HOME || "") ? fullPath.replace(process.env.HOME || "", "~") : fullPath;
|
|
541
|
+
return displayPath + "/";
|
|
542
|
+
}).sort();
|
|
543
|
+
if (entries.length === 1) {
|
|
544
|
+
return [entries, line];
|
|
545
|
+
}
|
|
546
|
+
if (entries.length > 1) {
|
|
547
|
+
const commonPrefix = getCommonPrefix(entries);
|
|
548
|
+
if (commonPrefix.length > line.length) {
|
|
549
|
+
return [[commonPrefix], line];
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return [entries, line];
|
|
553
|
+
} catch {
|
|
554
|
+
return [[], line];
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
function getCommonPrefix(strings) {
|
|
558
|
+
if (strings.length === 0) return "";
|
|
559
|
+
if (strings.length === 1) return strings[0] || "";
|
|
560
|
+
let prefix = strings[0] || "";
|
|
561
|
+
for (let i = 1; i < strings.length; i++) {
|
|
562
|
+
const str = strings[i] || "";
|
|
563
|
+
while (prefix.length > 0 && !str.startsWith(prefix)) {
|
|
564
|
+
prefix = prefix.slice(0, -1);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return prefix;
|
|
568
|
+
}
|
|
569
|
+
function isCancelled(value) {
|
|
570
|
+
return typeof value === "symbol";
|
|
571
|
+
}
|
|
572
|
+
|
|
436
573
|
// src/commands/wizard/setup-flow.ts
|
|
437
574
|
async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
438
575
|
const s = spinner();
|
|
@@ -464,8 +601,8 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
464
601
|
options: existingProjects.map((project) => ({
|
|
465
602
|
value: `${project.name}:${project.source}`,
|
|
466
603
|
// Unique key
|
|
467
|
-
label: `${project.name} ${
|
|
468
|
-
hint:
|
|
604
|
+
label: `${project.name} ${pc2.dim(`(${project.source})`)}`,
|
|
605
|
+
hint: pc2.dim(
|
|
469
606
|
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
470
607
|
)
|
|
471
608
|
})),
|
|
@@ -515,7 +652,7 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
515
652
|
`Storage: ${config.storageMode === "both" ? "global + workspace" : config.storageMode}`
|
|
516
653
|
];
|
|
517
654
|
if (customGlobalPath && customGlobalPath !== getDefaultRRCEHome()) {
|
|
518
|
-
summary.push(`Global path: ${
|
|
655
|
+
summary.push(`Global path: ${pc2.cyan(customGlobalPath)}`);
|
|
519
656
|
}
|
|
520
657
|
if (dataPaths.length > 0) {
|
|
521
658
|
summary.push(`Data paths:`);
|
|
@@ -528,13 +665,13 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
528
665
|
const linkedProjects = config.linkedProjects;
|
|
529
666
|
if (linkedProjects.length > 0) {
|
|
530
667
|
summary.push(`Linked projects: ${linkedProjects.join(", ")}`);
|
|
531
|
-
summary.push(`Workspace file: ${
|
|
668
|
+
summary.push(`Workspace file: ${pc2.cyan(`${workspaceName}.code-workspace`)}`);
|
|
532
669
|
}
|
|
533
670
|
note(summary.join("\n"), "Setup Summary");
|
|
534
671
|
if (linkedProjects.length > 0) {
|
|
535
|
-
outro(
|
|
672
|
+
outro(pc2.green(`\u2713 Setup complete! Open ${pc2.bold(`${workspaceName}.code-workspace`)} in VSCode to access linked knowledge.`));
|
|
536
673
|
} else {
|
|
537
|
-
outro(
|
|
674
|
+
outro(pc2.green(`\u2713 Setup complete! Your agents are ready to use.`));
|
|
538
675
|
}
|
|
539
676
|
} catch (error) {
|
|
540
677
|
s.stop("Error occurred");
|
|
@@ -549,7 +686,7 @@ async function resolveGlobalPath() {
|
|
|
549
686
|
options.push({
|
|
550
687
|
value: "default",
|
|
551
688
|
label: `Default (${defaultPath})`,
|
|
552
|
-
hint: isDefaultWritable ?
|
|
689
|
+
hint: isDefaultWritable ? pc2.green("\u2713 writable") : pc2.red("\u2717 not writable")
|
|
553
690
|
});
|
|
554
691
|
options.push({
|
|
555
692
|
value: "custom",
|
|
@@ -567,8 +704,8 @@ async function resolveGlobalPath() {
|
|
|
567
704
|
if (choice === "default") {
|
|
568
705
|
if (!isDefaultWritable) {
|
|
569
706
|
note(
|
|
570
|
-
`${
|
|
571
|
-
${
|
|
707
|
+
`${pc2.yellow("\u26A0")} Cannot write to default path:
|
|
708
|
+
${pc2.dim(defaultPath)}
|
|
572
709
|
|
|
573
710
|
This can happen when running via npx/bunx in restricted environments.
|
|
574
711
|
Please choose a custom path instead.`,
|
|
@@ -578,28 +715,26 @@ Please choose a custom path instead.`,
|
|
|
578
715
|
}
|
|
579
716
|
return defaultPath;
|
|
580
717
|
}
|
|
581
|
-
const suggestedPath =
|
|
582
|
-
const customPath = await
|
|
583
|
-
message: "Enter custom global path:",
|
|
718
|
+
const suggestedPath = path7.join(process.env.HOME || "~", ".local", "share", "rrce-workflow");
|
|
719
|
+
const customPath = await directoryPrompt({
|
|
720
|
+
message: "Enter custom global path (Tab to autocomplete):",
|
|
584
721
|
defaultValue: suggestedPath,
|
|
585
|
-
placeholder: suggestedPath,
|
|
586
722
|
validate: (value) => {
|
|
587
723
|
if (!value.trim()) {
|
|
588
724
|
return "Path cannot be empty";
|
|
589
725
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
return `Cannot write to ${expandedPath2}. Please choose a writable path.`;
|
|
726
|
+
if (!checkWriteAccess(value)) {
|
|
727
|
+
return `Cannot write to ${value}. Please choose a writable path.`;
|
|
593
728
|
}
|
|
594
729
|
return void 0;
|
|
595
730
|
}
|
|
596
731
|
});
|
|
597
|
-
if (
|
|
732
|
+
if (isCancelled(customPath)) {
|
|
598
733
|
return void 0;
|
|
599
734
|
}
|
|
600
|
-
let expandedPath = customPath
|
|
735
|
+
let expandedPath = customPath;
|
|
601
736
|
if (!expandedPath.endsWith(".rrce-workflow")) {
|
|
602
|
-
expandedPath =
|
|
737
|
+
expandedPath = path7.join(expandedPath, ".rrce-workflow");
|
|
603
738
|
}
|
|
604
739
|
return expandedPath;
|
|
605
740
|
}
|
|
@@ -607,14 +742,14 @@ async function generateConfiguration(config, workspacePath, workspaceName, allPr
|
|
|
607
742
|
const dataPaths = getDataPaths(config.storageMode, workspaceName, workspacePath, config.globalPath);
|
|
608
743
|
for (const dataPath of dataPaths) {
|
|
609
744
|
ensureDir(dataPath);
|
|
610
|
-
ensureDir(
|
|
611
|
-
ensureDir(
|
|
612
|
-
ensureDir(
|
|
613
|
-
ensureDir(
|
|
745
|
+
ensureDir(path7.join(dataPath, "knowledge"));
|
|
746
|
+
ensureDir(path7.join(dataPath, "refs"));
|
|
747
|
+
ensureDir(path7.join(dataPath, "tasks"));
|
|
748
|
+
ensureDir(path7.join(dataPath, "templates"));
|
|
614
749
|
}
|
|
615
750
|
const agentCoreDir = getAgentCoreDir();
|
|
616
751
|
syncMetadataToAll(agentCoreDir, dataPaths);
|
|
617
|
-
copyDirToAllStoragePaths(
|
|
752
|
+
copyDirToAllStoragePaths(path7.join(agentCoreDir, "templates"), "templates", dataPaths);
|
|
618
753
|
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
619
754
|
if (config.tools.includes("copilot")) {
|
|
620
755
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
@@ -626,8 +761,8 @@ async function generateConfiguration(config, workspacePath, workspaceName, allPr
|
|
|
626
761
|
ensureDir(antigravityPath);
|
|
627
762
|
copyPromptsToDir(prompts, antigravityPath, ".md");
|
|
628
763
|
}
|
|
629
|
-
const workspaceConfigPath =
|
|
630
|
-
ensureDir(
|
|
764
|
+
const workspaceConfigPath = path7.join(workspacePath, ".rrce-workflow", "config.yaml");
|
|
765
|
+
ensureDir(path7.dirname(workspaceConfigPath));
|
|
631
766
|
let configContent = `# RRCE-Workflow Configuration
|
|
632
767
|
version: 1
|
|
633
768
|
|
|
@@ -655,7 +790,7 @@ linked_projects:
|
|
|
655
790
|
`;
|
|
656
791
|
});
|
|
657
792
|
}
|
|
658
|
-
|
|
793
|
+
fs7.writeFileSync(workspaceConfigPath, configContent);
|
|
659
794
|
if (config.tools.includes("copilot") || config.linkedProjects.length > 0) {
|
|
660
795
|
const selectedProjects = allProjects.filter(
|
|
661
796
|
(p) => config.linkedProjects.includes(`${p.name}:${p.source}`)
|
|
@@ -664,8 +799,8 @@ linked_projects:
|
|
|
664
799
|
}
|
|
665
800
|
}
|
|
666
801
|
function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
667
|
-
const globalPath =
|
|
668
|
-
const workspacePath =
|
|
802
|
+
const globalPath = path7.join(customGlobalPath || getDefaultRRCEHome(), "workspaces", workspaceName);
|
|
803
|
+
const workspacePath = path7.join(workspaceRoot, ".rrce-workflow");
|
|
669
804
|
switch (mode) {
|
|
670
805
|
case "global":
|
|
671
806
|
return [globalPath];
|
|
@@ -680,16 +815,15 @@ function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
|
680
815
|
|
|
681
816
|
// src/commands/wizard/link-flow.ts
|
|
682
817
|
import { multiselect as multiselect2, spinner as spinner2, note as note2, outro as outro2, cancel as cancel2, isCancel as isCancel2 } from "@clack/prompts";
|
|
683
|
-
import
|
|
684
|
-
import * as
|
|
818
|
+
import pc3 from "picocolors";
|
|
819
|
+
import * as fs8 from "fs";
|
|
685
820
|
async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
686
821
|
const projects = scanForProjects({
|
|
687
822
|
excludeWorkspace: workspaceName,
|
|
688
|
-
workspacePath
|
|
689
|
-
scanSiblings: true
|
|
823
|
+
workspacePath
|
|
690
824
|
});
|
|
691
825
|
if (projects.length === 0) {
|
|
692
|
-
outro2(
|
|
826
|
+
outro2(pc3.yellow("No other projects found. Try setting up another project first."));
|
|
693
827
|
return;
|
|
694
828
|
}
|
|
695
829
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
@@ -698,8 +832,8 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
|
698
832
|
options: projects.map((project) => ({
|
|
699
833
|
value: `${project.name}:${project.source}`,
|
|
700
834
|
// Unique key
|
|
701
|
-
label: `${project.name} ${
|
|
702
|
-
hint:
|
|
835
|
+
label: `${project.name} ${pc3.dim(`(${project.source})`)}`,
|
|
836
|
+
hint: pc3.dim(
|
|
703
837
|
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
704
838
|
)
|
|
705
839
|
})),
|
|
@@ -720,7 +854,7 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
|
720
854
|
const s = spinner2();
|
|
721
855
|
s.start("Linking projects");
|
|
722
856
|
const configFilePath = getConfigPath(workspacePath);
|
|
723
|
-
let configContent =
|
|
857
|
+
let configContent = fs8.readFileSync(configFilePath, "utf-8");
|
|
724
858
|
if (configContent.includes("linked_projects:")) {
|
|
725
859
|
const lines = configContent.split("\n");
|
|
726
860
|
const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
|
|
@@ -747,42 +881,42 @@ linked_projects:
|
|
|
747
881
|
`;
|
|
748
882
|
});
|
|
749
883
|
}
|
|
750
|
-
|
|
884
|
+
fs8.writeFileSync(configFilePath, configContent);
|
|
751
885
|
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
|
|
752
886
|
s.stop("Projects linked");
|
|
753
887
|
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
754
888
|
const summary = [
|
|
755
889
|
`Linked projects:`,
|
|
756
|
-
...selectedProjects.map((p) => ` \u2713 ${p.name} ${
|
|
890
|
+
...selectedProjects.map((p) => ` \u2713 ${p.name} ${pc3.dim(`(${p.source})`)}`),
|
|
757
891
|
``,
|
|
758
|
-
`Workspace file: ${
|
|
892
|
+
`Workspace file: ${pc3.cyan(workspaceFile)}`
|
|
759
893
|
];
|
|
760
894
|
note2(summary.join("\n"), "Link Summary");
|
|
761
|
-
outro2(
|
|
895
|
+
outro2(pc3.green(`\u2713 Projects linked! Open ${pc3.bold(workspaceFile)} in VSCode to access linked data.`));
|
|
762
896
|
}
|
|
763
897
|
|
|
764
898
|
// src/commands/wizard/sync-flow.ts
|
|
765
899
|
import { confirm as confirm2, spinner as spinner3, note as note3, outro as outro3, cancel as cancel3, isCancel as isCancel3 } from "@clack/prompts";
|
|
766
|
-
import
|
|
767
|
-
import * as
|
|
768
|
-
import * as
|
|
900
|
+
import pc4 from "picocolors";
|
|
901
|
+
import * as fs9 from "fs";
|
|
902
|
+
import * as path8 from "path";
|
|
769
903
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
770
904
|
const localPath = getLocalWorkspacePath(workspacePath);
|
|
771
905
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
772
|
-
const globalPath =
|
|
906
|
+
const globalPath = path8.join(customGlobalPath, "workspaces", workspaceName);
|
|
773
907
|
const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
|
|
774
908
|
const existingDirs = subdirs.filter(
|
|
775
|
-
(dir) =>
|
|
909
|
+
(dir) => fs9.existsSync(path8.join(localPath, dir))
|
|
776
910
|
);
|
|
777
911
|
if (existingDirs.length === 0) {
|
|
778
|
-
outro3(
|
|
912
|
+
outro3(pc4.yellow("No data found in workspace storage to sync."));
|
|
779
913
|
return;
|
|
780
914
|
}
|
|
781
915
|
note3(
|
|
782
916
|
`The following will be copied to global storage:
|
|
783
917
|
${existingDirs.map((d) => ` \u2022 ${d}/`).join("\n")}
|
|
784
918
|
|
|
785
|
-
Destination: ${
|
|
919
|
+
Destination: ${pc4.cyan(globalPath)}`,
|
|
786
920
|
"Sync Preview"
|
|
787
921
|
);
|
|
788
922
|
const shouldSync = await confirm2({
|
|
@@ -798,27 +932,27 @@ Destination: ${pc3.cyan(globalPath)}`,
|
|
|
798
932
|
try {
|
|
799
933
|
ensureDir(globalPath);
|
|
800
934
|
for (const dir of existingDirs) {
|
|
801
|
-
const srcDir =
|
|
802
|
-
const destDir =
|
|
935
|
+
const srcDir = path8.join(localPath, dir);
|
|
936
|
+
const destDir = path8.join(globalPath, dir);
|
|
803
937
|
ensureDir(destDir);
|
|
804
938
|
copyDirRecursive(srcDir, destDir);
|
|
805
939
|
}
|
|
806
940
|
const configFilePath = getConfigPath(workspacePath);
|
|
807
|
-
let configContent =
|
|
941
|
+
let configContent = fs9.readFileSync(configFilePath, "utf-8");
|
|
808
942
|
configContent = configContent.replace(/mode:\s*workspace/, "mode: both");
|
|
809
|
-
|
|
943
|
+
fs9.writeFileSync(configFilePath, configContent);
|
|
810
944
|
s.stop("Sync complete");
|
|
811
945
|
const summary = [
|
|
812
946
|
`Synced directories:`,
|
|
813
947
|
...existingDirs.map((d) => ` \u2713 ${d}/`),
|
|
814
948
|
``,
|
|
815
|
-
`Global path: ${
|
|
816
|
-
`Storage mode updated to: ${
|
|
949
|
+
`Global path: ${pc4.cyan(globalPath)}`,
|
|
950
|
+
`Storage mode updated to: ${pc4.bold("both")}`,
|
|
817
951
|
``,
|
|
818
952
|
`Other projects can now link this knowledge!`
|
|
819
953
|
];
|
|
820
954
|
note3(summary.join("\n"), "Sync Summary");
|
|
821
|
-
outro3(
|
|
955
|
+
outro3(pc4.green("\u2713 Workspace knowledge synced to global storage!"));
|
|
822
956
|
} catch (error) {
|
|
823
957
|
s.stop("Error occurred");
|
|
824
958
|
cancel3(`Failed to sync: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -828,9 +962,9 @@ Destination: ${pc3.cyan(globalPath)}`,
|
|
|
828
962
|
|
|
829
963
|
// src/commands/wizard/update-flow.ts
|
|
830
964
|
import { confirm as confirm3, spinner as spinner4, note as note4, outro as outro4, cancel as cancel4, isCancel as isCancel4 } from "@clack/prompts";
|
|
831
|
-
import
|
|
832
|
-
import * as
|
|
833
|
-
import * as
|
|
965
|
+
import pc5 from "picocolors";
|
|
966
|
+
import * as fs10 from "fs";
|
|
967
|
+
import * as path9 from "path";
|
|
834
968
|
async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
835
969
|
const s = spinner4();
|
|
836
970
|
s.start("Checking for updates");
|
|
@@ -860,10 +994,10 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
860
994
|
}
|
|
861
995
|
s.start("Updating from package");
|
|
862
996
|
for (const dataPath of dataPaths) {
|
|
863
|
-
copyDirToAllStoragePaths(
|
|
997
|
+
copyDirToAllStoragePaths(path9.join(agentCoreDir, "templates"), "templates", [dataPath]);
|
|
864
998
|
}
|
|
865
999
|
const configFilePath = getConfigPath(workspacePath);
|
|
866
|
-
const configContent =
|
|
1000
|
+
const configContent = fs10.readFileSync(configFilePath, "utf-8");
|
|
867
1001
|
if (configContent.includes("copilot: true")) {
|
|
868
1002
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
869
1003
|
ensureDir(copilotPath);
|
|
@@ -883,7 +1017,7 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
883
1017
|
`Your configuration and knowledge files were preserved.`
|
|
884
1018
|
];
|
|
885
1019
|
note4(summary.join("\n"), "Update Summary");
|
|
886
|
-
outro4(
|
|
1020
|
+
outro4(pc5.green("\u2713 Successfully updated from package!"));
|
|
887
1021
|
} catch (error) {
|
|
888
1022
|
s.stop("Error occurred");
|
|
889
1023
|
cancel4(`Failed to update: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -891,8 +1025,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
891
1025
|
}
|
|
892
1026
|
}
|
|
893
1027
|
function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
894
|
-
const globalPath =
|
|
895
|
-
const workspacePath =
|
|
1028
|
+
const globalPath = path9.join(customGlobalPath, "workspaces", workspaceName);
|
|
1029
|
+
const workspacePath = path9.join(workspaceRoot, ".rrce-workflow");
|
|
896
1030
|
switch (mode) {
|
|
897
1031
|
case "global":
|
|
898
1032
|
return [globalPath];
|
|
@@ -907,7 +1041,7 @@ function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot,
|
|
|
907
1041
|
|
|
908
1042
|
// src/commands/wizard/index.ts
|
|
909
1043
|
async function runWizard() {
|
|
910
|
-
intro(
|
|
1044
|
+
intro(pc6.cyan(pc6.inverse(" RRCE-Workflow Setup ")));
|
|
911
1045
|
const s = spinner5();
|
|
912
1046
|
s.start("Detecting environment");
|
|
913
1047
|
const workspacePath = detectWorkspaceRoot();
|
|
@@ -916,28 +1050,27 @@ async function runWizard() {
|
|
|
916
1050
|
await new Promise((r) => setTimeout(r, 800));
|
|
917
1051
|
s.stop("Environment detected");
|
|
918
1052
|
note5(
|
|
919
|
-
`Git User: ${
|
|
920
|
-
Workspace: ${
|
|
1053
|
+
`Git User: ${pc6.bold(gitUser || "(not found)")}
|
|
1054
|
+
Workspace: ${pc6.bold(workspaceName)}`,
|
|
921
1055
|
"Context"
|
|
922
1056
|
);
|
|
923
1057
|
const detectedProjects = scanForProjects({
|
|
924
1058
|
excludeWorkspace: workspaceName,
|
|
925
|
-
workspacePath
|
|
926
|
-
scanSiblings: true
|
|
1059
|
+
workspacePath
|
|
927
1060
|
});
|
|
928
1061
|
const configFilePath = getConfigPath(workspacePath);
|
|
929
|
-
const isAlreadyConfigured =
|
|
1062
|
+
const isAlreadyConfigured = fs11.existsSync(configFilePath);
|
|
930
1063
|
let currentStorageMode = null;
|
|
931
1064
|
if (isAlreadyConfigured) {
|
|
932
1065
|
try {
|
|
933
|
-
const configContent =
|
|
1066
|
+
const configContent = fs11.readFileSync(configFilePath, "utf-8");
|
|
934
1067
|
const modeMatch = configContent.match(/mode:\s*(global|workspace|both)/);
|
|
935
1068
|
currentStorageMode = modeMatch?.[1] ?? null;
|
|
936
1069
|
} catch {
|
|
937
1070
|
}
|
|
938
1071
|
}
|
|
939
1072
|
const localDataPath = getLocalWorkspacePath(workspacePath);
|
|
940
|
-
const hasLocalData =
|
|
1073
|
+
const hasLocalData = fs11.existsSync(localDataPath);
|
|
941
1074
|
if (isAlreadyConfigured) {
|
|
942
1075
|
const menuOptions = [];
|
|
943
1076
|
if (detectedProjects.length > 0) {
|
|
@@ -982,11 +1115,11 @@ Workspace: ${pc5.bold(workspaceName)}`,
|
|
|
982
1115
|
|
|
983
1116
|
// src/commands/selector.ts
|
|
984
1117
|
import { intro as intro2, select as select3, note as note6, cancel as cancel6, isCancel as isCancel6, outro as outro6 } from "@clack/prompts";
|
|
985
|
-
import
|
|
986
|
-
import * as
|
|
1118
|
+
import pc7 from "picocolors";
|
|
1119
|
+
import * as path10 from "path";
|
|
987
1120
|
async function runSelector() {
|
|
988
|
-
const workspaceName =
|
|
989
|
-
intro2(
|
|
1121
|
+
const workspaceName = path10.basename(process.cwd());
|
|
1122
|
+
intro2(pc7.cyan(pc7.inverse(` RRCE-Workflow | ${workspaceName} `)));
|
|
990
1123
|
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
991
1124
|
if (prompts.length === 0) {
|
|
992
1125
|
cancel6("No agents found. Run `rrce-workflow` to set up.");
|
|
@@ -1007,7 +1140,7 @@ async function runSelector() {
|
|
|
1007
1140
|
const prompt = selection;
|
|
1008
1141
|
note6(
|
|
1009
1142
|
`Use this agent in your IDE by invoking:
|
|
1010
|
-
${
|
|
1143
|
+
${pc7.bold(pc7.cyan(`@${prompt.frontmatter.name}`))}`,
|
|
1011
1144
|
"Agent Selected"
|
|
1012
1145
|
);
|
|
1013
1146
|
outro6("Done");
|