craftar 0.28.2 → 0.29.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.
@@ -0,0 +1,160 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { EXAMPLE_SETTINGS } from "../emitters/shared.js";
4
+ import { listTargets } from "./capabilities.js";
5
+ import { diffOps } from "./diff.js";
6
+ import { mcpTagged } from "./drift.js";
7
+ import { FULL_SHA } from "./remote.js";
8
+ import { resolve } from "./resolve.js";
9
+ import { errorText } from "./schema-fault.js";
10
+ import { loadForgeFor, unsetDeclared } from "./sync.js";
11
+ import { hashNormalized, stripBom, toLf } from "./text.js";
12
+ /*
13
+ * What the reading commands answer, as data (spec 35 §5.1): one builder per shape, called by the CLI, by
14
+ * `craftar mcp` and by anything else that shows the same thing. Nothing here prints, and none of them selects,
15
+ * normalizes or refuses a path — each caller keeps its own rule.
16
+ */
17
+ /** Spec 27 Ruling 4: the on-disk content of the example file is never shown. No indentation: the caller's. */
18
+ export const EXAMPLE_CONTENT_HIDDEN = "content not shown: an example file may hold a value typed by hand";
19
+ /** Spec 35 §4.5: what `craftar mcp` says in place of the disk side of a hand-touched MCP file. */
20
+ export const MCP_CONTENT_HIDDEN = "content not shown: an MCP configuration file may hold a value typed by hand";
21
+ /** A path as the user may type it, to the spelling `status` prints: forward slashes, no leading `./`. */
22
+ export const statusPath = (p) => p.replace(/\\/g, "/").replace(/^\.\//, "");
23
+ /** `explain`'s refusal: the Forge does not produce this path for the profile. */
24
+ export const notProduced = (p, profile) => `${p} is not produced by the Forge for profile ${profile}`;
25
+ /** Why sync leaves a file alone, for the three states it skips. */
26
+ export function explainSkip(s) {
27
+ switch (s.state) {
28
+ case "drift":
29
+ return "hand-edited since last sync — `craftar drift show <path>`, then `craftar drift discard` or `craftar drift promote`";
30
+ case "collision":
31
+ return "exists but was never generated by craftar and differs from the Forge — rename it or import it";
32
+ case "orphan-drift":
33
+ return "no longer produced by the Forge but hand-edited — kept; `craftar drift discard <path>` removes it, or delete it yourself";
34
+ default:
35
+ return "";
36
+ }
37
+ }
38
+ /** A file's text as a diff compares it: LF, no BOM; null when it cannot be read. */
39
+ export async function readText(p) {
40
+ try {
41
+ return toLf(stripBom(await fs.readFile(p, "utf8")));
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ export function statusReport(ws, p, lock, statuses) {
48
+ const o = ws.origin;
49
+ return {
50
+ forge: {
51
+ kind: o.kind,
52
+ source: o.source,
53
+ ref: o.ref,
54
+ defaultBranch: o.defaultBranch,
55
+ commit: ws.forge.commit,
56
+ lockCommit: lock?.forge.commit ?? null,
57
+ fetched: o.fetched,
58
+ },
59
+ // The planned buffer never leaves the process: dropped here, once, for every reader of the document.
60
+ statuses: statuses.map(({ planned, ...s }) => s),
61
+ warnings: p.warnings,
62
+ unsetParams: unsetDeclared(p),
63
+ };
64
+ }
65
+ /**
66
+ * What `diff` shows for each row in a state `sync --check` refuses (spec 19 §3.2: `unchanged` and `adopt` are
67
+ * skipped). It never renders: the caller owns the header lines and the paint. `withholdMcp` widens the one
68
+ * withholding of spec 27 Ruling 4 — the example file — to every file tagged `mcp/*`, for a reader that is a model
69
+ * (spec 35 §4.5). The disk is read at the row's path, never at one a caller typed.
70
+ */
71
+ export async function diffReport(ws, rows, opts) {
72
+ const out = [];
73
+ for (const s of rows) {
74
+ if (s.state === "unchanged" || s.state === "adopt")
75
+ continue;
76
+ const noted = (note) => ({ path: s.path, state: s.state, added: null, removed: null, note, disk: null, forge: null });
77
+ if (s.state === "orphan-drift") {
78
+ // No body: sync keeps this file
79
+ out.push(noted(explainSkip(s)));
80
+ continue;
81
+ }
82
+ // Only where a hand has touched the file: in `update` and `orphan` the disk side is what craftar wrote.
83
+ if (s.state === "drift" || s.state === "collision") {
84
+ if (opts.withholdMcp && mcpTagged(s)) {
85
+ out.push(noted(MCP_CONTENT_HIDDEN));
86
+ continue;
87
+ }
88
+ if (s.path === EXAMPLE_SETTINGS) {
89
+ out.push(noted(EXAMPLE_CONTENT_HIDDEN));
90
+ continue;
91
+ }
92
+ }
93
+ const disk = (await readText(path.join(ws.root, s.path))) ?? "";
94
+ // An orphan is the removal of the whole file
95
+ const forge = s.state === "orphan" || !s.planned ? "" : toLf(stripBom(s.planned.content.toString("utf8")));
96
+ const ops = diffOps(disk, forge);
97
+ out.push({
98
+ path: s.path,
99
+ state: s.state,
100
+ added: ops.filter((o) => o.kind === "add").length,
101
+ removed: ops.filter((o) => o.kind === "del").length,
102
+ note: null,
103
+ disk,
104
+ forge,
105
+ });
106
+ }
107
+ return out;
108
+ }
109
+ /** The planned file at `file`, compared as given (the caller normalizes); null when the Forge does not produce it. */
110
+ export function explainFile(ws, p, file) {
111
+ const f = p.files.find((x) => x.path === file);
112
+ if (!f)
113
+ return null;
114
+ // AGENTS.md (rule/*) and the MCP files (mcp/*) are not one ingredient: nothing resolved has their ref.
115
+ const ing = p.resolution.ingredients.find((i) => i.ref === f.ingredient);
116
+ return {
117
+ path: f.path,
118
+ target: f.target,
119
+ ingredient: f.ingredient,
120
+ origin: ing?.meta.origin ? { workspace: ing.meta.origin.workspace, path: ing.meta.origin.path } : null,
121
+ via: ing ? [...ing.via] : null,
122
+ sections: (p.sections.get(f.ingredient) ?? []).map((x) => ({ name: x.name, layer: x.layer })),
123
+ params: (p.params.get(f.ingredient) ?? []).map((x) => ({ key: x.key, layer: x.layer })),
124
+ profile: ws.config.profile,
125
+ recipes: [...p.resolution.recipes],
126
+ hash: hashNormalized(f.content),
127
+ };
128
+ }
129
+ /**
130
+ * The capability matrix with the targets a workspace uses marked. `input` is the configuration to load from
131
+ * (never fetched: `no-fetch`), a reason not to load — worded as a failed load is — or null for no workspace at
132
+ * all: the matrix unmarked, no warning. It never throws for a workspace that does not load or resolve.
133
+ */
134
+ export async function targetsReport(root, opts, input) {
135
+ if (input === null)
136
+ return { ...listTargets(null), warnings: [] };
137
+ const notShown = (why) => ({ ...listTargets(null), warnings: [`targets in use not shown: ${why}`] });
138
+ if ("reason" in input)
139
+ return notShown(input.reason);
140
+ try {
141
+ const ws = await loadForgeFor(root, input.merged, { ...opts, mode: "no-fetch" });
142
+ return { ...listTargets(resolve(ws.forge, ws.config).targets), warnings: [] };
143
+ }
144
+ catch (e) {
145
+ // Load or resolve failed — a warning, not an error
146
+ return notShown(errorText(e));
147
+ }
148
+ }
149
+ /**
150
+ * For a reader started without `--fetch` (`craftar mcp`, spec 35 §4.4): the line that says a remote Forge was read
151
+ * from its cached copy, so an answer for a Forge that has moved is never silent. Null when the caller fetches (the
152
+ * fallback warning is then the signal), for a path Forge, and for a full-SHA `ref`, which cannot go stale.
153
+ */
154
+ export function cachedCopyLine(ws, fetch) {
155
+ const o = ws.origin;
156
+ if (fetch || o.kind !== "remote" || (o.ref !== null && FULL_SHA.test(o.ref)))
157
+ return null;
158
+ return `Forge ${o.source} read from the copy cached ${o.fetchedAt ?? "(time unknown)"} (commit ${ws.forge.commit?.slice(0, 8) ?? "no git"}) — craftar mcp was started without --fetch`;
159
+ }
160
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/core/report.ts"],"names":[],"mappings":"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"}
package/dist/mcp.js ADDED
@@ -0,0 +1,87 @@
1
+ import { handleLine } from "./core/mcp-protocol.js";
2
+ /*
3
+ * The stdio transport of `craftar mcp` (spec 35 §4.3): one JSON-RPC message per line in, one per line out. The
4
+ * only place that knows the wire — the protocol itself is `src/core/mcp-protocol.ts`. It splits lines itself
5
+ * (the cap needs it, and `node:readline` stays `src/prompt.ts`'s alone), touches neither `process` nor `console`,
6
+ * and writes nothing but answers.
7
+ */
8
+ /** A line longer than this is discarded whole: one line cannot hold the server's memory. */
9
+ export const MAX_LINE_BYTES = 1024 * 1024;
10
+ /**
11
+ * Lines in, lines out, one call at a time: a line is not handled before the previous one was answered.
12
+ * Resolves when `input` has ended and the last answer was written.
13
+ */
14
+ export function serve(input, output, ctx) {
15
+ const state = { initialized: false };
16
+ let queue = Promise.resolve();
17
+ // The bytes of the line being read: decoded only once it is whole, so a character split across chunks survives.
18
+ let parts = [];
19
+ let size = 0;
20
+ // Inside a line that already passed the cap: its bytes are dropped up to the newline, never buffered.
21
+ let skipping = false;
22
+ const line = (bytes) => {
23
+ const end = bytes.length > 0 && bytes[bytes.length - 1] === 0x0d ? bytes.length - 1 : bytes.length;
24
+ // The cap is on the line itself: a CR before the newline is not counted against it
25
+ if (end === 0 || end > MAX_LINE_BYTES)
26
+ return;
27
+ const text = bytes.toString("utf8", 0, end);
28
+ queue = queue.then(async () => {
29
+ // A tool that fails is an answer. Anything else that throws — the handling itself, or a write to a reader
30
+ // that went away — drops this line only: the queue goes on, and nothing is said on any stream.
31
+ try {
32
+ const answer = await handleLine(text, ctx, state);
33
+ if (answer !== null)
34
+ output.write(answer + "\n");
35
+ }
36
+ catch {
37
+ /* dropped */
38
+ }
39
+ });
40
+ };
41
+ const feed = (chunk) => {
42
+ let from = 0;
43
+ for (;;) {
44
+ const newline = chunk.indexOf(0x0a, from);
45
+ const piece = chunk.subarray(from, newline === -1 ? chunk.length : newline);
46
+ if (!skipping) {
47
+ // One byte of slack while buffering, for that CR; `line()` holds the cap itself
48
+ if (size + piece.length > MAX_LINE_BYTES + 1) {
49
+ skipping = true;
50
+ parts = [];
51
+ size = 0;
52
+ }
53
+ else {
54
+ parts.push(piece);
55
+ size += piece.length;
56
+ }
57
+ }
58
+ if (newline === -1)
59
+ return;
60
+ if (!skipping)
61
+ line(Buffer.concat(parts));
62
+ skipping = false;
63
+ parts = [];
64
+ size = 0;
65
+ from = newline + 1;
66
+ }
67
+ };
68
+ return new Promise((resolve) => {
69
+ let over = false;
70
+ // The input is over once: at its end, or when it fails or closes without one (a pipe that resets). What was
71
+ // already read is still answered; a stream error never reaches the process as an uncaught exception.
72
+ const finish = (ended) => {
73
+ if (over)
74
+ return;
75
+ over = true;
76
+ // A last line with no newline is still a line — only when the input really ended
77
+ if (ended && !skipping && size > 0)
78
+ line(Buffer.concat(parts));
79
+ void queue.then(resolve);
80
+ };
81
+ input.on("data", (chunk) => feed(typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk));
82
+ input.on("end", () => finish(true));
83
+ input.on("error", () => finish(false));
84
+ input.on("close", () => finish(false));
85
+ });
86
+ }
87
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "craftar",
3
- "version": "0.28.2",
3
+ "version": "0.29.0",
4
4
  "description": "Craft, sync and convert AI-coding workspace harnesses across clients and tools.",
5
5
  "license": "MIT",
6
6
  "type": "module",