@quolu/lattice 0.21.0 → 0.21.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quolu/lattice",
3
- "version": "0.21.0",
3
+ "version": "0.21.2",
4
4
  "description": "Lattice — phase-aware TODO graph compiler and conflict-aware orchestration runtime",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -130,11 +130,35 @@ async function buildPatch(worktreePath, changedPaths) {
130
130
  return Buffer.concat(parts);
131
131
  }
132
132
 
133
+ /**
134
+ * mountのために作った親dirが1エントリで報告されたら、除外せず展開して子を同じ規律で見る。
135
+ *
136
+ * 親ごと除外すると、その中に現れた別の変更まで隠れる。runnerが張ったmountだけを外す規律を、
137
+ * ディレクトリ単位の報告でも保つ。
138
+ */
139
+ async function expandMountAncestors(worktreePath, paths, mountedEntries) {
140
+ const isAncestor = (entry) => mountedEntries
141
+ .some((mount) => mount.startsWith(`${entry}/`));
142
+ const expanded = [];
143
+ const pending = [...paths];
144
+ while (pending.length > 0) {
145
+ const current = pending.pop();
146
+ const normalized = current.replace(/\/$/u, '');
147
+ if (!current.endsWith('/') || !isAncestor(normalized)) { expanded.push(current); continue; }
148
+ const children = await readdir(path.join(worktreePath, normalized), { withFileTypes: true });
149
+ for (const child of children) {
150
+ pending.push(`${normalized}/${child.name}${child.isDirectory() ? '/' : ''}`);
151
+ }
152
+ }
153
+ return [...new Set(expanded)].sort();
154
+ }
155
+
133
156
  async function captureSnapshot(worktreePath, baseSha, allowedPaths, mountedEntries = []) {
134
157
  const mounted = new Set(mountedEntries);
135
- const changedPaths = statusPaths((await run('git', [
158
+ const reported = statusPaths((await run('git', [
136
159
  'status', '--porcelain=v1', '-z', '--untracked-files=all', '--ignored=matching',
137
- ], { cwd: worktreePath })).stdout)
160
+ ], { cwd: worktreePath })).stdout);
161
+ const changedPaths = (await expandMountAncestors(worktreePath, reported, [...mounted]))
138
162
  // runnerが張ったmountだけを外す。それ以外は無視しない——gitignore対象であっても、
139
163
  // allowed pathの外に現れたものは変更である。
140
164
  .filter((changedPath) => {
package/src/todo-cli.mjs CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  lstat, mkdir, open, readFile, realpath, rename, rm, writeFile,
5
5
  } from 'node:fs/promises';
6
6
  import path from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
7
8
  import { parseTree } from 'jsonc-parser';
8
9
 
9
10
  import {
@@ -988,7 +989,9 @@ async function seamProposalApply({ repoRoot, planKey, pathNames = {}, land = fal
988
989
  pathNames,
989
990
  sourceProposal: artifact,
990
991
  witnessSet,
991
- latticeBin: path.join(repoRoot, 'bin', 'lattice.mjs'),
992
+ // 配布物内の自分自身を指す。repoRoot配下を指すと、Lattice自身のrepositoryでしか動かない
993
+ // ——消費側のprojectに`bin/lattice.mjs`は存在しない。
994
+ latticeBin: fileURLToPath(new URL('../bin/lattice.mjs', import.meta.url)),
992
995
  sharedPathFor: (sourcePath) => sourcePath.replace(/(\.[^./]+)$/u, '.seam-shared$1'),
993
996
  executors: witnessSet.capacity.executors,
994
997
  compileIndependence: {