rhachet 1.11.0 → 1.12.1
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/contract/cli/invoke.js +9 -0
- package/dist/contract/cli/invoke.js.map +1 -1
- package/dist/contract/cli/invokeBriefsLink.integration.test.js +7 -4
- package/dist/contract/cli/invokeBriefsLink.integration.test.js.map +1 -1
- package/dist/contract/cli/invokeBriefsLink.js +8 -46
- package/dist/contract/cli/invokeBriefsLink.js.map +1 -1
- package/dist/contract/cli/invokeInit.d.ts +9 -0
- package/dist/contract/cli/invokeInit.integration.test.d.ts +1 -0
- package/dist/contract/cli/invokeInit.integration.test.js +123 -0
- package/dist/contract/cli/invokeInit.integration.test.js.map +1 -0
- package/dist/contract/cli/invokeInit.js +57 -0
- package/dist/contract/cli/invokeInit.js.map +1 -0
- package/dist/contract/cli/invokeRolesBoot.integration.test.d.ts +1 -0
- package/dist/contract/cli/invokeRolesBoot.integration.test.js +152 -0
- package/dist/contract/cli/invokeRolesBoot.integration.test.js.map +1 -0
- package/dist/contract/cli/invokeRolesLink.integration.test.d.ts +1 -0
- package/dist/contract/cli/invokeRolesLink.integration.test.js +117 -0
- package/dist/contract/cli/invokeRolesLink.integration.test.js.map +1 -0
- package/dist/contract/cli/invokeRolesLink.js +16 -95
- package/dist/contract/cli/invokeRolesLink.js.map +1 -1
- package/dist/logic/init/discoverRolePackages.d.ts +8 -0
- package/dist/logic/init/discoverRolePackages.js +20 -0
- package/dist/logic/init/discoverRolePackages.js.map +1 -0
- package/dist/logic/init/generateRhachetConfig.d.ts +8 -0
- package/dist/logic/init/generateRhachetConfig.js +40 -0
- package/dist/logic/init/generateRhachetConfig.js.map +1 -0
- package/dist/logic/init/generateRhachetConfig.test.d.ts +1 -0
- package/dist/logic/init/generateRhachetConfig.test.js +35 -0
- package/dist/logic/init/generateRhachetConfig.test.js.map +1 -0
- package/dist/logic/invoke/getAgentReadmeTemplates.js +1 -1
- package/dist/logic/invoke/getInvokeHooksByOpts.d.ts +2 -1
- package/dist/logic/invoke/getInvokeHooksByOpts.js +11 -3
- package/dist/logic/invoke/getInvokeHooksByOpts.js.map +1 -1
- package/dist/logic/invoke/link/findsertFile.d.ts +9 -0
- package/dist/logic/invoke/link/findsertFile.js +29 -0
- package/dist/logic/invoke/link/findsertFile.js.map +1 -0
- package/dist/logic/invoke/link/symlinkResourceDirectories.d.ts +12 -0
- package/dist/logic/invoke/link/symlinkResourceDirectories.js +81 -0
- package/dist/logic/invoke/link/symlinkResourceDirectories.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const test_fns_1 = require("test-fns");
|
|
7
|
+
const Role_1 = require("../../domain/objects/Role");
|
|
8
|
+
const RoleRegistry_1 = require("../../domain/objects/RoleRegistry");
|
|
9
|
+
const invokeRolesLink_1 = require("./invokeRolesLink");
|
|
10
|
+
describe('invokeRolesLink (integration)', () => {
|
|
11
|
+
(0, test_fns_1.given)('a CLI program with invokeRolesLink registered', () => {
|
|
12
|
+
const testDir = (0, node_path_1.resolve)(__dirname, './.temp/invokeRolesLink');
|
|
13
|
+
const originalCwd = process.cwd();
|
|
14
|
+
beforeAll(() => {
|
|
15
|
+
// Create test directory structure
|
|
16
|
+
(0, node_fs_1.mkdirSync)(testDir, { recursive: true });
|
|
17
|
+
process.chdir(testDir);
|
|
18
|
+
// Create mock briefs directory
|
|
19
|
+
const briefsDir = (0, node_path_1.resolve)(testDir, 'test-briefs');
|
|
20
|
+
(0, node_fs_1.mkdirSync)(briefsDir, { recursive: true });
|
|
21
|
+
// Create mock brief files
|
|
22
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.resolve)(briefsDir, 'brief1.md'), '# Brief 1\nThis is test brief 1');
|
|
23
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.resolve)(briefsDir, 'brief2.md'), '# Brief 2\nThis is test brief 2');
|
|
24
|
+
// Create mock skills directory
|
|
25
|
+
const skillsDir = (0, node_path_1.resolve)(testDir, 'test-skills');
|
|
26
|
+
(0, node_fs_1.mkdirSync)(skillsDir, { recursive: true });
|
|
27
|
+
// Create mock skill files
|
|
28
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.resolve)(skillsDir, 'skill1.sh'), '#!/bin/bash\n# Skill 1\necho "test skill 1"');
|
|
29
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.resolve)(skillsDir, 'skill2.sh'), '#!/bin/bash\n# Skill 2\necho "test skill 2"');
|
|
30
|
+
});
|
|
31
|
+
afterAll(() => {
|
|
32
|
+
process.chdir(originalCwd);
|
|
33
|
+
});
|
|
34
|
+
// Create mock registries with a role that has briefs and skills configured
|
|
35
|
+
const mockRole = new Role_1.Role({
|
|
36
|
+
slug: 'mechanic',
|
|
37
|
+
name: 'Mechanic',
|
|
38
|
+
purpose: 'Test mechanic role',
|
|
39
|
+
readme: '# Mechanic Role\n\nThis is the mechanic role readme.',
|
|
40
|
+
traits: [],
|
|
41
|
+
skills: {
|
|
42
|
+
dirs: [{ uri: 'test-skills' }],
|
|
43
|
+
refs: [],
|
|
44
|
+
},
|
|
45
|
+
briefs: { dirs: [{ uri: 'test-briefs' }] },
|
|
46
|
+
});
|
|
47
|
+
const mockRegistry = new RoleRegistry_1.RoleRegistry({
|
|
48
|
+
slug: 'test-registry',
|
|
49
|
+
readme: 'Test readme',
|
|
50
|
+
roles: [mockRole],
|
|
51
|
+
});
|
|
52
|
+
const rolesCommand = new commander_1.Command('roles');
|
|
53
|
+
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
logSpy.mockClear();
|
|
56
|
+
// Clean up any existing .agent directory
|
|
57
|
+
const agentDir = (0, node_path_1.resolve)(testDir, '.agent');
|
|
58
|
+
if ((0, node_fs_1.existsSync)(agentDir)) {
|
|
59
|
+
(0, node_fs_1.rmSync)(agentDir, { recursive: true, force: true });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
(0, invokeRolesLink_1.invokeRolesLink)({ command: rolesCommand, registries: [mockRegistry] });
|
|
63
|
+
(0, test_fns_1.when)('invoked with "link --repo test --role mechanic"', () => {
|
|
64
|
+
(0, test_fns_1.then)('it should create .agent directory structure and link briefs and skills', async () => {
|
|
65
|
+
await rolesCommand.parseAsync(['link', '--repo', 'test', '--role', 'mechanic'], {
|
|
66
|
+
from: 'user',
|
|
67
|
+
});
|
|
68
|
+
// Check that .agent directory structure was created
|
|
69
|
+
expect((0, node_fs_1.existsSync)((0, node_path_1.resolve)(testDir, '.agent/readme.md'))).toBe(true);
|
|
70
|
+
expect((0, node_fs_1.existsSync)((0, node_path_1.resolve)(testDir, '.agent/repo=.this/readme.md'))).toBe(true);
|
|
71
|
+
expect((0, node_fs_1.existsSync)((0, node_path_1.resolve)(testDir, '.agent/repo=test/role=mechanic/readme.md'))).toBe(true);
|
|
72
|
+
// Check that role readme was created
|
|
73
|
+
const roleReadmeContent = require('fs').readFileSync((0, node_path_1.resolve)(testDir, '.agent/repo=test/role=mechanic/readme.md'), 'utf-8');
|
|
74
|
+
expect(roleReadmeContent).toContain('Mechanic Role');
|
|
75
|
+
// Check that briefs directory symlink was created
|
|
76
|
+
expect((0, node_fs_1.existsSync)((0, node_path_1.resolve)(testDir, '.agent/repo=test/role=mechanic/briefs/test-briefs'))).toBe(true);
|
|
77
|
+
// Check that files are accessible through the symlinked briefs directory
|
|
78
|
+
expect((0, node_fs_1.existsSync)((0, node_path_1.resolve)(testDir, '.agent/repo=test/role=mechanic/briefs/test-briefs/brief1.md'))).toBe(true);
|
|
79
|
+
expect((0, node_fs_1.existsSync)((0, node_path_1.resolve)(testDir, '.agent/repo=test/role=mechanic/briefs/test-briefs/brief2.md'))).toBe(true);
|
|
80
|
+
// Check that skills directory symlink was created
|
|
81
|
+
expect((0, node_fs_1.existsSync)((0, node_path_1.resolve)(testDir, '.agent/repo=test/role=mechanic/skills/test-skills'))).toBe(true);
|
|
82
|
+
// Check that files are accessible through the symlinked skills directory
|
|
83
|
+
expect((0, node_fs_1.existsSync)((0, node_path_1.resolve)(testDir, '.agent/repo=test/role=mechanic/skills/test-skills/skill1.sh'))).toBe(true);
|
|
84
|
+
expect((0, node_fs_1.existsSync)((0, node_path_1.resolve)(testDir, '.agent/repo=test/role=mechanic/skills/test-skills/skill2.sh'))).toBe(true);
|
|
85
|
+
// Check log output
|
|
86
|
+
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Linked role "mechanic"'));
|
|
87
|
+
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('2 brief(s) linked'));
|
|
88
|
+
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('2 skill(s) linked'));
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
(0, test_fns_1.when)('invoked with "link" without --repo', () => {
|
|
92
|
+
(0, test_fns_1.then)('it should throw an error requiring --repo', async () => {
|
|
93
|
+
const error = await (0, test_fns_1.getError)(() => rolesCommand.parseAsync(['link', '--role', 'mechanic'], {
|
|
94
|
+
from: 'user',
|
|
95
|
+
}));
|
|
96
|
+
expect(error?.message).toContain('--repo is required');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
(0, test_fns_1.when)('invoked with "link" without --role', () => {
|
|
100
|
+
(0, test_fns_1.then)('it should throw an error requiring --role', async () => {
|
|
101
|
+
const error = await (0, test_fns_1.getError)(() => rolesCommand.parseAsync(['link', '--repo', 'test'], {
|
|
102
|
+
from: 'user',
|
|
103
|
+
}));
|
|
104
|
+
expect(error?.message).toContain('--role is required');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
(0, test_fns_1.when)('invoked with "link --repo test --role nonexistent"', () => {
|
|
108
|
+
(0, test_fns_1.then)('it should throw an error about role not found', async () => {
|
|
109
|
+
const error = await (0, test_fns_1.getError)(() => rolesCommand.parseAsync(['link', '--repo', 'test', '--role', 'nonexistent'], {
|
|
110
|
+
from: 'user',
|
|
111
|
+
}));
|
|
112
|
+
expect(error?.message).toContain('no role named "nonexistent"');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=invokeRolesLink.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invokeRolesLink.integration.test.js","sourceRoot":"","sources":["../../../src/contract/cli/invokeRolesLink.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,74 +6,8 @@ const node_fs_1 = require("node:fs");
|
|
|
6
6
|
const node_path_1 = require("node:path");
|
|
7
7
|
const assureFindRole_1 = require("../../logic/invoke/assureFindRole");
|
|
8
8
|
const getAgentReadmeTemplates_1 = require("../../logic/invoke/getAgentReadmeTemplates");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* .why = ensures standard readme files exist without overwriting custom changes
|
|
12
|
-
* .how = only writes if file doesn't exist or content matches template exactly
|
|
13
|
-
*/
|
|
14
|
-
const findsertFile = (options) => {
|
|
15
|
-
const { path, template } = options;
|
|
16
|
-
if (!(0, node_fs_1.existsSync)(path)) {
|
|
17
|
-
console.log(` + ${(0, node_path_1.basename)(path)} (created)`);
|
|
18
|
-
(0, node_fs_1.writeFileSync)(path, template, 'utf8');
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
// File exists - check if it matches template
|
|
22
|
-
const existingContent = (0, node_fs_1.readFileSync)(path, 'utf8');
|
|
23
|
-
if (existingContent === template) {
|
|
24
|
-
console.log(` ✓ ${(0, node_path_1.basename)(path)} (unchanged)`);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
console.log(` ↻ ${(0, node_path_1.basename)(path)} (preserved with custom changes)`);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* .what = creates symlinks for all files in a source directory to a target directory
|
|
32
|
-
* .why = enables role resources to be linked from node_modules or other sources
|
|
33
|
-
*/
|
|
34
|
-
const symlinkDirectory = (options) => {
|
|
35
|
-
const { sourceDir, targetDir, label } = options;
|
|
36
|
-
if (!(0, node_fs_1.existsSync)(sourceDir)) {
|
|
37
|
-
return 0; // No source directory, skip silently
|
|
38
|
-
}
|
|
39
|
-
const files = (0, node_fs_1.readdirSync)(sourceDir);
|
|
40
|
-
if (files.length === 0) {
|
|
41
|
-
return 0;
|
|
42
|
-
}
|
|
43
|
-
(0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
|
|
44
|
-
for (const file of files) {
|
|
45
|
-
const sourcePath = (0, node_path_1.resolve)(sourceDir, file);
|
|
46
|
-
const targetPath = (0, node_path_1.resolve)(targetDir, (0, node_path_1.basename)(file));
|
|
47
|
-
// Remove existing symlink/file if it exists
|
|
48
|
-
if ((0, node_fs_1.existsSync)(targetPath)) {
|
|
49
|
-
try {
|
|
50
|
-
(0, node_fs_1.unlinkSync)(targetPath);
|
|
51
|
-
console.log(` ↻ ${label}/${file} (updating)`);
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
(0, node_fs_1.rmSync)(targetPath, { recursive: true, force: true });
|
|
55
|
-
console.log(` ↻ ${label}/${file} (updating)`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
console.log(` + ${label}/${file}`);
|
|
60
|
-
}
|
|
61
|
-
// Create relative symlink from target directory to source file
|
|
62
|
-
const relativeSource = (0, node_path_1.relative)(targetDir, sourcePath);
|
|
63
|
-
try {
|
|
64
|
-
(0, node_fs_1.symlinkSync)(relativeSource, targetPath);
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
if (error.code === 'EEXIST') {
|
|
68
|
-
console.log(` ⚠️ ${label}/${file} already exists (skipping)`);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
throw error;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return files.length;
|
|
76
|
-
};
|
|
9
|
+
const findsertFile_1 = require("../../logic/invoke/link/findsertFile");
|
|
10
|
+
const symlinkResourceDirectories_1 = require("../../logic/invoke/link/symlinkResourceDirectories");
|
|
77
11
|
/**
|
|
78
12
|
* .what = adds the "roles link" subcommand to the CLI
|
|
79
13
|
* .why = creates .agent/ directory structure and links role resources
|
|
@@ -103,47 +37,34 @@ const invokeRolesLink = ({ command, registries, }) => {
|
|
|
103
37
|
(0, node_fs_1.mkdirSync)(repoThisDir, { recursive: true });
|
|
104
38
|
(0, node_fs_1.mkdirSync)(repoRoleDir, { recursive: true });
|
|
105
39
|
// Findsert .agent/readme.md
|
|
106
|
-
findsertFile({
|
|
40
|
+
(0, findsertFile_1.findsertFile)({
|
|
107
41
|
path: (0, node_path_1.resolve)(agentDir, 'readme.md'),
|
|
108
42
|
template: (0, getAgentReadmeTemplates_1.getAgentRootReadmeTemplate)(),
|
|
109
43
|
});
|
|
110
44
|
// Findsert .agent/repo=.this/readme.md
|
|
111
|
-
findsertFile({
|
|
45
|
+
(0, findsertFile_1.findsertFile)({
|
|
112
46
|
path: (0, node_path_1.resolve)(repoThisDir, 'readme.md'),
|
|
113
47
|
template: (0, getAgentReadmeTemplates_1.getAgentRepoThisReadmeTemplate)(),
|
|
114
48
|
});
|
|
115
49
|
// Upsert .agent/repo=$repo/role=$role/readme.md
|
|
116
50
|
if (role.readme) {
|
|
117
51
|
const roleReadmePath = (0, node_path_1.resolve)(repoRoleDir, 'readme.md');
|
|
52
|
+
const relativeRoleReadmePath = (0, node_path_1.relative)(process.cwd(), roleReadmePath);
|
|
118
53
|
(0, node_fs_1.writeFileSync)(roleReadmePath, role.readme, 'utf8');
|
|
119
|
-
console.log(` +
|
|
54
|
+
console.log(` + ${relativeRoleReadmePath} (upserted)`);
|
|
120
55
|
}
|
|
121
56
|
// Link briefs if configured
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
briefsCount += symlinkDirectory({
|
|
128
|
-
sourceDir,
|
|
129
|
-
targetDir,
|
|
130
|
-
label: 'briefs',
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
}
|
|
57
|
+
const briefsCount = (0, symlinkResourceDirectories_1.symlinkResourceDirectories)({
|
|
58
|
+
sourceDirs: role.briefs.dirs,
|
|
59
|
+
targetDir: (0, node_path_1.resolve)(repoRoleDir, 'briefs'),
|
|
60
|
+
resourceName: 'briefs',
|
|
61
|
+
});
|
|
134
62
|
// Link skills if configured
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
skillsCount += symlinkDirectory({
|
|
141
|
-
sourceDir,
|
|
142
|
-
targetDir,
|
|
143
|
-
label: 'skills',
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
63
|
+
const skillsCount = (0, symlinkResourceDirectories_1.symlinkResourceDirectories)({
|
|
64
|
+
sourceDirs: role.skills.dirs,
|
|
65
|
+
targetDir: (0, node_path_1.resolve)(repoRoleDir, 'skills'),
|
|
66
|
+
resourceName: 'skills',
|
|
67
|
+
});
|
|
147
68
|
console.log(``);
|
|
148
69
|
console.log(`🔗 Linked role "${role.slug}" from repo "${repoSlug}"`);
|
|
149
70
|
if (briefsCount > 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invokeRolesLink.js","sourceRoot":"","sources":["../../../src/contract/cli/invokeRolesLink.ts"],"names":[],"mappings":";;;AACA,mDAAiD;AACjD,
|
|
1
|
+
{"version":3,"file":"invokeRolesLink.js","sourceRoot":"","sources":["../../../src/contract/cli/invokeRolesLink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .what = discovers rhachet role packages from package.json
|
|
3
|
+
* .why = enables auto-initialization of rhachet.use.ts config
|
|
4
|
+
* .how = scans dependencies + devDependencies for packages matching `rhachet-roles-*`
|
|
5
|
+
*/
|
|
6
|
+
export declare const discoverRolePackages: (input: {
|
|
7
|
+
from: string;
|
|
8
|
+
}) => Promise<string[]>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.discoverRolePackages = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const rhachet_artifact_git_1 = require("rhachet-artifact-git");
|
|
7
|
+
/**
|
|
8
|
+
* .what = discovers rhachet role packages from package.json
|
|
9
|
+
* .why = enables auto-initialization of rhachet.use.ts config
|
|
10
|
+
* .how = scans dependencies + devDependencies for packages matching `rhachet-roles-*`
|
|
11
|
+
*/
|
|
12
|
+
const discoverRolePackages = async (input) => {
|
|
13
|
+
const root = await (0, rhachet_artifact_git_1.getGitRepoRoot)({ from: input.from });
|
|
14
|
+
const pkgPath = (0, node_path_1.resolve)(root, 'package.json');
|
|
15
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)(pkgPath, 'utf8'));
|
|
16
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
17
|
+
return Object.keys(allDeps).filter((name) => name.startsWith('rhachet-roles-'));
|
|
18
|
+
};
|
|
19
|
+
exports.discoverRolePackages = discoverRolePackages;
|
|
20
|
+
//# sourceMappingURL=discoverRolePackages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discoverRolePackages.js","sourceRoot":"","sources":["../../../src/logic/init/discoverRolePackages.ts"],"names":[],"mappings":";;;AAAA,qCAAuC;AACvC,yCAAoC;AACpC,+DAAsD;AAEtD;;;;GAIG;AACI,MAAM,oBAAoB,GAAG,KAAK,EAAE,KAE1C,EAAqB,EAAE;IACtB,MAAM,IAAI,GAAG,MAAM,IAAA,qCAAc,EAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,IAAA,mBAAO,EAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,EAAE,GAAG,GAAG,CAAC,YAAY,EAAE,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;IAChE,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAC1C,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAClC,CAAC;AACJ,CAAC,CAAC;AAVW,QAAA,oBAAoB,wBAU/B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .what = generates rhachet.use.ts config file content
|
|
3
|
+
* .why = enables auto-initialization from discovered role packages
|
|
4
|
+
* .how = creates aliased imports and exports for registries and hooks
|
|
5
|
+
*/
|
|
6
|
+
export declare const generateRhachetConfig: (input: {
|
|
7
|
+
packages: string[];
|
|
8
|
+
}) => string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateRhachetConfig = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* .what = converts a package name suffix to PascalCase
|
|
6
|
+
* .why = generates valid TypeScript identifier suffixes for aliased imports
|
|
7
|
+
*/
|
|
8
|
+
const toPascalCase = (str) => str
|
|
9
|
+
.split('-')
|
|
10
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
11
|
+
.join('');
|
|
12
|
+
/**
|
|
13
|
+
* .what = generates rhachet.use.ts config file content
|
|
14
|
+
* .why = enables auto-initialization from discovered role packages
|
|
15
|
+
* .how = creates aliased imports and exports for registries and hooks
|
|
16
|
+
*/
|
|
17
|
+
const generateRhachetConfig = (input) => {
|
|
18
|
+
// Always use aliased imports for consistency
|
|
19
|
+
const imports = input.packages
|
|
20
|
+
.map((pkg) => {
|
|
21
|
+
const suffix = toPascalCase(pkg.replace('rhachet-roles-', ''));
|
|
22
|
+
return `import { getRoleRegistry as getRoleRegistry${suffix}, getInvokeHooks as getInvokeHooks${suffix} } from '${pkg}';`;
|
|
23
|
+
})
|
|
24
|
+
.join('\n');
|
|
25
|
+
const registries = input.packages
|
|
26
|
+
.map((pkg) => `getRoleRegistry${toPascalCase(pkg.replace('rhachet-roles-', ''))}()`)
|
|
27
|
+
.join(', ');
|
|
28
|
+
const hooks = input.packages
|
|
29
|
+
.map((pkg) => `getInvokeHooks${toPascalCase(pkg.replace('rhachet-roles-', ''))}()`)
|
|
30
|
+
.join(', ');
|
|
31
|
+
return `import { InvokeHooks, RoleRegistry } from 'rhachet';
|
|
32
|
+
|
|
33
|
+
${imports}
|
|
34
|
+
|
|
35
|
+
export const getRoleRegistries = (): RoleRegistry[] => [${registries}];
|
|
36
|
+
export const getInvokeHooks = (): InvokeHooks[] => [${hooks}];
|
|
37
|
+
`;
|
|
38
|
+
};
|
|
39
|
+
exports.generateRhachetConfig = generateRhachetConfig;
|
|
40
|
+
//# sourceMappingURL=generateRhachetConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateRhachetConfig.js","sourceRoot":"","sources":["../../../src/logic/init/generateRhachetConfig.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,MAAM,YAAY,GAAG,CAAC,GAAW,EAAU,EAAE,CAC3C,GAAG;KACA,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KAC3D,IAAI,CAAC,EAAE,CAAC,CAAC;AAEd;;;;GAIG;AACI,MAAM,qBAAqB,GAAG,CAAC,KAErC,EAAU,EAAE;IACX,6CAA6C;IAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ;SAC3B,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACX,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/D,OAAO,8CAA8C,MAAM,qCAAqC,MAAM,YAAY,GAAG,IAAI,CAAC;IAC5H,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ;SAC9B,GAAG,CACF,CAAC,GAAG,EAAE,EAAE,CACN,kBAAkB,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,IAAI,CACxE;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ;SACzB,GAAG,CACF,CAAC,GAAG,EAAE,EAAE,CACN,iBAAiB,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,IAAI,CACvE;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO;;EAEP,OAAO;;0DAEiD,UAAU;sDACd,KAAK;CAC1D,CAAC;AACF,CAAC,CAAC;AAhCW,QAAA,qBAAqB,yBAgChC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const generateRhachetConfig_1 = require("./generateRhachetConfig");
|
|
4
|
+
describe('generateRhachetConfig', () => {
|
|
5
|
+
it('should generate config for single package with aliased imports', () => {
|
|
6
|
+
const result = (0, generateRhachetConfig_1.generateRhachetConfig)({
|
|
7
|
+
packages: ['rhachet-roles-ehmpathy'],
|
|
8
|
+
});
|
|
9
|
+
// Verify aliased imports for single package
|
|
10
|
+
expect(result).toContain("import { getRoleRegistry as getRoleRegistryEhmpathy, getInvokeHooks as getInvokeHooksEhmpathy } from 'rhachet-roles-ehmpathy'");
|
|
11
|
+
// Snapshot for observability
|
|
12
|
+
expect(result).toMatchSnapshot();
|
|
13
|
+
});
|
|
14
|
+
it('should generate config for multiple packages', () => {
|
|
15
|
+
const result = (0, generateRhachetConfig_1.generateRhachetConfig)({
|
|
16
|
+
packages: ['rhachet-roles-ehmpathy', 'rhachet-roles-other'],
|
|
17
|
+
});
|
|
18
|
+
// Verify multiple packages are included
|
|
19
|
+
expect(result).toContain('getRoleRegistryEhmpathy(), getRoleRegistryOther()');
|
|
20
|
+
expect(result).toContain('getInvokeHooksEhmpathy(), getInvokeHooksOther()');
|
|
21
|
+
// Snapshot for observability
|
|
22
|
+
expect(result).toMatchSnapshot();
|
|
23
|
+
});
|
|
24
|
+
it('should convert kebab-case to PascalCase for aliases', () => {
|
|
25
|
+
const result = (0, generateRhachetConfig_1.generateRhachetConfig)({
|
|
26
|
+
packages: ['rhachet-roles-my-custom-roles'],
|
|
27
|
+
});
|
|
28
|
+
// Verify key elements
|
|
29
|
+
expect(result).toContain('getRoleRegistryMyCustomRoles');
|
|
30
|
+
expect(result).toContain('getInvokeHooksMyCustomRoles');
|
|
31
|
+
// Snapshot for observability
|
|
32
|
+
expect(result).toMatchSnapshot();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=generateRhachetConfig.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateRhachetConfig.test.js","sourceRoot":"","sources":["../../../src/logic/init/generateRhachetConfig.test.ts"],"names":[],"mappings":";;AAAA,mEAAgE;AAEhE,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,MAAM,GAAG,IAAA,6CAAqB,EAAC;YACnC,QAAQ,EAAE,CAAC,wBAAwB,CAAC;SACrC,CAAC,CAAC;QAEH,4CAA4C;QAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,+HAA+H,CAChI,CAAC;QAEF,6BAA6B;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,MAAM,GAAG,IAAA,6CAAqB,EAAC;YACnC,QAAQ,EAAE,CAAC,wBAAwB,EAAE,qBAAqB,CAAC;SAC5D,CAAC,CAAC;QAEH,wCAAwC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,mDAAmD,CACpD,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iDAAiD,CAAC,CAAC;QAE5E,6BAA6B;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,MAAM,GAAG,IAAA,6CAAqB,EAAC;YACnC,QAAQ,EAAE,CAAC,+BAA+B,CAAC;SAC5C,CAAC,CAAC;QAEH,sBAAsB;QACtB,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QAExD,6BAA6B;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -4,7 +4,8 @@ import { InvokeOpts } from '../../domain/objects/InvokeOpts';
|
|
|
4
4
|
* .what = get invoke hooks from the invocation options declared
|
|
5
5
|
* .how =
|
|
6
6
|
* - lookup the config based on the options
|
|
7
|
-
* - grab the hooks from the config
|
|
7
|
+
* - grab the hooks from the config (supports array of InvokeHooks)
|
|
8
|
+
* - merge hooks from all sources
|
|
8
9
|
*/
|
|
9
10
|
export declare const getInvokeHooksByOpts: (input: {
|
|
10
11
|
opts: InvokeOpts<{
|
|
@@ -28,13 +28,21 @@ exports.getInvokeHooksByOpts = void 0;
|
|
|
28
28
|
* .what = get invoke hooks from the invocation options declared
|
|
29
29
|
* .how =
|
|
30
30
|
* - lookup the config based on the options
|
|
31
|
-
* - grab the hooks from the config
|
|
31
|
+
* - grab the hooks from the config (supports array of InvokeHooks)
|
|
32
|
+
* - merge hooks from all sources
|
|
32
33
|
*/
|
|
33
34
|
const getInvokeHooksByOpts = async (input) => {
|
|
34
35
|
// import the config
|
|
35
36
|
const config = await Promise.resolve(`${input.opts.config}`).then(s => __importStar(require(s)));
|
|
36
|
-
// grab the
|
|
37
|
-
|
|
37
|
+
// grab the hooks (may be single or array)
|
|
38
|
+
const hooksResult = await config.getInvokeHooks?.();
|
|
39
|
+
if (!hooksResult)
|
|
40
|
+
return null;
|
|
41
|
+
// normalize to array and merge
|
|
42
|
+
const hooksList = Array.isArray(hooksResult) ? hooksResult : [hooksResult];
|
|
43
|
+
return {
|
|
44
|
+
onInvokeAskInput: hooksList.flatMap((h) => h?.onInvokeAskInput ?? []),
|
|
45
|
+
};
|
|
38
46
|
};
|
|
39
47
|
exports.getInvokeHooksByOpts = getInvokeHooksByOpts;
|
|
40
48
|
//# sourceMappingURL=getInvokeHooksByOpts.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getInvokeHooksByOpts.js","sourceRoot":"","sources":["../../../src/logic/invoke/getInvokeHooksByOpts.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAGA
|
|
1
|
+
{"version":3,"file":"getInvokeHooksByOpts.js","sourceRoot":"","sources":["../../../src/logic/invoke/getInvokeHooksByOpts.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAGA;;;;;;GAMG;AACI,MAAM,oBAAoB,GAAG,KAAK,EAAE,KAE1C,EAA+B,EAAE;IAChC,oBAAoB;IACpB,MAAM,MAAM,GAKR,yBAAa,KAAK,CAAC,IAAI,CAAC,MAAM,uCAAC,CAAC;IAEpC,0CAA0C;IAC1C,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC;IACpD,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAE9B,+BAA+B;IAC/B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC3E,OAAO;QACL,gBAAgB,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,gBAAgB,IAAI,EAAE,CAAC;KACtE,CAAC;AACJ,CAAC,CAAC;AApBW,QAAA,oBAAoB,wBAoB/B"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .what = finds or inserts a file with template content
|
|
3
|
+
* .why = ensures standard readme files exist without overwriting custom changes
|
|
4
|
+
* .how = only writes if file doesn't exist or content matches template exactly
|
|
5
|
+
*/
|
|
6
|
+
export declare const findsertFile: (options: {
|
|
7
|
+
path: string;
|
|
8
|
+
template: string;
|
|
9
|
+
}) => void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findsertFile = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
/**
|
|
7
|
+
* .what = finds or inserts a file with template content
|
|
8
|
+
* .why = ensures standard readme files exist without overwriting custom changes
|
|
9
|
+
* .how = only writes if file doesn't exist or content matches template exactly
|
|
10
|
+
*/
|
|
11
|
+
const findsertFile = (options) => {
|
|
12
|
+
const { path, template } = options;
|
|
13
|
+
const relativePath = (0, node_path_1.relative)(process.cwd(), path);
|
|
14
|
+
if (!(0, node_fs_1.existsSync)(path)) {
|
|
15
|
+
console.log(` + ${relativePath} (created)`);
|
|
16
|
+
(0, node_fs_1.writeFileSync)(path, template, 'utf8');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
// File exists - check if it matches template
|
|
20
|
+
const existingContent = (0, node_fs_1.readFileSync)(path, 'utf8');
|
|
21
|
+
if (existingContent === template) {
|
|
22
|
+
console.log(` ✓ ${relativePath} (unchanged)`);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log(` ↻ ${relativePath} (preserved with custom changes)`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
exports.findsertFile = findsertFile;
|
|
29
|
+
//# sourceMappingURL=findsertFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findsertFile.js","sourceRoot":"","sources":["../../../../src/logic/invoke/link/findsertFile.ts"],"names":[],"mappings":";;;AAAA,qCAAkE;AAClE,yCAAqC;AAErC;;;;GAIG;AACI,MAAM,YAAY,GAAG,CAAC,OAG5B,EAAQ,EAAE;IACT,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACnC,MAAM,YAAY,GAAG,IAAA,oBAAQ,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;IAEnD,IAAI,CAAC,IAAA,oBAAU,EAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,OAAO,YAAY,YAAY,CAAC,CAAC;QAC7C,IAAA,uBAAa,EAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QACtC,OAAO;IACT,CAAC;IAED,6CAA6C;IAC7C,MAAM,eAAe,GAAG,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnD,IAAI,eAAe,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,OAAO,YAAY,cAAc,CAAC,CAAC;IACjD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,OAAO,YAAY,kCAAkC,CAAC,CAAC;IACrE,CAAC;AACH,CAAC,CAAC;AApBW,QAAA,YAAY,gBAoBvB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .what = creates symlinks for resource directories to a target directory
|
|
3
|
+
* .why = enables role resources (briefs, skills, etc.) to be linked from node_modules or other sources
|
|
4
|
+
* .how = creates symlinks for entire directories, returns count of leaf files
|
|
5
|
+
*/
|
|
6
|
+
export declare const symlinkResourceDirectories: (options: {
|
|
7
|
+
sourceDirs: Array<{
|
|
8
|
+
uri: string;
|
|
9
|
+
}>;
|
|
10
|
+
targetDir: string;
|
|
11
|
+
resourceName: string;
|
|
12
|
+
}) => number;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.symlinkResourceDirectories = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
/**
|
|
7
|
+
* .what = recursively counts all leaf files in a directory
|
|
8
|
+
* .why = to provide accurate file counts when linking directories
|
|
9
|
+
*/
|
|
10
|
+
const countFilesInDirectory = (dirPath) => {
|
|
11
|
+
let count = 0;
|
|
12
|
+
const entries = (0, node_fs_1.readdirSync)(dirPath);
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
const fullPath = (0, node_path_1.resolve)(dirPath, entry);
|
|
15
|
+
const stats = (0, node_fs_1.statSync)(fullPath);
|
|
16
|
+
if (stats.isDirectory()) {
|
|
17
|
+
count += countFilesInDirectory(fullPath);
|
|
18
|
+
}
|
|
19
|
+
else if (stats.isFile()) {
|
|
20
|
+
count++;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return count;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* .what = creates symlinks for resource directories to a target directory
|
|
27
|
+
* .why = enables role resources (briefs, skills, etc.) to be linked from node_modules or other sources
|
|
28
|
+
* .how = creates symlinks for entire directories, returns count of leaf files
|
|
29
|
+
*/
|
|
30
|
+
const symlinkResourceDirectories = (options) => {
|
|
31
|
+
const { sourceDirs, targetDir, resourceName } = options;
|
|
32
|
+
if (sourceDirs.length === 0) {
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
let totalFileCount = 0;
|
|
36
|
+
for (const sourceDir of sourceDirs) {
|
|
37
|
+
const sourcePath = (0, node_path_1.resolve)(process.cwd(), sourceDir.uri);
|
|
38
|
+
if (!(0, node_fs_1.existsSync)(sourcePath)) {
|
|
39
|
+
continue; // Skip if source doesn't exist
|
|
40
|
+
}
|
|
41
|
+
// Create target directory parent if needed
|
|
42
|
+
(0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
|
|
43
|
+
// Create a unique target path for this source directory
|
|
44
|
+
// Use the basename of the source directory to avoid conflicts
|
|
45
|
+
const targetPath = (0, node_path_1.resolve)(targetDir, (0, node_path_1.basename)(sourcePath));
|
|
46
|
+
// Remove existing symlink/file if it exists
|
|
47
|
+
const relativeTargetPath = (0, node_path_1.relative)(process.cwd(), targetPath);
|
|
48
|
+
if ((0, node_fs_1.existsSync)(targetPath)) {
|
|
49
|
+
try {
|
|
50
|
+
(0, node_fs_1.unlinkSync)(targetPath);
|
|
51
|
+
console.log(` ↻ ${relativeTargetPath} (updated)`);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
(0, node_fs_1.rmSync)(targetPath, { recursive: true, force: true });
|
|
55
|
+
console.log(` ↻ ${relativeTargetPath} (updated)`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log(` + ${relativeTargetPath}`);
|
|
60
|
+
}
|
|
61
|
+
// Create relative symlink from target directory to source directory
|
|
62
|
+
const relativeSource = (0, node_path_1.relative)(targetDir, sourcePath);
|
|
63
|
+
try {
|
|
64
|
+
(0, node_fs_1.symlinkSync)(relativeSource, targetPath, 'dir');
|
|
65
|
+
// Count the files in the source directory
|
|
66
|
+
const fileCount = countFilesInDirectory(sourcePath);
|
|
67
|
+
totalFileCount += fileCount;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error.code === 'EEXIST') {
|
|
71
|
+
console.log(` ⚠️ ${relativeTargetPath} already exists (skipped)`);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return totalFileCount;
|
|
79
|
+
};
|
|
80
|
+
exports.symlinkResourceDirectories = symlinkResourceDirectories;
|
|
81
|
+
//# sourceMappingURL=symlinkResourceDirectories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symlinkResourceDirectories.js","sourceRoot":"","sources":["../../../../src/logic/invoke/link/symlinkResourceDirectories.ts"],"names":[],"mappings":"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"}
|