@graphrefly/stack 0.1.0 → 0.1.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.
Files changed (3) hide show
  1. package/README.md +24 -12
  2. package/dist/grfs.js +40 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -21,14 +21,13 @@ GraphReFly repository you want to review:
21
21
  ```bash
22
22
  pnpm add -D @graphrefly/stack
23
23
  pnpm exec grfs init --graph-module src/application-graph.ts
24
- git add .graphrefly-stack.json graphrefly-stack.blueprint.mjs
25
- git commit -m "configure GraphReFly Stack"
26
24
 
27
25
  BASE=<the commit immediately before your stack>
28
26
  pnpm exec grfs review --repo . --base "$BASE" --head HEAD
29
27
  ```
30
28
 
31
- Open <http://127.0.0.1:4173>, then:
29
+ The review command stays running and prints its loopback URL; it does not launch a browser
30
+ automatically. Open the printed URL (normally <http://127.0.0.1:4173>), then:
32
31
 
33
32
  1. Select each commit discovered from the real linear Git range.
34
33
  2. See the Blueprint and parent delta produced by the repository's installed GraphReFly 0.3.x
@@ -38,15 +37,28 @@ Open <http://127.0.0.1:4173>, then:
38
37
  4. Expand repository evidence or commit lineage only when needed. No session, delivery, fixture, or
39
38
  fake semantic-gate state appears in the generic review.
40
39
 
41
- `grfs init` does not guess how an arbitrary application assembles its graph. You point it at the
42
- module and export that already build the repository's root Graph. It generates the strict
43
- `.graphrefly-stack.json` config and a small deterministic `graphrefly-stack.blueprint.mjs` adapter;
44
- both are ordinary source files that should be committed. Use `--graph-export <name>` when the module
45
- does not export `createApplicationGraph`.
46
-
47
- The CLI executes that generated adapter at the base and every commit in permission-limited detached
48
- worktrees. Each invocation calls the real GraphReFly `graph.blueprint()` API; Stack then parses,
49
- verifies, renders, and diffs only with the installed runtime's public GraphReFly APIs.
40
+ `--graph-module` means the repository's root Graph construction module, not the only Graph module
41
+ allowed in the repository. That root module may import, compose, and mount any number of Graphs and
42
+ subgraphs. The first version reviews one configured root Blueprint target at a time; selecting among
43
+ multiple independent application roots in a monorepo is roadmap work.
44
+
45
+ `grfs init` does not guess how an arbitrary application assembles that root Graph. You point it at
46
+ the module and export that already construct it once during onboarding. The command generates the
47
+ strict `.graphrefly-stack.json` config and a small deterministic
48
+ `graphrefly-stack.blueprint.mjs` adapter; both are ordinary source files that should be committed.
49
+ Use `--graph-export <name>` when the module does not export `createApplicationGraph`. JSON is the v1
50
+ configuration format; optional YAML and TOML authoring formats are deferred roadmap work and must
51
+ normalize to the same strict configuration contract before execution.
52
+
53
+ Initialization may happen after the stack already exists. The review snapshots the configured
54
+ adapter and supplies those same bounded bytes only inside isolated detached revisions where that
55
+ entrypoint did not exist yet; it does not rewrite repository history. The referenced root Graph
56
+ module must exist at every reviewed revision. Commit the config and adapter after onboarding so
57
+ future reviews have a Git-owned configuration witness.
58
+
59
+ The CLI executes the adapter at the base and every commit in permission-limited detached worktrees.
60
+ Each invocation calls the real GraphReFly `graph.blueprint()` API; Stack then parses, verifies,
61
+ renders, and diffs only with the installed runtime's public GraphReFly APIs.
50
62
 
51
63
  ## Generic repository contract
52
64
 
package/dist/grfs.js CHANGED
@@ -8563,6 +8563,7 @@ var require_semver2 = __commonJS({
8563
8563
  });
8564
8564
 
8565
8565
  // packages/cli/dist/cli.js
8566
+ import { realpathSync } from "node:fs";
8566
8567
  import { readFile as readFile7 } from "node:fs/promises";
8567
8568
  import { resolve as resolve10 } from "node:path";
8568
8569
  import { pathToFileURL as pathToFileURL3 } from "node:url";
@@ -10149,7 +10150,7 @@ process.stdout.write(JSON.stringify(blueprint));
10149
10150
  // packages/cli/dist/repository-review.js
10150
10151
  import { spawnSync as spawnSync5 } from "node:child_process";
10151
10152
  import { createHash as createHash6 } from "node:crypto";
10152
- import { access as access2, mkdir as mkdir5, readFile as readFile6, realpath as realpath3, rm as rm4, symlink } from "node:fs/promises";
10153
+ import { access as access2, mkdir as mkdir5, readFile as readFile6, realpath as realpath3, rm as rm4, symlink, writeFile as writeFile5 } from "node:fs/promises";
10153
10154
  import { createRequire as createRequire2 } from "node:module";
10154
10155
  import { basename as basename2, dirname as dirname5, parse, resolve as resolve8, sep as sep4 } from "node:path";
10155
10156
  import { pathToFileURL as pathToFileURL2 } from "node:url";
@@ -10283,6 +10284,7 @@ var reviewSchemaPath = runtimeAssetPath("contracts/repository/v1/review.schema.j
10283
10284
  var configName2 = ".graphrefly-stack.json";
10284
10285
  var lockCandidates = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock"];
10285
10286
  var maxReviewCommits = 64;
10287
+ var maxEntrypointBytes = 64 * 1024;
10286
10288
  var RepositoryReviewError = class extends Error {
10287
10289
  code;
10288
10290
  constructor(code, message) {
@@ -10365,6 +10367,22 @@ function ensureInside(root, candidate) {
10365
10367
  throw new RepositoryReviewError("ENTRYPOINT_ESCAPE", "Blueprint entrypoint escapes the worktree");
10366
10368
  }
10367
10369
  }
10370
+ async function readConfiguredEntrypoint(repository, entrypointPath) {
10371
+ const entrypoint = resolve8(repository, entrypointPath);
10372
+ ensureInside(repository, entrypoint);
10373
+ let canonicalEntrypoint;
10374
+ try {
10375
+ canonicalEntrypoint = await realpath3(entrypoint);
10376
+ } catch {
10377
+ throw new RepositoryReviewError("ENTRYPOINT_MISSING", "Configured Blueprint entrypoint is missing");
10378
+ }
10379
+ ensureInside(repository, canonicalEntrypoint);
10380
+ const source = await readFile6(canonicalEntrypoint);
10381
+ if (source.byteLength > maxEntrypointBytes) {
10382
+ throw new RepositoryReviewError("ENTRYPOINT_TOO_LARGE", `Configured Blueprint entrypoint exceeds ${maxEntrypointBytes} bytes`);
10383
+ }
10384
+ return source;
10385
+ }
10368
10386
  function containsAbsolutePath(value) {
10369
10387
  if (typeof value === "string")
10370
10388
  return value.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(value);
@@ -10416,7 +10434,7 @@ async function resolveTargetRuntime(repository) {
10416
10434
  diffGraphBlueprints: graphModule.diffGraphBlueprints
10417
10435
  };
10418
10436
  }
10419
- async function executeBlueprint(repository, revision, entrypointPath, runtime) {
10437
+ async function executeBlueprint(repository, revision, entrypointPath, entrypointSource, runtime) {
10420
10438
  const worktreeRoot = resolve8(dirname5(repository), `.graphrefly-stack-review-${basename2(repository)}-${process.pid}`);
10421
10439
  const worktree = resolve8(worktreeRoot, revision.slice(0, 16));
10422
10440
  await mkdir5(worktreeRoot, { recursive: true });
@@ -10429,8 +10447,19 @@ async function executeBlueprint(repository, revision, entrypointPath, runtime) {
10429
10447
  try {
10430
10448
  await access2(entrypoint);
10431
10449
  } catch {
10432
- throw new RepositoryReviewError("ENTRYPOINT_MISSING", `Blueprint entrypoint is missing at ${revision.slice(0, 12)}`);
10450
+ let canonicalParent;
10451
+ try {
10452
+ canonicalParent = await realpath3(dirname5(entrypoint));
10453
+ } catch {
10454
+ throw new RepositoryReviewError("ENTRYPOINT_MISSING", `Blueprint entrypoint parent is missing at ${revision.slice(0, 12)}`);
10455
+ }
10456
+ ensureInside(canonicalWorktree, canonicalParent);
10457
+ await writeFile5(resolve8(canonicalParent, basename2(entrypoint)), entrypointSource, {
10458
+ flag: "wx"
10459
+ });
10433
10460
  }
10461
+ const canonicalEntrypoint = await realpath3(entrypoint);
10462
+ ensureInside(canonicalWorktree, canonicalEntrypoint);
10434
10463
  const worktreeNodeModules = resolve8(canonicalWorktree, "node_modules");
10435
10464
  await rm4(worktreeNodeModules, { recursive: true, force: true });
10436
10465
  await symlink(runtime.nodeModulesRoot, worktreeNodeModules, "dir");
@@ -10439,7 +10468,7 @@ async function executeBlueprint(repository, revision, entrypointPath, runtime) {
10439
10468
  `--allow-fs-read=${canonicalWorktree}`,
10440
10469
  `--allow-fs-read=${runtime.nodeModulesRoot}`,
10441
10470
  "--disable-warning=ExperimentalWarning",
10442
- entrypoint
10471
+ canonicalEntrypoint
10443
10472
  ], {
10444
10473
  cwd: canonicalWorktree,
10445
10474
  encoding: "utf8",
@@ -10552,6 +10581,7 @@ async function createRepositoryReview(options) {
10552
10581
  throw new RepositoryReviewError("REPOSITORY_INVALID", "Repository must be a local Git worktree");
10553
10582
  }
10554
10583
  const config = await readRepositoryConfig(repository);
10584
+ const entrypointSource = await readConfiguredEntrypoint(repository, config.blueprint.entrypoint);
10555
10585
  const git2 = new SystemGitAdapter();
10556
10586
  let baseOid;
10557
10587
  let headOid;
@@ -10595,7 +10625,7 @@ async function createRepositoryReview(options) {
10595
10625
  await validateDependencyContinuity(repository, allRevisions, runtime.version);
10596
10626
  const evidence = [];
10597
10627
  for (const revision of allRevisions) {
10598
- const blueprint = await executeBlueprint(repository, revision, config.blueprint.entrypoint, runtime);
10628
+ const blueprint = await executeBlueprint(repository, revision, config.blueprint.entrypoint, entrypointSource, runtime);
10599
10629
  evidence.push({
10600
10630
  oid: revision,
10601
10631
  subject: gitText(repository, ["show", "-s", "--format=%s", revision]),
@@ -11079,7 +11109,11 @@ ${help}`);
11079
11109
  process.once("SIGTERM", close);
11080
11110
  return 0;
11081
11111
  }
11082
- var entry = process.argv[1] ? pathToFileURL3(process.argv[1]).href : "";
11112
+ var entry = "";
11113
+ try {
11114
+ entry = process.argv[1] ? pathToFileURL3(realpathSync(process.argv[1])).href : "";
11115
+ } catch {
11116
+ }
11083
11117
  if (import.meta.url === entry) {
11084
11118
  runCli().then((code) => {
11085
11119
  process.exitCode = code;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphrefly/stack",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "description": "Semantic stacked diffs with commit-indexed GraphBlueprint validity gates.",
6
6
  "license": "MIT",