@attalabs/vinaya 0.1.1 → 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/aeg-root/contracts/archivist-tranche-archivist.md +92 -0
- package/aeg-root/contracts/brief-developer.md +140 -0
- package/aeg-root/contracts/developer-reviewer.md +106 -0
- package/aeg-root/contracts/planner-brief.md +130 -0
- package/aeg-root/contracts/reviewer-archivist.md +96 -0
- package/aeg-root/contracts/tranche-archivist-planner.md +116 -0
- package/aeg-root/coordination.md +293 -0
- package/aeg-root/enforcement.md +159 -0
- package/aeg-root/glossary.md +32 -0
- package/aeg-root/process.md +371 -0
- package/aeg-root/roles/archivist.md +167 -0
- package/aeg-root/roles/brief-author.md +108 -0
- package/aeg-root/roles/developer.md +429 -0
- package/aeg-root/roles/planner.md +285 -0
- package/aeg-root/roles/principal.md +107 -0
- package/aeg-root/roles/reviewer.md +130 -0
- package/aeg-root/roles/security.md +121 -0
- package/aeg-root/roles/tranche-archivist.md +257 -0
- package/aeg-root/skills/aeg/SKILL.md +90 -0
- package/aeg-root/skills/aeg-roles/SKILL.md +58 -0
- package/aeg-root/skills/brief-authoring/SKILL.md +497 -0
- package/aeg-root/state-machine.md +642 -0
- package/aeg-root/templates/brief-template.md +103 -0
- package/aeg-root/templates/issue-rationale-template.md +35 -0
- package/aeg-root/templates/pr-report-template.md +68 -0
- package/aeg-root/tranche-model.md +304 -0
- package/dist/checks/bin/check-branch-topology.js +2840 -0
- package/dist/checks/bin/check-brief-shape.js +2775 -0
- package/dist/checks/bin/check-closes-n.js +2824 -0
- package/dist/checks/bin/check-coherence.js +2922 -0
- package/dist/checks/bin/check-dead-branch-push.js +2799 -0
- package/dist/checks/bin/check-dispatch-readiness.js +2923 -0
- package/dist/checks/bin/check-doc-coverage-push.js +2818 -0
- package/dist/checks/bin/check-doc-coverage.js +2816 -0
- package/dist/checks/bin/check-first-push-dispatch.js +2888 -0
- package/dist/checks/bin/check-issue-assignment.js +2863 -0
- package/dist/checks/bin/check-no-disk-state.js +2811 -0
- package/dist/checks/bin/check-reader-resolvable-prose.js +2820 -0
- package/dist/checks/bin/check-registry-gates.js +2923 -0
- package/dist/checks/bin/check-review-gate.js +2826 -0
- package/dist/checks/bin/check-single-plan-pr.js +2810 -0
- package/dist/checks/bin/check-test-plan.js +2775 -0
- package/dist/index.js +110 -94
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { readFileSync as readFileSync11 } from "node:fs";
|
|
5
|
-
import { dirname as dirname5, join as
|
|
5
|
+
import { dirname as dirname5, join as join15 } from "node:path";
|
|
6
6
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7
7
|
|
|
8
8
|
// src/commands/archive.ts
|
|
@@ -1244,6 +1244,7 @@ function emitCheckError(error) {
|
|
|
1244
1244
|
}
|
|
1245
1245
|
|
|
1246
1246
|
// src/checks/registry.ts
|
|
1247
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
1247
1248
|
import { join as join3 } from "node:path";
|
|
1248
1249
|
|
|
1249
1250
|
// src/lib/package-root.ts
|
|
@@ -1262,96 +1263,102 @@ function packageRoot(moduleUrl) {
|
|
|
1262
1263
|
}
|
|
1263
1264
|
|
|
1264
1265
|
// src/checks/registry.ts
|
|
1265
|
-
var
|
|
1266
|
+
var DIST_BIN_DIR = join3(packageRoot(import.meta.url), "dist", "checks", "bin");
|
|
1267
|
+
var SRC_BIN_DIR = join3(packageRoot(import.meta.url), "src", "checks", "bin");
|
|
1268
|
+
var BIN_DIR = existsSync3(DIST_BIN_DIR) ? DIST_BIN_DIR : SRC_BIN_DIR;
|
|
1269
|
+
var BIN_EXT = BIN_DIR === DIST_BIN_DIR ? ".js" : ".ts";
|
|
1270
|
+
function bin(name) {
|
|
1271
|
+
return join3(BIN_DIR, `${name}${BIN_EXT}`);
|
|
1272
|
+
}
|
|
1266
1273
|
function coreCheckRegistry() {
|
|
1267
1274
|
return [
|
|
1268
1275
|
{
|
|
1269
1276
|
name: "brief-shape",
|
|
1270
|
-
run:
|
|
1277
|
+
run: bin("check-brief-shape"),
|
|
1271
1278
|
scope: "diff",
|
|
1272
1279
|
timeoutMs: 15000
|
|
1273
1280
|
},
|
|
1274
1281
|
{
|
|
1275
1282
|
name: "doc-coverage",
|
|
1276
|
-
run:
|
|
1283
|
+
run: bin("check-doc-coverage"),
|
|
1277
1284
|
scope: "diff",
|
|
1278
1285
|
timeoutMs: 15000
|
|
1279
1286
|
},
|
|
1280
1287
|
{
|
|
1281
1288
|
name: "coherence",
|
|
1282
|
-
run:
|
|
1289
|
+
run: bin("check-coherence"),
|
|
1283
1290
|
scope: "full",
|
|
1284
1291
|
timeoutMs: 30000
|
|
1285
1292
|
},
|
|
1286
1293
|
{
|
|
1287
1294
|
name: "dispatch-readiness",
|
|
1288
|
-
run:
|
|
1295
|
+
run: bin("check-dispatch-readiness"),
|
|
1289
1296
|
scope: "full",
|
|
1290
1297
|
timeoutMs: 30000
|
|
1291
1298
|
},
|
|
1292
1299
|
{
|
|
1293
1300
|
name: "closes-n",
|
|
1294
|
-
run:
|
|
1301
|
+
run: bin("check-closes-n"),
|
|
1295
1302
|
scope: "diff",
|
|
1296
1303
|
timeoutMs: 15000
|
|
1297
1304
|
},
|
|
1298
1305
|
{
|
|
1299
1306
|
name: "single-plan-pr",
|
|
1300
|
-
run:
|
|
1307
|
+
run: bin("check-single-plan-pr"),
|
|
1301
1308
|
scope: "diff",
|
|
1302
1309
|
timeoutMs: 15000
|
|
1303
1310
|
},
|
|
1304
1311
|
{
|
|
1305
1312
|
name: "test-plan",
|
|
1306
|
-
run:
|
|
1313
|
+
run: bin("check-test-plan"),
|
|
1307
1314
|
scope: "diff",
|
|
1308
1315
|
timeoutMs: 15000
|
|
1309
1316
|
},
|
|
1310
1317
|
{
|
|
1311
1318
|
name: "no-disk-state",
|
|
1312
|
-
run:
|
|
1319
|
+
run: bin("check-no-disk-state"),
|
|
1313
1320
|
scope: "diff",
|
|
1314
1321
|
timeoutMs: 15000
|
|
1315
1322
|
},
|
|
1316
1323
|
{
|
|
1317
1324
|
name: "registry-gates",
|
|
1318
|
-
run:
|
|
1325
|
+
run: bin("check-registry-gates"),
|
|
1319
1326
|
scope: "full",
|
|
1320
1327
|
timeoutMs: 30000
|
|
1321
1328
|
},
|
|
1322
1329
|
{
|
|
1323
1330
|
name: "review-gate",
|
|
1324
|
-
run:
|
|
1331
|
+
run: bin("check-review-gate"),
|
|
1325
1332
|
scope: "full",
|
|
1326
1333
|
timeoutMs: 30000
|
|
1327
1334
|
},
|
|
1328
1335
|
{
|
|
1329
1336
|
name: "branch-topology",
|
|
1330
|
-
run:
|
|
1337
|
+
run: bin("check-branch-topology"),
|
|
1331
1338
|
scope: "full",
|
|
1332
1339
|
timeoutMs: 30000
|
|
1333
1340
|
},
|
|
1334
1341
|
{
|
|
1335
1342
|
name: "dead-branch-push",
|
|
1336
|
-
run:
|
|
1343
|
+
run: bin("check-dead-branch-push"),
|
|
1337
1344
|
scope: "full",
|
|
1338
1345
|
timeoutMs: 30000
|
|
1339
1346
|
},
|
|
1340
1347
|
{
|
|
1341
1348
|
name: "first-push-dispatch",
|
|
1342
|
-
run:
|
|
1349
|
+
run: bin("check-first-push-dispatch"),
|
|
1343
1350
|
scope: "full",
|
|
1344
1351
|
timeoutMs: 30000
|
|
1345
1352
|
},
|
|
1346
1353
|
{
|
|
1347
1354
|
name: "doc-coverage-push",
|
|
1348
|
-
run:
|
|
1355
|
+
run: bin("check-doc-coverage-push"),
|
|
1349
1356
|
scope: "diff",
|
|
1350
1357
|
timeoutMs: 15000
|
|
1351
1358
|
},
|
|
1352
1359
|
{
|
|
1353
1360
|
name: "issue-assignment",
|
|
1354
|
-
run:
|
|
1361
|
+
run: bin("check-issue-assignment"),
|
|
1355
1362
|
scope: "full",
|
|
1356
1363
|
timeoutMs: 30000
|
|
1357
1364
|
}
|
|
@@ -1487,7 +1494,7 @@ async function runChecks(specs, opts) {
|
|
|
1487
1494
|
}
|
|
1488
1495
|
|
|
1489
1496
|
// src/lib/config.ts
|
|
1490
|
-
import { existsSync as
|
|
1497
|
+
import { existsSync as existsSync4, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
1491
1498
|
import { homedir } from "node:os";
|
|
1492
1499
|
import { dirname as dirname2, join as join4 } from "node:path";
|
|
1493
1500
|
import { z } from "zod";
|
|
@@ -1562,7 +1569,7 @@ function findLocalConfig() {
|
|
|
1562
1569
|
let dir = process.cwd();
|
|
1563
1570
|
while (true) {
|
|
1564
1571
|
const candidate = join4(dir, LOCAL_CONFIG_FILENAME);
|
|
1565
|
-
if (
|
|
1572
|
+
if (existsSync4(candidate))
|
|
1566
1573
|
return candidate;
|
|
1567
1574
|
const parent = dirname2(dir);
|
|
1568
1575
|
if (parent === dir)
|
|
@@ -1574,7 +1581,7 @@ function configPath() {
|
|
|
1574
1581
|
const local = findLocalConfig();
|
|
1575
1582
|
if (local)
|
|
1576
1583
|
return local;
|
|
1577
|
-
if (
|
|
1584
|
+
if (existsSync4(GLOBAL_CONFIG_PATH))
|
|
1578
1585
|
return GLOBAL_CONFIG_PATH;
|
|
1579
1586
|
return null;
|
|
1580
1587
|
}
|
|
@@ -1688,7 +1695,7 @@ async function checkCommand(args) {
|
|
|
1688
1695
|
|
|
1689
1696
|
// src/commands/demo.ts
|
|
1690
1697
|
import { execFileSync as execFileSync5, spawnSync } from "node:child_process";
|
|
1691
|
-
import { existsSync as
|
|
1698
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2, rmSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1692
1699
|
import { isAbsolute, join as join5 } from "node:path";
|
|
1693
1700
|
var DEMO_BRANCH_PREFIX = "vinaya/demo-break-";
|
|
1694
1701
|
var FIXTURE_PATH = ".vinaya-demo-brief.md";
|
|
@@ -1696,6 +1703,13 @@ var STATE_FILENAME = "vinaya-demo-state.json";
|
|
|
1696
1703
|
function gitCapture(repoRoot, args) {
|
|
1697
1704
|
return execFileSync5("git", args, { cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
1698
1705
|
}
|
|
1706
|
+
function currentBranchName(repoRoot) {
|
|
1707
|
+
try {
|
|
1708
|
+
return gitCapture(repoRoot, ["symbolic-ref", "--short", "HEAD"]);
|
|
1709
|
+
} catch {
|
|
1710
|
+
return "HEAD";
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1699
1713
|
function branchExists(repoRoot, name) {
|
|
1700
1714
|
try {
|
|
1701
1715
|
execFileSync5("git", ["rev-parse", "--verify", "--quiet", `refs/heads/${name}`], {
|
|
@@ -1722,9 +1736,9 @@ function gitDirAbs(repoRoot) {
|
|
|
1722
1736
|
return isAbsolute(raw) ? raw : join5(repoRoot, raw);
|
|
1723
1737
|
}
|
|
1724
1738
|
function recoverFromCrash(repoRoot, statePath) {
|
|
1725
|
-
const currentBranch =
|
|
1739
|
+
const currentBranch = currentBranchName(repoRoot);
|
|
1726
1740
|
let state = null;
|
|
1727
|
-
if (
|
|
1741
|
+
if (existsSync5(statePath)) {
|
|
1728
1742
|
try {
|
|
1729
1743
|
state = JSON.parse(readFileSync2(statePath, "utf-8"));
|
|
1730
1744
|
} catch {
|
|
@@ -1796,14 +1810,14 @@ function cleanup(repoRoot, originalBranch, demoBranch, statePath) {
|
|
|
1796
1810
|
gitCapture(repoRoot, ["clean", "-fd"]);
|
|
1797
1811
|
gitCapture(repoRoot, ["checkout", originalBranch]);
|
|
1798
1812
|
gitCapture(repoRoot, ["branch", "-D", demoBranch]);
|
|
1799
|
-
if (
|
|
1813
|
+
if (existsSync5(statePath))
|
|
1800
1814
|
rmSync(statePath, { force: true });
|
|
1801
1815
|
}
|
|
1802
1816
|
async function runDemoBreak(repoRoot, args) {
|
|
1803
1817
|
const keep = args.includes("--keep");
|
|
1804
1818
|
const hookDir = resolveHookDir(repoRoot);
|
|
1805
1819
|
const hookPath = join5(repoRoot, hookDir, "pre-commit");
|
|
1806
|
-
if (!
|
|
1820
|
+
if (!existsSync5(hookPath)) {
|
|
1807
1821
|
console.error("Vinaya hooks are not installed in this repo. Run `vinaya init` first.");
|
|
1808
1822
|
return 1;
|
|
1809
1823
|
}
|
|
@@ -1814,7 +1828,7 @@ async function runDemoBreak(repoRoot, args) {
|
|
|
1814
1828
|
console.error("Working tree has uncommitted changes. Commit or stash them before running `vinaya demo break` — " + "the demo never touches a dirty tree.");
|
|
1815
1829
|
return 1;
|
|
1816
1830
|
}
|
|
1817
|
-
const originalBranch =
|
|
1831
|
+
const originalBranch = currentBranchName(repoRoot);
|
|
1818
1832
|
if (originalBranch === "HEAD") {
|
|
1819
1833
|
console.error("Cannot run `vinaya demo break` from a detached HEAD — checkout a branch first.");
|
|
1820
1834
|
return 1;
|
|
@@ -1861,7 +1875,7 @@ Attempting to commit…
|
|
|
1861
1875
|
process.stdout.write(`✓ Commit passed — the fix worked.
|
|
1862
1876
|
`);
|
|
1863
1877
|
if (keep) {
|
|
1864
|
-
if (
|
|
1878
|
+
if (existsSync5(statePath))
|
|
1865
1879
|
unlinkSync(statePath);
|
|
1866
1880
|
process.stdout.write(`
|
|
1867
1881
|
--keep: leaving \`${demoBranch}\` checked out for you to inspect. Clean up with:
|
|
@@ -1888,10 +1902,11 @@ async function demoBreakCommand(args) {
|
|
|
1888
1902
|
}
|
|
1889
1903
|
|
|
1890
1904
|
// src/commands/doctor.ts
|
|
1891
|
-
import { existsSync as
|
|
1892
|
-
import { join as
|
|
1905
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4, statSync } from "node:fs";
|
|
1906
|
+
import { join as join8 } from "node:path";
|
|
1893
1907
|
|
|
1894
1908
|
// src/lib/artifacts.ts
|
|
1909
|
+
import { join as join6 } from "node:path";
|
|
1895
1910
|
var CONFIG_PATH = "vinaya.config.json";
|
|
1896
1911
|
var DOCTRINE_POINTER_PATH = "VINAYA.md";
|
|
1897
1912
|
var CHECKS_WORKFLOW_PATH = ".github/workflows/vinaya-checks.yml";
|
|
@@ -2093,15 +2108,14 @@ function prePushBody() {
|
|
|
2093
2108
|
npx --no-install @attalabs/vinaya check --all || exit 1`;
|
|
2094
2109
|
}
|
|
2095
2110
|
function doctrinePointer() {
|
|
2111
|
+
const doctrineRoot = join6(packageRoot(import.meta.url), "aeg-root");
|
|
2096
2112
|
return `<!-- ${MANAGED_NOTE} -->
|
|
2097
2113
|
# Vinaya doctrine — read this first
|
|
2098
2114
|
|
|
2099
2115
|
This repo is governed by Vinaya. The full, canonical doctrine (roles,
|
|
2100
|
-
contracts, the state machine, the ring gates)
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
\`vinaya upgrade\` with no in-repo copy to drift, is planned but not yet
|
|
2104
|
-
shipped.
|
|
2116
|
+
contracts, the state machine, the ring gates) ships inside the installed
|
|
2117
|
+
\`@attalabs/vinaya\` npm package itself — no in-repo copy to drift, and
|
|
2118
|
+
\`vinaya upgrade\` regenerates this pointer if the install location changes.
|
|
2105
2119
|
|
|
2106
2120
|
An agent working in this repo follows the governed flow by reading two things:
|
|
2107
2121
|
|
|
@@ -2113,10 +2127,12 @@ An agent working in this repo follows the governed flow by reading two things:
|
|
|
2113
2127
|
Live task status is derived from the forge (Issues, labels, comments) via
|
|
2114
2128
|
\`vinaya check\` — it is never written into a file here.
|
|
2115
2129
|
|
|
2116
|
-
To
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2130
|
+
To read the doctrine text, it is bundled at this install's own resolved
|
|
2131
|
+
path:
|
|
2132
|
+
|
|
2133
|
+
${doctrineRoot}
|
|
2134
|
+
|
|
2135
|
+
\`vinaya doctor\` reports what is installed in this repo.
|
|
2120
2136
|
`;
|
|
2121
2137
|
}
|
|
2122
2138
|
function starterDocOwners() {
|
|
@@ -2256,8 +2272,8 @@ function buildInitProductOps(name) {
|
|
|
2256
2272
|
}
|
|
2257
2273
|
|
|
2258
2274
|
// src/lib/ops.ts
|
|
2259
|
-
import { chmodSync, existsSync as
|
|
2260
|
-
import { dirname as dirname3, join as
|
|
2275
|
+
import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
2276
|
+
import { dirname as dirname3, join as join7, resolve, sep } from "node:path";
|
|
2261
2277
|
var MARKER_NS = "vinaya:managed";
|
|
2262
2278
|
function markerLines(marker, comment) {
|
|
2263
2279
|
const [open, close] = comment === "hash" ? ["#", ""] : ["<!--", " -->"];
|
|
@@ -2273,7 +2289,7 @@ ${op.body}
|
|
|
2273
2289
|
${end}`;
|
|
2274
2290
|
}
|
|
2275
2291
|
function abs(repoRoot, relPath) {
|
|
2276
|
-
return
|
|
2292
|
+
return join7(repoRoot, relPath);
|
|
2277
2293
|
}
|
|
2278
2294
|
function containedAbs(repoRoot, relPath) {
|
|
2279
2295
|
const root = resolve(repoRoot);
|
|
@@ -2284,7 +2300,7 @@ function containedAbs(repoRoot, relPath) {
|
|
|
2284
2300
|
}
|
|
2285
2301
|
function fileContains(repoRoot, relPath, needle) {
|
|
2286
2302
|
const p = abs(repoRoot, relPath);
|
|
2287
|
-
if (!
|
|
2303
|
+
if (!existsSync6(p))
|
|
2288
2304
|
return false;
|
|
2289
2305
|
return readFileSync3(p, "utf-8").includes(needle);
|
|
2290
2306
|
}
|
|
@@ -2294,7 +2310,7 @@ function planInstall(ops, repoRoot, ownedFiles = new Set) {
|
|
|
2294
2310
|
for (const op of ops) {
|
|
2295
2311
|
switch (op.kind) {
|
|
2296
2312
|
case "create-file": {
|
|
2297
|
-
const exists =
|
|
2313
|
+
const exists = existsSync6(abs(repoRoot, op.path));
|
|
2298
2314
|
let action;
|
|
2299
2315
|
if (!exists)
|
|
2300
2316
|
action = "create";
|
|
@@ -2312,7 +2328,7 @@ function planInstall(ops, repoRoot, ownedFiles = new Set) {
|
|
|
2312
2328
|
let action;
|
|
2313
2329
|
if (fileContains(repoRoot, op.path, begin))
|
|
2314
2330
|
action = "skip-present";
|
|
2315
|
-
else if (
|
|
2331
|
+
else if (existsSync6(abs(repoRoot, op.path)))
|
|
2316
2332
|
action = "append";
|
|
2317
2333
|
else
|
|
2318
2334
|
action = "create-host";
|
|
@@ -2507,7 +2523,7 @@ function planEject(manifest, repoRoot) {
|
|
|
2507
2523
|
escapes.push(b.path);
|
|
2508
2524
|
continue;
|
|
2509
2525
|
}
|
|
2510
|
-
if (!
|
|
2526
|
+
if (!existsSync6(p)) {
|
|
2511
2527
|
actions.push({
|
|
2512
2528
|
kind: "strip-block",
|
|
2513
2529
|
path: b.path,
|
|
@@ -2536,7 +2552,7 @@ function planEject(manifest, repoRoot) {
|
|
|
2536
2552
|
escapes.push(f);
|
|
2537
2553
|
continue;
|
|
2538
2554
|
}
|
|
2539
|
-
actions.push({ kind: "delete-file", path: f, present:
|
|
2555
|
+
actions.push({ kind: "delete-file", path: f, present: existsSync6(p) });
|
|
2540
2556
|
}
|
|
2541
2557
|
for (const name of manifest.labels) {
|
|
2542
2558
|
actions.push({ kind: "report-label", name });
|
|
@@ -2593,7 +2609,7 @@ function applyEject(plan, repoRoot) {
|
|
|
2593
2609
|
|
|
2594
2610
|
// src/commands/doctor.ts
|
|
2595
2611
|
function readVersion() {
|
|
2596
|
-
const pkg = JSON.parse(readFileSync4(
|
|
2612
|
+
const pkg = JSON.parse(readFileSync4(join8(packageRoot(import.meta.url), "package.json"), "utf-8"));
|
|
2597
2613
|
return pkg.version;
|
|
2598
2614
|
}
|
|
2599
2615
|
function realDeps3() {
|
|
@@ -2612,8 +2628,8 @@ var info = (check, message) => ({ check, severity: "info", message });
|
|
|
2612
2628
|
var warn = (check, message) => ({ check, severity: "warn", message });
|
|
2613
2629
|
var error = (check, message) => ({ check, severity: "error", message });
|
|
2614
2630
|
function readConfig(repoRoot) {
|
|
2615
|
-
const p =
|
|
2616
|
-
if (!
|
|
2631
|
+
const p = join8(repoRoot, CONFIG_PATH);
|
|
2632
|
+
if (!existsSync7(p))
|
|
2617
2633
|
return { kind: "missing" };
|
|
2618
2634
|
let raw;
|
|
2619
2635
|
try {
|
|
@@ -2646,8 +2662,8 @@ function diagnoseInstall(repoRoot, ctx, manifest) {
|
|
|
2646
2662
|
for (const op of buildInitOps(ctx)) {
|
|
2647
2663
|
if (op.kind === "create-file") {
|
|
2648
2664
|
const check = labelForPath(op.path);
|
|
2649
|
-
const abs2 =
|
|
2650
|
-
const exists =
|
|
2665
|
+
const abs2 = join8(repoRoot, op.path);
|
|
2666
|
+
const exists = existsSync7(abs2);
|
|
2651
2667
|
const owned = ownedFiles.has(op.path);
|
|
2652
2668
|
if (!exists) {
|
|
2653
2669
|
findings.push(owned ? error(check, `${op.path} is recorded as vinaya-managed but missing on disk — run \`vinaya upgrade\`.`) : error(check, `${op.path} is not installed — run \`vinaya init\`.`));
|
|
@@ -2670,9 +2686,9 @@ function diagnoseInstall(repoRoot, ctx, manifest) {
|
|
|
2670
2686
|
}
|
|
2671
2687
|
} else if (op.kind === "managed-block") {
|
|
2672
2688
|
const check = "hooks";
|
|
2673
|
-
const abs2 =
|
|
2689
|
+
const abs2 = join8(repoRoot, op.path);
|
|
2674
2690
|
const owned = ownedBlocks.has(blockKey(op.path, op.marker));
|
|
2675
|
-
if (!
|
|
2691
|
+
if (!existsSync7(abs2)) {
|
|
2676
2692
|
findings.push(owned ? error(check, `${op.path} is missing — likely a fresh clone (raw git hooks aren't tracked by git). Run \`vinaya upgrade\` to restore it.`) : info(check, `${op.path} is not installed.`));
|
|
2677
2693
|
continue;
|
|
2678
2694
|
}
|
|
@@ -2701,8 +2717,8 @@ function diagnoseInstall(repoRoot, ctx, manifest) {
|
|
|
2701
2717
|
function diagnoseCustomChecks(repoRoot, config) {
|
|
2702
2718
|
const findings = [];
|
|
2703
2719
|
for (const [name, entry2] of Object.entries(config.checks ?? {})) {
|
|
2704
|
-
const scriptAbs =
|
|
2705
|
-
findings.push(
|
|
2720
|
+
const scriptAbs = join8(repoRoot, entry2.run);
|
|
2721
|
+
findings.push(existsSync7(scriptAbs) ? ok("checks", `custom check '${name}' → ${entry2.run}`) : error("checks", `custom check '${name}' points at a missing script: ${entry2.run}`));
|
|
2706
2722
|
}
|
|
2707
2723
|
return findings;
|
|
2708
2724
|
}
|
|
@@ -2790,8 +2806,8 @@ async function doctorCommand(args) {
|
|
|
2790
2806
|
}
|
|
2791
2807
|
|
|
2792
2808
|
// src/commands/eject.ts
|
|
2793
|
-
import { existsSync as
|
|
2794
|
-
import { join as
|
|
2809
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "node:fs";
|
|
2810
|
+
import { join as join9 } from "node:path";
|
|
2795
2811
|
|
|
2796
2812
|
// src/lib/prompt.ts
|
|
2797
2813
|
var stdinBuffer = "";
|
|
@@ -2872,8 +2888,8 @@ function parse(args) {
|
|
|
2872
2888
|
return { dryRun: args.includes("--dry-run"), yes: args.includes("--yes") };
|
|
2873
2889
|
}
|
|
2874
2890
|
function readManifest(repoRoot) {
|
|
2875
|
-
const p =
|
|
2876
|
-
if (!
|
|
2891
|
+
const p = join9(repoRoot, CONFIG_PATH);
|
|
2892
|
+
if (!existsSync8(p))
|
|
2877
2893
|
return { kind: "none" };
|
|
2878
2894
|
let raw;
|
|
2879
2895
|
try {
|
|
@@ -2960,8 +2976,8 @@ async function ejectCommand(args) {
|
|
|
2960
2976
|
}
|
|
2961
2977
|
|
|
2962
2978
|
// src/commands/init.ts
|
|
2963
|
-
import { existsSync as
|
|
2964
|
-
import { join as
|
|
2979
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2980
|
+
import { join as join10 } from "node:path";
|
|
2965
2981
|
function realDeps5() {
|
|
2966
2982
|
return {
|
|
2967
2983
|
detectRepo: detectGitRepo,
|
|
@@ -2981,8 +2997,8 @@ function flags(args) {
|
|
|
2981
2997
|
}
|
|
2982
2998
|
var PRODUCT_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
2983
2999
|
function readManifest2(repoRoot) {
|
|
2984
|
-
const p =
|
|
2985
|
-
if (!
|
|
3000
|
+
const p = join10(repoRoot, CONFIG_PATH);
|
|
3001
|
+
if (!existsSync9(p))
|
|
2986
3002
|
return null;
|
|
2987
3003
|
try {
|
|
2988
3004
|
return VinayaConfigSchema.parse(JSON.parse(readFileSync6(p, "utf-8"))).managed ?? null;
|
|
@@ -2991,7 +3007,7 @@ function readManifest2(repoRoot) {
|
|
|
2991
3007
|
}
|
|
2992
3008
|
}
|
|
2993
3009
|
function writeManifest(repoRoot, manifest) {
|
|
2994
|
-
const configAbs =
|
|
3010
|
+
const configAbs = join10(repoRoot, CONFIG_PATH);
|
|
2995
3011
|
const seed = JSON.parse(readFileSync6(configAbs, "utf-8"));
|
|
2996
3012
|
writeFileSync4(configAbs, `${JSON.stringify({ ...seed, managed: manifest }, null, 2)}
|
|
2997
3013
|
`, "utf-8");
|
|
@@ -3134,7 +3150,7 @@ import { execFileSync as execFileSync6 } from "node:child_process";
|
|
|
3134
3150
|
import { mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3135
3151
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
3136
3152
|
import { tmpdir } from "node:os";
|
|
3137
|
-
import { join as
|
|
3153
|
+
import { join as join11 } from "node:path";
|
|
3138
3154
|
class ForgeArgError extends Error {
|
|
3139
3155
|
}
|
|
3140
3156
|
function locateBody(args) {
|
|
@@ -3167,8 +3183,8 @@ function resolveShippableArgs(args, bodyResult) {
|
|
|
3167
3183
|
if (bodyResult?.source.kind !== "file") {
|
|
3168
3184
|
return { finalArgs: args, cleanup: () => {} };
|
|
3169
3185
|
}
|
|
3170
|
-
const dir = mkdtempSync(
|
|
3171
|
-
const tempPath =
|
|
3186
|
+
const dir = mkdtempSync(join11(tmpdir(), "vinaya-forge-body-"));
|
|
3187
|
+
const tempPath = join11(dir, "body.md");
|
|
3172
3188
|
writeFileSync5(tempPath, bodyResult.body, "utf8");
|
|
3173
3189
|
const finalArgs = [...args];
|
|
3174
3190
|
const { argIndex, inlineForm } = bodyResult.source;
|
|
@@ -3440,10 +3456,10 @@ function issueEditCommand(args) {
|
|
|
3440
3456
|
}
|
|
3441
3457
|
|
|
3442
3458
|
// src/commands/new-check.ts
|
|
3443
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
3444
|
-
import { join as
|
|
3445
|
-
var TEMPLATE_PATH =
|
|
3446
|
-
var CHECKS_DIR =
|
|
3459
|
+
import { chmodSync as chmodSync2, existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
|
|
3460
|
+
import { join as join12 } from "node:path";
|
|
3461
|
+
var TEMPLATE_PATH = join12(packageRoot(import.meta.url), "templates", "custom-check.template.ts");
|
|
3462
|
+
var CHECKS_DIR = join12("scripts", "vinaya-checks");
|
|
3447
3463
|
var VALID_NAME = /^[a-z0-9][a-z0-9-]*$/;
|
|
3448
3464
|
function newCheckCommand(args) {
|
|
3449
3465
|
const name = args[0];
|
|
@@ -3451,11 +3467,11 @@ function newCheckCommand(args) {
|
|
|
3451
3467
|
console.error("Usage: vinaya new check <name> (name: lowercase letters, digits, hyphens)");
|
|
3452
3468
|
process.exit(2);
|
|
3453
3469
|
}
|
|
3454
|
-
const scriptsDir =
|
|
3455
|
-
if (!
|
|
3470
|
+
const scriptsDir = join12(process.cwd(), CHECKS_DIR);
|
|
3471
|
+
if (!existsSync10(scriptsDir))
|
|
3456
3472
|
mkdirSync3(scriptsDir, { recursive: true });
|
|
3457
|
-
const targetPath =
|
|
3458
|
-
if (
|
|
3473
|
+
const targetPath = join12(scriptsDir, `${name}.ts`);
|
|
3474
|
+
if (existsSync10(targetPath)) {
|
|
3459
3475
|
console.error(`Error: ${targetPath} already exists.`);
|
|
3460
3476
|
process.exit(1);
|
|
3461
3477
|
}
|
|
@@ -3463,7 +3479,7 @@ function newCheckCommand(args) {
|
|
|
3463
3479
|
const contents = template.split("{{CHECK_NAME}}").join(name);
|
|
3464
3480
|
writeFileSync6(targetPath, contents, "utf-8");
|
|
3465
3481
|
chmodSync2(targetPath, 493);
|
|
3466
|
-
const relPath =
|
|
3482
|
+
const relPath = join12(CHECKS_DIR, `${name}.ts`);
|
|
3467
3483
|
const registration = JSON.stringify({ checks: { [name]: { run: `./${relPath}`, scope: "diff" } } }, null, 2);
|
|
3468
3484
|
process.stdout.write(`Created ${relPath}
|
|
3469
3485
|
|
|
@@ -3623,14 +3639,14 @@ function prEditCommand(args) {
|
|
|
3623
3639
|
|
|
3624
3640
|
// src/commands/studio.ts
|
|
3625
3641
|
import { spawn as spawn2 } from "node:child_process";
|
|
3626
|
-
import { existsSync as
|
|
3627
|
-
import { dirname as dirname4, join as
|
|
3642
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
|
|
3643
|
+
import { dirname as dirname4, join as join13 } from "node:path";
|
|
3628
3644
|
function resolveStudioTarget(cwd) {
|
|
3629
3645
|
let dir = cwd;
|
|
3630
3646
|
for (;; ) {
|
|
3631
|
-
const webDir =
|
|
3632
|
-
const pkgPath =
|
|
3633
|
-
if (
|
|
3647
|
+
const webDir = join13(dir, "apps", "vinaya", "web");
|
|
3648
|
+
const pkgPath = join13(webDir, "package.json");
|
|
3649
|
+
if (existsSync11(pkgPath)) {
|
|
3634
3650
|
try {
|
|
3635
3651
|
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
3636
3652
|
if (pkg.name === "@atta/vinaya-web") {
|
|
@@ -3665,8 +3681,8 @@ async function runStudio(cwd, args) {
|
|
|
3665
3681
|
}
|
|
3666
3682
|
|
|
3667
3683
|
// src/commands/upgrade.ts
|
|
3668
|
-
import { existsSync as
|
|
3669
|
-
import { join as
|
|
3684
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
3685
|
+
import { join as join14 } from "node:path";
|
|
3670
3686
|
function realDeps6() {
|
|
3671
3687
|
return {
|
|
3672
3688
|
detectRepo: detectGitRepo,
|
|
@@ -3682,8 +3698,8 @@ function flags2(args) {
|
|
|
3682
3698
|
return { dryRun: args.includes("--dry-run"), yes: args.includes("--yes") };
|
|
3683
3699
|
}
|
|
3684
3700
|
function readManifest3(repoRoot) {
|
|
3685
|
-
const p =
|
|
3686
|
-
if (!
|
|
3701
|
+
const p = join14(repoRoot, CONFIG_PATH);
|
|
3702
|
+
if (!existsSync12(p))
|
|
3687
3703
|
return { kind: "missing" };
|
|
3688
3704
|
let raw;
|
|
3689
3705
|
try {
|
|
@@ -3703,7 +3719,7 @@ function readManifest3(repoRoot) {
|
|
|
3703
3719
|
return { kind: "ok", manifest: parsed.data.managed };
|
|
3704
3720
|
}
|
|
3705
3721
|
function writeManifestVersion(repoRoot, manifest) {
|
|
3706
|
-
const configAbs =
|
|
3722
|
+
const configAbs = join14(repoRoot, CONFIG_PATH);
|
|
3707
3723
|
const seed = JSON.parse(readFileSync10(configAbs, "utf-8"));
|
|
3708
3724
|
const updated = { ...manifest, version: MANAGED_MANIFEST_VERSION };
|
|
3709
3725
|
writeFileSync7(configAbs, `${JSON.stringify({ ...seed, managed: updated }, null, 2)}
|
|
@@ -3717,8 +3733,8 @@ function planUpgrade(ops, repoRoot, manifest) {
|
|
|
3717
3733
|
const ownedBlocks = new Set(manifest.blocks.map((b) => blockKey(b.path, b.marker)));
|
|
3718
3734
|
for (const op of ops) {
|
|
3719
3735
|
if (op.kind === "create-file") {
|
|
3720
|
-
const abs2 =
|
|
3721
|
-
const exists =
|
|
3736
|
+
const abs2 = join14(repoRoot, op.path);
|
|
3737
|
+
const exists = existsSync12(abs2);
|
|
3722
3738
|
const owned = ownedFiles.has(op.path);
|
|
3723
3739
|
let action;
|
|
3724
3740
|
if (op.path === CONFIG_PATH) {
|
|
@@ -3736,12 +3752,12 @@ function planUpgrade(ops, repoRoot, manifest) {
|
|
|
3736
3752
|
}
|
|
3737
3753
|
entries.push({ kind: "create-file", op, action });
|
|
3738
3754
|
} else if (op.kind === "managed-block") {
|
|
3739
|
-
const abs2 =
|
|
3755
|
+
const abs2 = join14(repoRoot, op.path);
|
|
3740
3756
|
const owned = ownedBlocks.has(blockKey(op.path, op.marker));
|
|
3741
3757
|
let action;
|
|
3742
3758
|
if (!owned) {
|
|
3743
3759
|
action = "not-installed";
|
|
3744
|
-
} else if (!
|
|
3760
|
+
} else if (!existsSync12(abs2)) {
|
|
3745
3761
|
action = "recreate-host";
|
|
3746
3762
|
hasChanges = true;
|
|
3747
3763
|
} else {
|
|
@@ -3821,7 +3837,7 @@ function renderUpgradeDiff(plan) {
|
|
|
3821
3837
|
`);
|
|
3822
3838
|
}
|
|
3823
3839
|
function regenerateBlock(repoRoot, op) {
|
|
3824
|
-
const abs2 =
|
|
3840
|
+
const abs2 = join14(repoRoot, op.path);
|
|
3825
3841
|
const content = readFileSync10(abs2, "utf-8");
|
|
3826
3842
|
const stripped = stripBlockFromContent(content, op.marker, op.comment);
|
|
3827
3843
|
if (stripped !== null) {
|
|
@@ -3835,7 +3851,7 @@ function applyUpgrade(plan, repoRoot) {
|
|
|
3835
3851
|
for (const e of plan.entries) {
|
|
3836
3852
|
if (e.kind === "create-file") {
|
|
3837
3853
|
if (e.action === "regenerate" || e.action === "recreate") {
|
|
3838
|
-
writeFileWithDirs(
|
|
3854
|
+
writeFileWithDirs(join14(repoRoot, e.op.path), e.op.content, e.op.mode);
|
|
3839
3855
|
}
|
|
3840
3856
|
} else {
|
|
3841
3857
|
if (e.action === "recreate-host")
|
|
@@ -4234,9 +4250,9 @@ function printHelp() {
|
|
|
4234
4250
|
}
|
|
4235
4251
|
|
|
4236
4252
|
// src/index.ts
|
|
4237
|
-
var PACKAGE_ROOT =
|
|
4253
|
+
var PACKAGE_ROOT = join15(dirname5(fileURLToPath2(import.meta.url)), "..");
|
|
4238
4254
|
function readVersion2() {
|
|
4239
|
-
const pkg = JSON.parse(readFileSync11(
|
|
4255
|
+
const pkg = JSON.parse(readFileSync11(join15(PACKAGE_ROOT, "package.json"), "utf-8"));
|
|
4240
4256
|
return pkg.version;
|
|
4241
4257
|
}
|
|
4242
4258
|
var [, , command, ...args] = process.argv;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@attalabs/vinaya",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Vinaya — Agentic Engineering Harness. Deterministic checks every AI coding agent must satisfy before merge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
13
|
"templates",
|
|
14
|
+
"aeg-root",
|
|
14
15
|
"README.md"
|
|
15
16
|
],
|
|
16
17
|
"publishConfig": {
|
|
@@ -36,7 +37,8 @@
|
|
|
36
37
|
},
|
|
37
38
|
"scripts": {
|
|
38
39
|
"build": "bun scripts/build.ts",
|
|
39
|
-
"
|
|
40
|
+
"bundle-doctrine": "bun scripts/bundle-doctrine.ts",
|
|
41
|
+
"prepack": "bun scripts/build.ts && bun scripts/bundle-doctrine.ts",
|
|
40
42
|
"test": "bun test",
|
|
41
43
|
"typecheck": "tsc --noEmit",
|
|
42
44
|
"lint": "biome check src tests scripts",
|