azcodr 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/hooks.json +3 -3
- package/.github/workflows/ci.yml +1 -0
- package/.github/workflows/publish.yml +0 -4
- package/AGENTS.md +1 -1
- package/bin/azcodr.js +11 -4
- package/lib/cli-parse.d.ts +32 -0
- package/lib/cli-parse.d.ts.map +1 -0
- package/lib/cli-parse.js +45 -41
- package/lib/cli-parse.js.map +1 -0
- package/lib/cli-target.d.ts +66 -0
- package/lib/cli-target.d.ts.map +1 -0
- package/lib/cli-target.js +89 -96
- package/lib/cli-target.js.map +1 -0
- package/lib/cli.d.ts +40 -0
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +122 -136
- package/lib/cli.js.map +1 -0
- package/lib/errors.d.ts +54 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +25 -18
- package/lib/errors.js.map +1 -0
- package/lib/git.d.ts +23 -0
- package/lib/git.d.ts.map +1 -0
- package/lib/git.js +33 -22
- package/lib/git.js.map +1 -0
- package/lib/guards.d.ts +50 -0
- package/lib/guards.d.ts.map +1 -0
- package/lib/guards.js +75 -64
- package/lib/guards.js.map +1 -0
- package/lib/index.d.ts +14 -188
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +17 -5
- package/lib/index.js.map +1 -0
- package/lib/links.d.ts +42 -0
- package/lib/links.d.ts.map +1 -0
- package/lib/links.js +116 -99
- package/lib/links.js.map +1 -0
- package/lib/permissions.d.ts +13 -0
- package/lib/permissions.d.ts.map +1 -0
- package/lib/permissions.js +40 -36
- package/lib/permissions.js.map +1 -0
- package/lib/repo.d.ts +30 -0
- package/lib/repo.d.ts.map +1 -0
- package/lib/repo.js +80 -71
- package/lib/repo.js.map +1 -0
- package/lib/scaffold.d.ts +109 -0
- package/lib/scaffold.d.ts.map +1 -0
- package/lib/scaffold.js +165 -197
- package/lib/scaffold.js.map +1 -0
- package/memory.md +24 -0
- package/package.json +14 -5
- package/scripts/validate/adr.js +11 -7
- package/scripts/validate/io.js +7 -9
- package/scripts/validate/links.js +6 -7
- package/scripts/validate/parity.js +5 -7
- package/scripts/validate/root.js +6 -7
- package/scripts/validate/rules.js +7 -9
- package/scripts/validate/skills.js +8 -10
- package/scripts/validate/text.js +3 -5
- package/scripts/validate-cli.js +1 -2
- package/scripts/validate.js +37 -19
- package/src/cli-parse.ts +77 -0
- package/src/cli-target.ts +167 -0
- package/src/cli.ts +240 -0
- package/src/errors.ts +50 -0
- package/src/git.ts +42 -0
- package/src/guards.ts +116 -0
- package/src/index.ts +60 -0
- package/src/links.ts +153 -0
- package/src/permissions.ts +46 -0
- package/src/repo.ts +104 -0
- package/src/scaffold.ts +282 -0
- package/scripts/test_coverage.js +0 -66
package/lib/links.js
CHANGED
|
@@ -1,123 +1,140 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const fs = require('node:fs');
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Detects whether linkName and targetFileName refer to the same entry on a case-insensitive filesystem.
|
|
8
|
-
* Uses exact directory listing (not existsSync, which lies on case-insensitive systems).
|
|
9
|
-
*/
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
10
3
|
function namesDifferOnlyByCase(linkName, targetFileName) {
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
if (linkName.toLowerCase() !== targetFileName.toLowerCase())
|
|
5
|
+
return false;
|
|
6
|
+
return linkName !== targetFileName;
|
|
13
7
|
}
|
|
14
|
-
|
|
15
8
|
function readDirEntries(targetDir) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
try {
|
|
10
|
+
return fs.readdirSync(targetDir);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
21
15
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
function bothEntriesExist(options) {
|
|
17
|
+
const { targetDir, linkName, targetFileName, entries } = options;
|
|
18
|
+
if (!entries.includes(targetFileName) || !entries.includes(linkName))
|
|
19
|
+
return false;
|
|
20
|
+
try {
|
|
21
|
+
fs.lstatSync(path.join(targetDir, targetFileName));
|
|
22
|
+
fs.lstatSync(path.join(targetDir, linkName));
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
32
28
|
}
|
|
33
|
-
|
|
34
29
|
function accessiblePair(targetPath, linkPath) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function isSameCaseInsensitiveFile(targetDir, linkName, targetFileName) {
|
|
48
|
-
if (linkName === targetFileName) return true;
|
|
49
|
-
if (!namesDifferOnlyByCase(linkName, targetFileName)) return false;
|
|
50
|
-
const entries = readDirEntries(targetDir);
|
|
51
|
-
if (entries === null) return false;
|
|
52
|
-
if (bothEntriesExist({ targetDir, linkName, targetFileName, entries })) {
|
|
53
|
-
return !fs.lstatSync(path.join(targetDir, linkName)).isSymbolicLink();
|
|
54
|
-
}
|
|
55
|
-
const targetPath = path.join(targetDir, targetFileName);
|
|
56
|
-
const linkPath = path.join(targetDir, linkName);
|
|
57
|
-
return accessiblePair(targetPath, linkPath);
|
|
30
|
+
if (!fs.existsSync(targetPath) || !fs.existsSync(linkPath))
|
|
31
|
+
return false;
|
|
32
|
+
try {
|
|
33
|
+
fs.lstatSync(targetPath);
|
|
34
|
+
fs.lstatSync(linkPath);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
58
40
|
}
|
|
59
|
-
|
|
60
41
|
function removeIfExists(linkPath) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
42
|
+
try {
|
|
43
|
+
fs.lstatSync(linkPath);
|
|
44
|
+
fs.rmSync(linkPath, { force: true });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Path does not exist, proceed
|
|
48
|
+
}
|
|
67
49
|
}
|
|
68
|
-
|
|
69
50
|
function copyFallback(targetDir, linkName, targetFileName) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
51
|
+
const sourceFile = path.resolve(targetDir, targetFileName);
|
|
52
|
+
if (fs.existsSync(sourceFile)) {
|
|
53
|
+
fs.copyFileSync(sourceFile, path.join(targetDir, linkName));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Detects whether linkName and targetFileName refer to the same entry on a case-insensitive filesystem.
|
|
58
|
+
* Uses exact directory listing (not existsSync, which lies on case-insensitive systems).
|
|
59
|
+
*
|
|
60
|
+
* @param targetDir - Directory containing the file entries.
|
|
61
|
+
* @param linkName - Name of the proposed symlink or alias entry.
|
|
62
|
+
* @param targetFileName - Target file name to match against.
|
|
63
|
+
* @returns True if both names resolve to the same disk file on a case-insensitive filesystem.
|
|
64
|
+
*/
|
|
65
|
+
export function isSameCaseInsensitiveFile(targetDir, linkName, targetFileName) {
|
|
66
|
+
if (linkName === targetFileName)
|
|
67
|
+
return true;
|
|
68
|
+
if (!namesDifferOnlyByCase(linkName, targetFileName))
|
|
69
|
+
return false;
|
|
70
|
+
const entries = readDirEntries(targetDir);
|
|
71
|
+
if (entries === null)
|
|
72
|
+
return false;
|
|
73
|
+
if (bothEntriesExist({ targetDir, linkName, targetFileName, entries })) {
|
|
74
|
+
return !fs.lstatSync(path.join(targetDir, linkName)).isSymbolicLink();
|
|
75
|
+
}
|
|
76
|
+
const targetPath = path.join(targetDir, targetFileName);
|
|
77
|
+
const linkPath = path.join(targetDir, linkName);
|
|
78
|
+
return accessiblePair(targetPath, linkPath);
|
|
75
79
|
}
|
|
76
|
-
|
|
77
80
|
/**
|
|
78
81
|
* Safely creates or updates a symbolic link, falling back to a file copy if symlinks are unsupported.
|
|
82
|
+
*
|
|
83
|
+
* @param options - Options specifying target directory, link name, target file name, and dry-run mode.
|
|
84
|
+
* @returns True if the symlink or copy fallback was successfully established.
|
|
79
85
|
*/
|
|
80
|
-
function ensureSymlink(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
export function ensureSymlink(options) {
|
|
87
|
+
const { targetDir, linkName, targetFileName, dryRun = false } = options;
|
|
88
|
+
if (dryRun)
|
|
89
|
+
return true;
|
|
90
|
+
if (isSameCaseInsensitiveFile(targetDir, linkName, targetFileName))
|
|
91
|
+
return true;
|
|
92
|
+
const linkPath = path.join(targetDir, linkName);
|
|
93
|
+
removeIfExists(linkPath);
|
|
94
|
+
try {
|
|
95
|
+
fs.symlinkSync(targetFileName, linkPath, 'file');
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
copyFallback(targetDir, linkName, targetFileName);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
92
102
|
}
|
|
93
|
-
|
|
94
103
|
/**
|
|
95
104
|
* Creates a symlink, falling back to a text pointer (not a full copy).
|
|
96
105
|
* Used for .github/copilot-instructions.md where a full AGENTS.md copy would
|
|
97
106
|
* break relative markdown links (they resolve from .github/, not root).
|
|
107
|
+
*
|
|
108
|
+
* @param options - Options specifying target directory, link name, target file name, and dry-run mode.
|
|
109
|
+
* @returns True if the symlink or pointer fallback was successfully established.
|
|
98
110
|
*/
|
|
99
|
-
function ensureSymlinkOrPointer(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
export function ensureSymlinkOrPointer(options) {
|
|
112
|
+
const { targetDir, linkName, targetFileName, dryRun = false } = options;
|
|
113
|
+
if (dryRun)
|
|
114
|
+
return true;
|
|
115
|
+
const linkPath = path.join(targetDir, linkName);
|
|
103
116
|
try {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
117
|
+
try {
|
|
118
|
+
fs.lstatSync(linkPath);
|
|
119
|
+
const existing = fs.existsSync(linkPath) ? fs.readFileSync(linkPath, 'utf-8') : '';
|
|
120
|
+
if (existing.trim() === targetFileName)
|
|
121
|
+
return true;
|
|
122
|
+
fs.rmSync(linkPath, { force: true });
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Path does not exist, proceed
|
|
126
|
+
}
|
|
127
|
+
fs.symlinkSync(targetFileName, linkPath, 'file');
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
fs.writeFileSync(linkPath, `${targetFileName}\n`, 'utf-8');
|
|
132
|
+
return true;
|
|
110
133
|
}
|
|
111
|
-
fs.symlinkSync(targetFileName, linkPath, 'file');
|
|
112
|
-
return true;
|
|
113
|
-
} catch {
|
|
114
|
-
fs.writeFileSync(linkPath, `${targetFileName}\n`, 'utf-8');
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
117
134
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
ensureSymlinkOrPointer
|
|
135
|
+
export default {
|
|
136
|
+
isSameCaseInsensitiveFile,
|
|
137
|
+
ensureSymlink,
|
|
138
|
+
ensureSymlinkOrPointer
|
|
123
139
|
};
|
|
140
|
+
//# sourceMappingURL=links.js.map
|
package/lib/links.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"links.js","sourceRoot":"","sources":["../src/links.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAmB7B,SAAS,qBAAqB,CAAC,QAAgB,EAAE,cAAsB;IACrE,IAAI,QAAQ,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,WAAW,EAAE;QAAE,OAAO,KAAK,CAAC;IAC1E,OAAO,QAAQ,KAAK,cAAc,CAAC;AACrC,CAAC;AAED,SAAS,cAAc,CAAC,SAAiB;IACvC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAgC;IACxD,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACjE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACnF,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC;QACnD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,UAAkB,EAAE,QAAgB;IAC1D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACzE,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACzB,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,QAAgB;IACtC,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACvB,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;IACjC,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,SAAiB,EAAE,QAAgB,EAAE,cAAsB;IAC/E,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAC3D,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CACvC,SAAiB,EACjB,QAAgB,EAChB,cAAsB;IAEtB,IAAI,QAAQ,KAAK,cAAc;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,cAAc,CAAC;QAAE,OAAO,KAAK,CAAC;IACnE,MAAM,OAAO,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACnC,IAAI,gBAAgB,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QACvE,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;IACxE,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChD,OAAO,cAAc,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,OAA6B;IACzD,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IACxE,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC;QAAE,OAAO,IAAI,CAAC;IAChF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChD,cAAc,CAAC,QAAQ,CAAC,CAAC;IACzB,IAAI,CAAC;QACH,EAAE,CAAC,WAAW,CAAC,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA6B;IAClE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IACxE,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACvB,MAAM,QAAQ,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACnF,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,cAAc;gBAAE,OAAO,IAAI,CAAC;YACpD,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,+BAA+B;QACjC,CAAC;QACD,EAAE,CAAC,WAAW,CAAC,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,cAAc,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,eAAe;IACb,yBAAyB;IACzB,aAAa;IACb,sBAAsB;CACvB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensures all bash scripts in agent and skill directories have executable permissions (0o755).
|
|
3
|
+
*
|
|
4
|
+
* @param targetDir - Root directory containing .agents and skills.
|
|
5
|
+
* @param dryRun - When true, simulates permission changes without modifying disk.
|
|
6
|
+
* @returns Array of file paths that were modified or would be modified.
|
|
7
|
+
*/
|
|
8
|
+
export declare function makeScriptsExecutable(targetDir: string, dryRun?: boolean): string[];
|
|
9
|
+
declare const _default: {
|
|
10
|
+
makeScriptsExecutable: typeof makeScriptsExecutable;
|
|
11
|
+
};
|
|
12
|
+
export default _default;
|
|
13
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAyBA;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,MAAM,EAAE,CAWjF;;;;AAED,wBAAyC"}
|
package/lib/permissions.js
CHANGED
|
@@ -1,44 +1,48 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const fs = require('node:fs');
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
6
3
|
function chmodShFile(filePath, dryRun) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
if (dryRun)
|
|
5
|
+
return;
|
|
6
|
+
try {
|
|
7
|
+
fs.chmodSync(filePath, 0o755);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// Non-critical if filesystem does not support POSIX permissions
|
|
11
|
+
}
|
|
13
12
|
}
|
|
14
|
-
|
|
15
13
|
function chmodShFilesIn(scriptsDir, dryRun) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
const modified = [];
|
|
15
|
+
if (!fs.existsSync(scriptsDir) || !fs.statSync(scriptsDir).isDirectory())
|
|
16
|
+
return modified;
|
|
17
|
+
const files = fs.readdirSync(scriptsDir);
|
|
18
|
+
for (const file of files) {
|
|
19
|
+
if (!file.endsWith('.sh'))
|
|
20
|
+
continue;
|
|
21
|
+
const filePath = path.join(scriptsDir, file);
|
|
22
|
+
modified.push(filePath);
|
|
23
|
+
chmodShFile(filePath, dryRun);
|
|
24
|
+
}
|
|
25
|
+
return modified;
|
|
26
26
|
}
|
|
27
|
-
|
|
28
27
|
/**
|
|
29
28
|
* Ensures all bash scripts in agent and skill directories have executable permissions (0o755).
|
|
29
|
+
*
|
|
30
|
+
* @param targetDir - Root directory containing .agents and skills.
|
|
31
|
+
* @param dryRun - When true, simulates permission changes without modifying disk.
|
|
32
|
+
* @returns Array of file paths that were modified or would be modified.
|
|
30
33
|
*/
|
|
31
|
-
function makeScriptsExecutable(targetDir, dryRun = false) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
export function makeScriptsExecutable(targetDir, dryRun = false) {
|
|
35
|
+
const agentScriptsDir = path.join(targetDir, '.agents', 'scripts');
|
|
36
|
+
const modified = chmodShFilesIn(agentScriptsDir, dryRun);
|
|
37
|
+
const skillsDir = path.join(targetDir, '.agents', 'skills');
|
|
38
|
+
if (!fs.existsSync(skillsDir))
|
|
39
|
+
return modified;
|
|
40
|
+
const skills = fs.readdirSync(skillsDir);
|
|
41
|
+
for (const skill of skills) {
|
|
42
|
+
const scriptsDir = path.join(skillsDir, skill, 'scripts');
|
|
43
|
+
modified.push(...chmodShFilesIn(scriptsDir, dryRun));
|
|
44
|
+
}
|
|
45
|
+
return modified;
|
|
42
46
|
}
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
export default { makeScriptsExecutable };
|
|
48
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,SAAS,WAAW,CAAC,QAAgB,EAAE,MAAe;IACpD,IAAI,MAAM;QAAE,OAAO;IACnB,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;IAClE,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,UAAkB,EAAE,MAAe;IACzD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC1F,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC7C,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAiB,EAAE,MAAM,GAAG,KAAK;IACrE,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACnE,MAAM,QAAQ,GAAG,cAAc,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC5D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/C,MAAM,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAC1D,QAAQ,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,eAAe,EAAE,qBAAqB,EAAE,CAAC"}
|
package/lib/repo.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options controlling git repository initialization.
|
|
3
|
+
*/
|
|
4
|
+
export interface InitGitOptions {
|
|
5
|
+
noGit?: boolean;
|
|
6
|
+
dryRun?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Detects whether targetDir is already inside an existing Git worktree.
|
|
10
|
+
* Socket note: shell access is limited to `git rev-parse` via runGit (no shell).
|
|
11
|
+
*
|
|
12
|
+
* @param targetDir - Directory path to inspect.
|
|
13
|
+
* @returns True if target directory is within a git worktree, false otherwise.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isInsideGitWorkTree(targetDir: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Initializes a git repository in the target directory if not already inside one.
|
|
18
|
+
* Socket note: only allowlisted `git init/branch/add/commit` via execFileSync, cwd scoped.
|
|
19
|
+
*
|
|
20
|
+
* @param targetDir - Directory where git repository should be initialized.
|
|
21
|
+
* @param options - Configuration options for git initialization.
|
|
22
|
+
* @returns True if repository was initialized and committed, false otherwise.
|
|
23
|
+
*/
|
|
24
|
+
export declare function initGit(targetDir: string, options?: InitGitOptions): boolean;
|
|
25
|
+
declare const _default: {
|
|
26
|
+
isInsideGitWorkTree: typeof isInsideGitWorkTree;
|
|
27
|
+
initGit: typeof initGit;
|
|
28
|
+
};
|
|
29
|
+
export default _default;
|
|
30
|
+
//# sourceMappingURL=repo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../src/repo.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAW9D;AA8CD;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAchF;;;;;AAED,wBAAgD"}
|
package/lib/repo.js
CHANGED
|
@@ -1,90 +1,99 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const { runGit } = require('./git.js');
|
|
6
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
import { runGit } from './git.js';
|
|
7
5
|
const INITIAL_COMMIT_MESSAGE = 'chore: initial scaffold from azcodr template';
|
|
8
|
-
|
|
9
6
|
/**
|
|
10
7
|
* Detects whether targetDir is already inside an existing Git worktree.
|
|
11
8
|
* Socket note: shell access is limited to `git rev-parse` via runGit (no shell).
|
|
9
|
+
*
|
|
10
|
+
* @param targetDir - Directory path to inspect.
|
|
11
|
+
* @returns True if target directory is within a git worktree, false otherwise.
|
|
12
12
|
*/
|
|
13
|
-
function isInsideGitWorkTree(targetDir) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
export function isInsideGitWorkTree(targetDir) {
|
|
14
|
+
try {
|
|
15
|
+
const checkDir = fs.existsSync(targetDir) ? targetDir : path.dirname(targetDir);
|
|
16
|
+
const out = runGit(['rev-parse', '--is-inside-work-tree'], {
|
|
17
|
+
cwd: checkDir,
|
|
18
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
19
|
+
});
|
|
20
|
+
return String(out).trim() === 'true';
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
24
25
|
}
|
|
25
|
-
|
|
26
26
|
function renameBranchMain(targetDir) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
try {
|
|
28
|
+
runGit(['branch', '-m', 'main'], { cwd: targetDir, stdio: 'ignore' });
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Non-critical if branch rename fails
|
|
32
|
+
}
|
|
32
33
|
}
|
|
33
|
-
|
|
34
34
|
function initRepository(targetDir) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
try {
|
|
36
|
+
runGit(['init', '-b', 'main', '-q'], { cwd: targetDir, stdio: 'ignore' });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
runGit(['init', '-q'], { cwd: targetDir, stdio: 'ignore' });
|
|
40
|
+
renameBranchMain(targetDir);
|
|
41
|
+
}
|
|
41
42
|
}
|
|
42
|
-
|
|
43
43
|
function commitWithFallbackIdentity(targetDir) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
const options = { cwd: targetDir, stdio: 'ignore' };
|
|
45
|
+
try {
|
|
46
|
+
runGit(['commit', '-q', '-m', INITIAL_COMMIT_MESSAGE], options);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
runGit(['commit', '-q', '-m', INITIAL_COMMIT_MESSAGE], {
|
|
50
|
+
...options,
|
|
51
|
+
env: {
|
|
52
|
+
...process.env,
|
|
53
|
+
GIT_AUTHOR_NAME: 'Subodh Khanal',
|
|
54
|
+
GIT_AUTHOR_EMAIL: 'prosubodh@gmail.com',
|
|
55
|
+
GIT_COMMITTER_NAME: 'Subodh Khanal',
|
|
56
|
+
GIT_COMMITTER_EMAIL: 'prosubodh@gmail.com'
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
59
60
|
}
|
|
60
|
-
|
|
61
61
|
function initialCommit(targetDir) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
try {
|
|
63
|
+
runGit(['add', '-A'], { cwd: targetDir, stdio: 'ignore' });
|
|
64
|
+
commitWithFallbackIdentity(targetDir);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Non-critical if initial commit fails
|
|
68
|
+
}
|
|
68
69
|
}
|
|
69
|
-
|
|
70
70
|
/**
|
|
71
71
|
* Initializes a git repository in the target directory if not already inside one.
|
|
72
72
|
* Socket note: only allowlisted `git init/branch/add/commit` via execFileSync, cwd scoped.
|
|
73
|
+
*
|
|
74
|
+
* @param targetDir - Directory where git repository should be initialized.
|
|
75
|
+
* @param options - Configuration options for git initialization.
|
|
76
|
+
* @returns True if repository was initialized and committed, false otherwise.
|
|
73
77
|
*/
|
|
74
|
-
function initGit(targetDir, options = {}) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
export function initGit(targetDir, options = {}) {
|
|
79
|
+
const { noGit = false, dryRun = false } = options;
|
|
80
|
+
if (noGit)
|
|
81
|
+
return false;
|
|
82
|
+
const gitDir = path.join(targetDir, '.git');
|
|
83
|
+
if (fs.existsSync(gitDir))
|
|
84
|
+
return false;
|
|
85
|
+
if (isInsideGitWorkTree(targetDir))
|
|
86
|
+
return false;
|
|
87
|
+
if (dryRun)
|
|
88
|
+
return true;
|
|
89
|
+
try {
|
|
90
|
+
initRepository(targetDir);
|
|
91
|
+
initialCommit(targetDir);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
88
97
|
}
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
export default { isInsideGitWorkTree, initGit };
|
|
99
|
+
//# sourceMappingURL=repo.js.map
|
package/lib/repo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo.js","sourceRoot":"","sources":["../src/repo.ts"],"names":[],"mappings":"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"}
|