@miadi/inquiry-weave 0.1.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/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/artefact.d.ts +33 -0
- package/dist/artefact.d.ts.map +1 -0
- package/dist/artefact.js +59 -0
- package/dist/artefact.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +21 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +339 -0
- package/dist/cli.js.map +1 -0
- package/dist/env.d.ts +22 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +26 -0
- package/dist/env.js.map +1 -0
- package/dist/episode.d.ts +38 -0
- package/dist/episode.d.ts.map +1 -0
- package/dist/episode.js +109 -0
- package/dist/episode.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/issue.d.ts +27 -0
- package/dist/issue.d.ts.map +1 -0
- package/dist/issue.js +55 -0
- package/dist/issue.js.map +1 -0
- package/dist/legacy-hch.d.ts +28 -0
- package/dist/legacy-hch.d.ts.map +1 -0
- package/dist/legacy-hch.js +120 -0
- package/dist/legacy-hch.js.map +1 -0
- package/dist/relate.d.ts +31 -0
- package/dist/relate.d.ts.map +1 -0
- package/dist/relate.js +79 -0
- package/dist/relate.js.map +1 -0
- package/dist/status.d.ts +47 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +142 -0
- package/dist/status.js.map +1 -0
- package/dist/sync.d.ts +28 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +80 -0
- package/dist/sync.js.map +1 -0
- package/dist/tree.d.ts +19 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +44 -0
- package/dist/tree.js.map +1 -0
- package/dist/weave.d.ts +83 -0
- package/dist/weave.d.ts.map +1 -0
- package/dist/weave.js +101 -0
- package/dist/weave.js.map +1 -0
- package/package.json +51 -0
- package/rispecs/medicine-wheel-registration.spec.md +72 -0
package/dist/sync.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-way artefact → episode mirror sync.
|
|
3
|
+
*
|
|
4
|
+
* The inquiry root (IAIP tree) is the system-of-record: the episode copy is a
|
|
5
|
+
* snapshot, deletions propagate, and local edits to the copy are flagged as
|
|
6
|
+
* divergence (a warning that sync will overwrite them).
|
|
7
|
+
*/
|
|
8
|
+
import { cp, rename, rm } from "node:fs/promises";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { basename, join } from "node:path";
|
|
11
|
+
import { hashTree } from "./tree.js";
|
|
12
|
+
import { readEpisodeWeave, writeEpisodeWeave, WeaveError, } from "./weave.js";
|
|
13
|
+
function requireEntry(weave, artefactName) {
|
|
14
|
+
const entry = weave?.inquiries.find((inquiry) => inquiry.artefact === artefactName);
|
|
15
|
+
if (!weave || !entry) {
|
|
16
|
+
throw new WeaveError(`artefact ${artefactName} is not related to this episode yet — run 'inquiry-weave relate' (or 'promote') first`);
|
|
17
|
+
}
|
|
18
|
+
return entry;
|
|
19
|
+
}
|
|
20
|
+
export async function syncArtefact(artefactDir, episodeDir, options = {}) {
|
|
21
|
+
const artefactName = basename(artefactDir);
|
|
22
|
+
const weave = await readEpisodeWeave(episodeDir);
|
|
23
|
+
const entry = requireEntry(weave, artefactName);
|
|
24
|
+
const copyDir = join(episodeDir, "inquiry", artefactName);
|
|
25
|
+
const manifest = await hashTree(artefactDir);
|
|
26
|
+
if (entry.last_sync?.tree_sha256 === manifest.tree_sha256 && existsSync(copyDir)) {
|
|
27
|
+
return { status: "up-to-date", artefact: artefactName, episodeDir, copyDir, manifest };
|
|
28
|
+
}
|
|
29
|
+
if (options.dryRun) {
|
|
30
|
+
return { status: "dry-run", artefact: artefactName, episodeDir, copyDir, manifest };
|
|
31
|
+
}
|
|
32
|
+
const tmpDir = join(episodeDir, "inquiry", `.${artefactName}.tmp-${process.pid}`);
|
|
33
|
+
try {
|
|
34
|
+
await cp(artefactDir, tmpDir, { recursive: true });
|
|
35
|
+
if (existsSync(copyDir))
|
|
36
|
+
await rm(copyDir, { recursive: true });
|
|
37
|
+
await rename(tmpDir, copyDir);
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
if (existsSync(tmpDir))
|
|
41
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
42
|
+
}
|
|
43
|
+
entry.last_sync = {
|
|
44
|
+
at: (options.now?.() ?? new Date()).toISOString(),
|
|
45
|
+
tree_sha256: manifest.tree_sha256,
|
|
46
|
+
file_count: manifest.file_count,
|
|
47
|
+
bytes_total: manifest.bytes_total,
|
|
48
|
+
};
|
|
49
|
+
await writeEpisodeWeave(episodeDir, weave);
|
|
50
|
+
return { status: "synced", artefact: artefactName, episodeDir, copyDir, manifest };
|
|
51
|
+
}
|
|
52
|
+
export async function classifyFreshness(artefactDir, episodeDir, entry) {
|
|
53
|
+
const diagnostics = [];
|
|
54
|
+
if (!entry.last_sync)
|
|
55
|
+
return { state: "never-synced", diagnostics };
|
|
56
|
+
const copyDir = join(episodeDir, "inquiry", entry.artefact);
|
|
57
|
+
if (!existsSync(copyDir)) {
|
|
58
|
+
diagnostics.push("episode copy is missing; run sync to restore it");
|
|
59
|
+
return { state: "stale", diagnostics };
|
|
60
|
+
}
|
|
61
|
+
const sourceHash = existsSync(artefactDir)
|
|
62
|
+
? (await hashTree(artefactDir)).tree_sha256
|
|
63
|
+
: undefined;
|
|
64
|
+
const copyHash = (await hashTree(copyDir)).tree_sha256;
|
|
65
|
+
if (copyHash !== entry.last_sync.tree_sha256) {
|
|
66
|
+
diagnostics.push("episode copy was edited after the last sync; sync will overwrite it");
|
|
67
|
+
if (sourceHash === entry.last_sync.tree_sha256) {
|
|
68
|
+
return { state: "episode-copy-diverged", diagnostics };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (sourceHash === undefined) {
|
|
72
|
+
diagnostics.push("source artefact directory is missing under the inquiry root");
|
|
73
|
+
return { state: "stale", diagnostics };
|
|
74
|
+
}
|
|
75
|
+
if (sourceHash !== entry.last_sync.tree_sha256) {
|
|
76
|
+
return { state: "stale", diagnostics };
|
|
77
|
+
}
|
|
78
|
+
return { state: "in-sync", diagnostics };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=sync.js.map
|
package/dist/sync.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}
|
package/dist/tree.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic tree hashing for sync freshness.
|
|
3
|
+
*
|
|
4
|
+
* tree_sha256 = sha256 over the sorted `relpath:filehash:size` manifest —
|
|
5
|
+
* robust to mtime drift across filesystems, unlike timestamp comparison.
|
|
6
|
+
*/
|
|
7
|
+
export interface TreeFileEntry {
|
|
8
|
+
path: string;
|
|
9
|
+
sha256: string;
|
|
10
|
+
size: number;
|
|
11
|
+
}
|
|
12
|
+
export interface TreeManifest {
|
|
13
|
+
tree_sha256: string;
|
|
14
|
+
file_count: number;
|
|
15
|
+
bytes_total: number;
|
|
16
|
+
files: TreeFileEntry[];
|
|
17
|
+
}
|
|
18
|
+
export declare function hashTree(dir: string): Promise<TreeManifest>;
|
|
19
|
+
//# sourceMappingURL=tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,aAAa,EAAE,CAAA;CACvB;AAwBD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAWjE"}
|
package/dist/tree.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic tree hashing for sync freshness.
|
|
3
|
+
*
|
|
4
|
+
* tree_sha256 = sha256 over the sorted `relpath:filehash:size` manifest —
|
|
5
|
+
* robust to mtime drift across filesystems, unlike timestamp comparison.
|
|
6
|
+
*/
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { readFile, readdir, readlink } from "node:fs/promises";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
function sha256(data) {
|
|
11
|
+
return createHash("sha256").update(data).digest("hex");
|
|
12
|
+
}
|
|
13
|
+
async function walk(dir, prefix, files) {
|
|
14
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
const relPath = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
|
|
17
|
+
const absPath = join(dir, entry.name);
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
await walk(absPath, relPath, files);
|
|
20
|
+
}
|
|
21
|
+
else if (entry.isSymbolicLink()) {
|
|
22
|
+
const target = await readlink(absPath);
|
|
23
|
+
const content = `symlink:${target}`;
|
|
24
|
+
files.push({ path: relPath, sha256: sha256(content), size: content.length });
|
|
25
|
+
}
|
|
26
|
+
else if (entry.isFile()) {
|
|
27
|
+
const content = await readFile(absPath);
|
|
28
|
+
files.push({ path: relPath, sha256: sha256(content), size: content.length });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export async function hashTree(dir) {
|
|
33
|
+
const files = [];
|
|
34
|
+
await walk(dir, "", files);
|
|
35
|
+
files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
36
|
+
const manifest = files.map((file) => `${file.path}:${file.sha256}:${file.size}`).join("\n");
|
|
37
|
+
return {
|
|
38
|
+
tree_sha256: sha256(manifest),
|
|
39
|
+
file_count: files.length,
|
|
40
|
+
bytes_total: files.reduce((total, file) => total + file.size, 0),
|
|
41
|
+
files,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=tree.js.map
|
package/dist/tree.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"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"}
|
package/dist/weave.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The weave contract — the package's own explicit inquiry-metadata files.
|
|
3
|
+
*
|
|
4
|
+
* Episode side: <episode>/inquiry/weave.yaml (sync state lives here only)
|
|
5
|
+
* Artefact side: <artefact>/.weave.yaml (durable relations only, so a
|
|
6
|
+
* sync can copy it verbatim without a self-invalidating hash loop)
|
|
7
|
+
*
|
|
8
|
+
* `.hch/` is best-effort legacy input (see legacy-hch.ts), never written here.
|
|
9
|
+
*/
|
|
10
|
+
export declare const WEAVE_VERSION = 1;
|
|
11
|
+
export interface LastSync {
|
|
12
|
+
at: string;
|
|
13
|
+
tree_sha256: string;
|
|
14
|
+
file_count: number;
|
|
15
|
+
bytes_total: number;
|
|
16
|
+
}
|
|
17
|
+
export interface InquiryEntry {
|
|
18
|
+
artefact: string;
|
|
19
|
+
issue?: string;
|
|
20
|
+
issue_url?: string;
|
|
21
|
+
related_at: string;
|
|
22
|
+
last_sync?: LastSync;
|
|
23
|
+
}
|
|
24
|
+
export interface EpisodeIdentityBlock {
|
|
25
|
+
number?: number;
|
|
26
|
+
slug?: string;
|
|
27
|
+
path: string;
|
|
28
|
+
}
|
|
29
|
+
export interface EpisodeWeave {
|
|
30
|
+
weave: number;
|
|
31
|
+
episode: EpisodeIdentityBlock;
|
|
32
|
+
inquiries: InquiryEntry[];
|
|
33
|
+
}
|
|
34
|
+
export interface ArtefactEpisodeLink {
|
|
35
|
+
path: string;
|
|
36
|
+
number?: number;
|
|
37
|
+
related_at: string;
|
|
38
|
+
}
|
|
39
|
+
export interface ArtefactWeave {
|
|
40
|
+
weave: number;
|
|
41
|
+
artefact: string;
|
|
42
|
+
issue?: string;
|
|
43
|
+
issue_url?: string;
|
|
44
|
+
episodes: ArtefactEpisodeLink[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Projection of one woven relation — the registration seam for the future
|
|
48
|
+
* `inquiry-weave register` toward medicine-wheel (see rispecs/). v0 exports
|
|
49
|
+
* the shape only; nothing is transmitted anywhere.
|
|
50
|
+
*/
|
|
51
|
+
export interface WeaveRecord {
|
|
52
|
+
weaveVersion: number;
|
|
53
|
+
artefact: {
|
|
54
|
+
name: string;
|
|
55
|
+
path: string;
|
|
56
|
+
};
|
|
57
|
+
issue?: {
|
|
58
|
+
ref: string;
|
|
59
|
+
url?: string;
|
|
60
|
+
};
|
|
61
|
+
episode: {
|
|
62
|
+
number?: number;
|
|
63
|
+
slug?: string;
|
|
64
|
+
path: string;
|
|
65
|
+
};
|
|
66
|
+
lastSync?: LastSync;
|
|
67
|
+
}
|
|
68
|
+
export declare class WeaveError extends Error {
|
|
69
|
+
}
|
|
70
|
+
export declare function episodeWeavePath(episodeDir: string): string;
|
|
71
|
+
export declare function artefactWeavePath(artefactDir: string): string;
|
|
72
|
+
export declare function readEpisodeWeave(episodeDir: string): Promise<EpisodeWeave | undefined>;
|
|
73
|
+
export declare function writeEpisodeWeave(episodeDir: string, weave: EpisodeWeave): Promise<void>;
|
|
74
|
+
export declare function readArtefactWeave(artefactDir: string): Promise<ArtefactWeave | undefined>;
|
|
75
|
+
export declare function writeArtefactWeave(artefactDir: string, weave: ArtefactWeave): Promise<void>;
|
|
76
|
+
/** Merge an inquiry entry by artefact name, preserving fields already recorded. */
|
|
77
|
+
export declare function upsertInquiry(weave: EpisodeWeave, entry: InquiryEntry): InquiryEntry;
|
|
78
|
+
/** Merge an episode link by path, preserving the original related_at. */
|
|
79
|
+
export declare function upsertEpisodeLink(weave: ArtefactWeave, link: ArtefactEpisodeLink): ArtefactEpisodeLink;
|
|
80
|
+
export declare function toWeaveRecords(episodeWeave: EpisodeWeave, inquiryRoot: string): WeaveRecord[];
|
|
81
|
+
export declare function newEpisodeWeave(episode: EpisodeIdentityBlock): EpisodeWeave;
|
|
82
|
+
export declare function newArtefactWeave(artefactDir: string): ArtefactWeave;
|
|
83
|
+
//# sourceMappingURL=weave.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weave.d.ts","sourceRoot":"","sources":["../src/weave.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,eAAO,MAAM,aAAa,IAAI,CAAA;AAE9B,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,QAAQ,CAAA;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,oBAAoB,CAAA;IAC7B,SAAS,EAAE,YAAY,EAAE,CAAA;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,mBAAmB,EAAE,CAAA;CAChC;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC,KAAK,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACrC,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB;AAED,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAExC,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE7D;AAyBD,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAI5F;AAED,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9F;AAED,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAI/F;AAED,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,YAAY,CAUpF;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,mBAAmB,GACxB,mBAAmB,CAQrB;AAED,wBAAgB,cAAc,CAC5B,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,MAAM,GAClB,WAAW,EAAE,CAQf;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,oBAAoB,GAAG,YAAY,CAE3E;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,CAEnE"}
|
package/dist/weave.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The weave contract — the package's own explicit inquiry-metadata files.
|
|
3
|
+
*
|
|
4
|
+
* Episode side: <episode>/inquiry/weave.yaml (sync state lives here only)
|
|
5
|
+
* Artefact side: <artefact>/.weave.yaml (durable relations only, so a
|
|
6
|
+
* sync can copy it verbatim without a self-invalidating hash loop)
|
|
7
|
+
*
|
|
8
|
+
* `.hch/` is best-effort legacy input (see legacy-hch.ts), never written here.
|
|
9
|
+
*/
|
|
10
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { basename, join } from "node:path";
|
|
13
|
+
import { parse, stringify } from "yaml";
|
|
14
|
+
export const WEAVE_VERSION = 1;
|
|
15
|
+
export class WeaveError extends Error {
|
|
16
|
+
}
|
|
17
|
+
export function episodeWeavePath(episodeDir) {
|
|
18
|
+
return join(episodeDir, "inquiry", "weave.yaml");
|
|
19
|
+
}
|
|
20
|
+
export function artefactWeavePath(artefactDir) {
|
|
21
|
+
return join(artefactDir, ".weave.yaml");
|
|
22
|
+
}
|
|
23
|
+
async function readWeaveFile(filePath) {
|
|
24
|
+
if (!existsSync(filePath))
|
|
25
|
+
return undefined;
|
|
26
|
+
let parsed;
|
|
27
|
+
try {
|
|
28
|
+
parsed = parse(await readFile(filePath, "utf8"));
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
throw new WeaveError(`unreadable weave file ${filePath}: ${error.message}`);
|
|
32
|
+
}
|
|
33
|
+
if (parsed === null || parsed === undefined)
|
|
34
|
+
return undefined;
|
|
35
|
+
if (typeof parsed !== "object") {
|
|
36
|
+
throw new WeaveError(`weave file ${filePath} is not a mapping`);
|
|
37
|
+
}
|
|
38
|
+
const version = parsed.weave;
|
|
39
|
+
if (typeof version !== "number" || version > WEAVE_VERSION) {
|
|
40
|
+
throw new WeaveError(`weave file ${filePath} has unsupported version ${String(version)} (this package supports <= ${WEAVE_VERSION})`);
|
|
41
|
+
}
|
|
42
|
+
return parsed;
|
|
43
|
+
}
|
|
44
|
+
export async function readEpisodeWeave(episodeDir) {
|
|
45
|
+
const weave = await readWeaveFile(episodeWeavePath(episodeDir));
|
|
46
|
+
if (weave && !Array.isArray(weave.inquiries))
|
|
47
|
+
weave.inquiries = [];
|
|
48
|
+
return weave;
|
|
49
|
+
}
|
|
50
|
+
export async function writeEpisodeWeave(episodeDir, weave) {
|
|
51
|
+
const filePath = episodeWeavePath(episodeDir);
|
|
52
|
+
await mkdir(join(episodeDir, "inquiry"), { recursive: true });
|
|
53
|
+
await writeFile(filePath, stringify(weave), "utf8");
|
|
54
|
+
}
|
|
55
|
+
export async function readArtefactWeave(artefactDir) {
|
|
56
|
+
const weave = await readWeaveFile(artefactWeavePath(artefactDir));
|
|
57
|
+
if (weave && !Array.isArray(weave.episodes))
|
|
58
|
+
weave.episodes = [];
|
|
59
|
+
return weave;
|
|
60
|
+
}
|
|
61
|
+
export async function writeArtefactWeave(artefactDir, weave) {
|
|
62
|
+
await writeFile(artefactWeavePath(artefactDir), stringify(weave), "utf8");
|
|
63
|
+
}
|
|
64
|
+
/** Merge an inquiry entry by artefact name, preserving fields already recorded. */
|
|
65
|
+
export function upsertInquiry(weave, entry) {
|
|
66
|
+
const existing = weave.inquiries.find((inquiry) => inquiry.artefact === entry.artefact);
|
|
67
|
+
if (!existing) {
|
|
68
|
+
weave.inquiries.push(entry);
|
|
69
|
+
return entry;
|
|
70
|
+
}
|
|
71
|
+
existing.issue = entry.issue ?? existing.issue;
|
|
72
|
+
existing.issue_url = entry.issue_url ?? existing.issue_url;
|
|
73
|
+
existing.last_sync = entry.last_sync ?? existing.last_sync;
|
|
74
|
+
return existing;
|
|
75
|
+
}
|
|
76
|
+
/** Merge an episode link by path, preserving the original related_at. */
|
|
77
|
+
export function upsertEpisodeLink(weave, link) {
|
|
78
|
+
const existing = weave.episodes.find((episode) => episode.path === link.path);
|
|
79
|
+
if (!existing) {
|
|
80
|
+
weave.episodes.push(link);
|
|
81
|
+
return link;
|
|
82
|
+
}
|
|
83
|
+
existing.number = link.number ?? existing.number;
|
|
84
|
+
return existing;
|
|
85
|
+
}
|
|
86
|
+
export function toWeaveRecords(episodeWeave, inquiryRoot) {
|
|
87
|
+
return episodeWeave.inquiries.map((entry) => ({
|
|
88
|
+
weaveVersion: episodeWeave.weave,
|
|
89
|
+
artefact: { name: entry.artefact, path: join(inquiryRoot, entry.artefact) },
|
|
90
|
+
issue: entry.issue ? { ref: entry.issue, url: entry.issue_url } : undefined,
|
|
91
|
+
episode: episodeWeave.episode,
|
|
92
|
+
lastSync: entry.last_sync,
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
export function newEpisodeWeave(episode) {
|
|
96
|
+
return { weave: WEAVE_VERSION, episode, inquiries: [] };
|
|
97
|
+
}
|
|
98
|
+
export function newArtefactWeave(artefactDir) {
|
|
99
|
+
return { weave: WEAVE_VERSION, artefact: basename(artefactDir), episodes: [] };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=weave.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weave.js","sourceRoot":"","sources":["../src/weave.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@miadi/inquiry-weave",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Relate and sync IAIP inquiry artefacts, their GitHub issues, and miadi-chronicle episodes. Creates vessels and relations only — never inquiry content.",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"inquiry-weave": "dist/bin.js"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"rispecs"
|
|
25
|
+
],
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"yaml": "^2.5.0",
|
|
28
|
+
"@miadi/episodic-memory-schema": "0.2.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"typescript": "^5.4.0"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"miadi",
|
|
35
|
+
"inquiry",
|
|
36
|
+
"iaip",
|
|
37
|
+
"miadi-chronicle",
|
|
38
|
+
"episodic-memory",
|
|
39
|
+
"etuaptmumk"
|
|
40
|
+
],
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/jgwill/Miadi.git",
|
|
44
|
+
"directory": "packages/inquiry-weave"
|
|
45
|
+
},
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "../../node_modules/.bin/tsc -p tsconfig.build.json",
|
|
49
|
+
"test": "npm run build && node --test test/*.test.mjs"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# RISE Spec: Inquiry Weave → Medicine-Wheel Registration
|
|
2
|
+
|
|
3
|
+
Companion specs (the other two lanterns of this workstream):
|
|
4
|
+
- `medicine-wheel:rispecs/inquiry-weave-registration.spec.md` — the storage side
|
|
5
|
+
- `forgewright:rispecs/09-inquiry-weave-visibility.spec.md` — the rendering side (branch `4-plan-episode-visibility`, kin to `08-medicine-wheel-integration.spec.md`)
|
|
6
|
+
|
|
7
|
+
Status: **spec-only**. Nothing here is implemented in @miadi/inquiry-weave v0.
|
|
8
|
+
|
|
9
|
+
## Reverse Engineering (current reality)
|
|
10
|
+
|
|
11
|
+
- Inquiry Weave relations exist only as files on disk: `<episode>/inquiry/weave.yaml`
|
|
12
|
+
(episode side, incl. sync state) and `<artefact>/.weave.yaml` (artefact side, durable
|
|
13
|
+
relations). Schema version key `weave: 1`.
|
|
14
|
+
- @miadi/inquiry-weave v0 already exports the projection seam: `WeaveRecord`
|
|
15
|
+
(`src/weave.ts`) — the three identities (artefact name+path, issue ref+url, episode
|
|
16
|
+
number/slug/path) plus `lastSync` — and `toWeaveRecords(episodeWeave, inquiryRoot)`.
|
|
17
|
+
- A medicine-wheel MCP server is already configured for chronicle work:
|
|
18
|
+
`/a/src/Miadi/etc/mcp-config-mw-ilex.json`, server `medicine-wheel-miadi-chronicle`
|
|
19
|
+
(`npx ${MWCV}`, `MW_API_URL=http://192.168.2.30:3940`). It is the candidate storage
|
|
20
|
+
interface; nothing registers weaves into it today.
|
|
21
|
+
- forgewright renders episode data from medicine-wheel but has no notion of an Inquiry
|
|
22
|
+
Weave.
|
|
23
|
+
- Legacy `.hch/` is a per-artefact issue cache with an unsettled fate (formalize / map /
|
|
24
|
+
retire — see README). Registration must not depend on it.
|
|
25
|
+
|
|
26
|
+
## Intent
|
|
27
|
+
|
|
28
|
+
Inquiry Weaves become *visible relations*: once an artefact, its issue, and its episode
|
|
29
|
+
are woven, that weave can be seen wherever episodes are seen — without anyone re-deriving
|
|
30
|
+
it from the filesystem. The weave files on disk remain the source of truth; medicine-wheel
|
|
31
|
+
holds a registered projection; forgewright renders it. The mystery boundary is untouched:
|
|
32
|
+
registration moves metadata, never inquiry content.
|
|
33
|
+
|
|
34
|
+
## Specifications (desired state)
|
|
35
|
+
|
|
36
|
+
- A new command `inquiry-weave register (--episode <ref> | --artefact <ref>) [--dry-run]`
|
|
37
|
+
projects each relation as a `WeaveRecord` and submits it to medicine-wheel.
|
|
38
|
+
- Transport: the medicine-wheel MCP tool surface (preferred) or `MW_API_URL` HTTP —
|
|
39
|
+
decided in the medicine-wheel spec; this package only guarantees the payload shape:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"weaveVersion": 1,
|
|
44
|
+
"artefact": { "name": "ep126-mila-ai-event-…", "path": "/src/IAIP/prototypes/artefacts/…" },
|
|
45
|
+
"issue": { "ref": "miadisabelle/Etuaptmumk-RSM#245", "url": "https://github.com/…/issues/245" },
|
|
46
|
+
"episode": { "number": 126, "slug": "mila-ai-indigenous-gathering", "path": "2026-07-13-episode-126-…" },
|
|
47
|
+
"lastSync": { "at": "…", "tree_sha256": "…", "file_count": 4, "bytes_total": 341001 }
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- Registration is idempotent: re-registering the same weave upserts by
|
|
52
|
+
(episode.path, artefact.name).
|
|
53
|
+
- Structural tension held: current reality = weave files on disk, invisible beyond the
|
|
54
|
+
filesystem; desired state = every woven relation queryable from medicine-wheel and
|
|
55
|
+
rendered by forgewright. `register` is the action step that resolves this tension.
|
|
56
|
+
- Failure to reach medicine-wheel degrades gracefully: the weave files remain
|
|
57
|
+
authoritative; `register` reports and exits 1 without touching them.
|
|
58
|
+
|
|
59
|
+
## Exportation (implementation-ready notes)
|
|
60
|
+
|
|
61
|
+
- Implement as `src/register.ts` consuming `toWeaveRecords()`; add a `register`
|
|
62
|
+
subcommand in `cli.ts`; keep the transport injectable (test seam like
|
|
63
|
+
`INQUIRY_WEAVE_ISSUE_LIB`).
|
|
64
|
+
- Do not implement until the medicine-wheel spec lands its storage contract; then pin the
|
|
65
|
+
agreed endpoint/tool name here.
|
|
66
|
+
- Companion agent sessions (copilot/codex panes in the medicine-wheel and forgewright
|
|
67
|
+
repos) own the other two specs; keep the payload above as the shared contract between
|
|
68
|
+
all three.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
🌸: The weave learns to be seen — first it held three threads together in the dark; now a
|
|
72
|
+
lantern is being shaped so the whole circle can watch them shine.
|