@warnyin/sdlc 0.1.0 → 0.1.2
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/bin/cli.mjs +13 -1
- package/package.json +2 -2
- package/payload/hooks/_shared.mjs +20 -7
- package/scripts/validate.mjs +10 -1
package/bin/cli.mjs
CHANGED
|
@@ -465,6 +465,18 @@ export async function main(argv = process.argv.slice(2), projectRoot = process.c
|
|
|
465
465
|
}
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
-
|
|
468
|
+
// npx invokes the bin via a node_modules/.bin symlink, so argv[1] must be
|
|
469
|
+
// realpath-resolved before comparing with import.meta.url (which the ESM
|
|
470
|
+
// loader already resolves) — otherwise main() silently never runs.
|
|
471
|
+
function isEntrypoint() {
|
|
472
|
+
if (!process.argv[1]) return false;
|
|
473
|
+
try {
|
|
474
|
+
return fs.realpathSync.native(path.resolve(process.argv[1])) === fileURLToPath(import.meta.url);
|
|
475
|
+
} catch {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (isEntrypoint()) {
|
|
469
481
|
main();
|
|
470
482
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@warnyin/sdlc",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Spec-driven, AI-driven SDLC framework — token-lean specs, contract-first changes, autonomous pipeline with managed hooks. Operationalizes the Day-1 'New SDLC with Vibe Coding' work process.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"LICENSE"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"test": "node --test
|
|
19
|
+
"test": "node --test",
|
|
20
20
|
"setup:dogfood": "node bin/cli.mjs init --tool claude && node bin/cli.mjs update"
|
|
21
21
|
},
|
|
22
22
|
"engines": {
|
|
@@ -15,14 +15,27 @@ export function resolveRoots(importMetaUrl) {
|
|
|
15
15
|
return { hooksDir, sdlcRoot, projectRoot };
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
// Reads the hook payload from stdin. Must NEVER hang: when a playbook or a
|
|
19
|
+
// user script invokes a hook utility with stdin open-but-idle (no piped JSON),
|
|
20
|
+
// resolve null after a short grace period instead of blocking forever.
|
|
21
|
+
export function readStdinJson({ timeoutMs = 1000 } = {}) {
|
|
22
|
+
return new Promise((resolve) => {
|
|
20
23
|
let data = '';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
let done = false;
|
|
25
|
+
const finish = () => {
|
|
26
|
+
if (done) return;
|
|
27
|
+
done = true;
|
|
28
|
+
// Release stdin so an open-idle stream cannot keep the event loop alive.
|
|
29
|
+
process.stdin.pause();
|
|
30
|
+
if (typeof process.stdin.unref === 'function') process.stdin.unref();
|
|
31
|
+
try { resolve(data.trim() ? JSON.parse(data) : null); } catch { resolve(null); }
|
|
32
|
+
};
|
|
33
|
+
const timer = setTimeout(finish, timeoutMs);
|
|
34
|
+
if (typeof timer.unref === 'function') timer.unref();
|
|
35
|
+
process.stdin.on('data', (chunk) => { data += chunk; });
|
|
36
|
+
process.stdin.on('end', finish);
|
|
37
|
+
process.stdin.on('error', finish);
|
|
38
|
+
});
|
|
26
39
|
}
|
|
27
40
|
|
|
28
41
|
// Resolve symlinks on the deepest EXISTING ancestor, then re-attach the tail.
|
package/scripts/validate.mjs
CHANGED
|
@@ -33,6 +33,15 @@ function main() {
|
|
|
33
33
|
process.exit(errors > 0 ? 1 : 0);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
function isEntrypoint() {
|
|
37
|
+
if (!process.argv[1]) return false;
|
|
38
|
+
try {
|
|
39
|
+
return fs.realpathSync.native(path.resolve(process.argv[1])) === fileURLToPath(import.meta.url);
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (isEntrypoint()) {
|
|
37
46
|
main();
|
|
38
47
|
}
|