craftar 0.22.0 → 0.22.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.
package/README.md CHANGED
@@ -313,6 +313,14 @@ Later: `service` ingredients with compose fragments (`craftar services up`); `do
313
313
 
314
314
  ## Upgrading
315
315
 
316
+ ### to 0.22.1
317
+
318
+ - **A file the schema refuses is reported on one line, and never with a value it holds.** `invalid <file>: <key>: <what was expected>; <key>: …` replaces zod's JSON list of issues, which quoted the refused value — so a credential written where one of a fixed set of words is expected reached the terminal. A key is still named, as a path (`overrides.sections.<key>`) or as an unrecognized key, and so is the *type* received (`Expected string, received number`) — never the value. It holds for a Forge file, `craftar.yaml` (merged with `craftar.local.yaml`), the registry (`invalid <file>: …`), a `forge unify --plan` file (`<file>: <key>: …`, with no `invalid`), and the refusals of `import` and `drift promote` (`does not fit the ingredient schema: …`, `does not load (…)`), `forge unify` (`the edit no longer loads: …`), and `add recipe`, `remove recipe` and `import --write-config` (`it no longer loads: …`).
319
+ - **A `craftar.lock` or a registry that does not read is named, and nothing of it is quoted.** `craftar.lock is not valid JSON` and `craftar.lock is not a valid lock: <key>: …` replace the raw parser and zod messages; a registry that is not valid JSON reads `cannot read <file>: not valid JSON`. `declares schema <n>, which this craftar does not read` prints the schema only when it is a whole number, and `(not a whole number)` otherwise.
320
+ - **`craftar doctor`**: the `config`, `lock` and `registry` messages carry the same text — `<what> (<key>: <what was expected>, and N more)` keeps its shape, without `received '<value>'`; `craftar.lock is not valid JSON` no longer ends with the parser's message in parentheses.
321
+ - **No exit code and no `--json` key changes**; the text of an error string inside `--json` follows the new wording — among them `doctor --json` `checks[].message`; the `warnings` of `workspaces --json`, `targets --json`, `forge unify --json` and `drift promote --json`; `forge impact --json` `error`; `impact[].error` of `forge unify --json` and `impact.workspaces[].error` of `drift promote --json`; and `forge unify --json` `recipes.kept[].reason`.
322
+ - **No byte change**: no emitter and no lock changed. No workspace sees `update`.
323
+
316
324
  ### to 0.22.0
317
325
 
318
326
  - **New commands `craftar drift show`, `craftar drift discard` and `craftar drift promote`**: list hand-edited files, discard their edits, or carry one into the Forge. `drift show --json` and `drift promote --json` are new tooling contracts. The `sync` skip lines for `drift` and `orphan-drift` were reworded (prose, not a contract).
package/dist/cli.js CHANGED
@@ -33,6 +33,7 @@ import { localKeys, readLocalFile } from "./core/workspace-yaml.js";
33
33
  import { HUNK_CLASSES, INGREDIENT_TYPES, UnifyPlanSchema } from "./schema/index.js";
34
34
  import { EXAMPLE_SETTINGS } from "./emitters/shared.js";
35
35
  import { YamlSyntaxError, parseYamlText } from "./core/yaml-read.js";
36
+ import { errorText } from "./core/schema-fault.js";
36
37
  process.stdout.on("error", (e) => { if (e.code === "EPIPE")
37
38
  process.exit(0); });
38
39
  /**
@@ -42,7 +43,7 @@ process.stdout.on("error", (e) => { if (e.code === "EPIPE")
42
43
  */
43
44
  const DIFF_EXIT_CODE_FETCH_MODE = "sync";
44
45
  const program = new Command();
45
- program.name("craftar").description("Craft, sync and convert AI-coding workspace harnesses.").version("0.22.0");
46
+ program.name("craftar").description("Craft, sync and convert AI-coding workspace harnesses.").version("0.22.1");
46
47
  const SAVE_PLAN_GATE = { what: "plan", who: "unify", outside: "save plans outside the Forge", never: "unify never overwrites" };
47
48
  const REPORT_GATE = { what: "report", who: "import", outside: "write the report outside the Forge", never: "import never overwrites" };
48
49
  program
@@ -1522,13 +1523,13 @@ forge
1522
1523
  parsed = parseYamlText(o.plan, await fs.readFile(o.plan, "utf8"));
1523
1524
  }
1524
1525
  catch (e) {
1525
- fail(e instanceof YamlSyntaxError ? e.message : `${o.plan}: ${e instanceof Error ? e.message : String(e)}`);
1526
+ fail(e instanceof YamlSyntaxError ? e.message : `${o.plan}: ${errorText(e)}`);
1526
1527
  }
1527
1528
  try {
1528
1529
  loadedPlan = UnifyPlanSchema.parse(parsed);
1529
1530
  }
1530
1531
  catch (e) {
1531
- fail(`${o.plan}: ${e instanceof Error ? e.message : String(e)}`);
1532
+ fail(`${o.plan}: ${errorText(e)}`);
1532
1533
  }
1533
1534
  // The plan must be for this exact invocation (Ruling 23) — checked before staleness, so a
1534
1535
  // right-ingredient-wrong-profile plan is named for what it is rather than misdiagnosed as
@@ -1994,7 +1995,7 @@ cache
1994
1995
  else
1995
1996
  printPrune(result);
1996
1997
  });
1997
- program.parseAsync().catch((e) => fail(e instanceof Error ? e.message : String(e)));
1998
+ program.parseAsync().catch((e) => fail(errorText(e)));
1998
1999
  /* ---------------------------------------------------------------- helpers */
1999
2000
  /** The network rule of a command, `--offline`, and `$CRAFTAR_HOME` (spec 13 §4.1, §6.3). */
2000
2001
  function load(o, mode) {
@@ -2328,7 +2329,7 @@ function unheldMessage(command, root, unheld) {
2328
2329
  * git tracks, `clean` for files unify created (checkout refuses a path git does not know).
2329
2330
  */
2330
2331
  function lateFailure(e, root, journal, command = "unify") {
2331
- const msg = e instanceof Error ? e.message : String(e);
2332
+ const msg = errorText(e);
2332
2333
  if (journal.length === 0)
2333
2334
  return msg;
2334
2335
  const rel = (abs) => path.relative(root, abs).split(path.sep).join("/");