dld-kit 1.0.0-rc.3 → 1.0.0-rc.4

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/dist/dld.mjs CHANGED
@@ -7372,7 +7372,7 @@ import { createInterface } from "node:readline/promises";
7372
7372
  import { fileURLToPath } from "node:url";
7373
7373
 
7374
7374
  // package.json
7375
- var version = "1.0.0-rc.3";
7375
+ var version = "1.0.0-rc.4";
7376
7376
 
7377
7377
  // src/core/errors.ts
7378
7378
  var EXIT_ERROR = 1;
@@ -7902,11 +7902,11 @@ function detectSnapshotChanges(ctx, project) {
7902
7902
  if ((stored === void 0 || stored === "unknown") && lastRun !== void 0) {
7903
7903
  stored = gitOrEmpty(git, "log", `--until=${lastRun}`, "--format=%h", "-1").trim() || void 0;
7904
7904
  }
7905
- const commit = resolveStateCommit(git, stored);
7905
+ const commit2 = resolveStateCommit(git, stored);
7906
7906
  let modifiedDecisions = [];
7907
7907
  let commitRange = "";
7908
- if (commit !== void 0 && commit !== shortHead(ctx, paths.root)) {
7909
- commitRange = `${commit}..HEAD`;
7908
+ if (commit2 !== void 0 && commit2 !== shortHead(ctx, paths.root)) {
7909
+ commitRange = `${commit2}..HEAD`;
7910
7910
  const numbers = nulSeparated(
7911
7911
  gitOrEmpty(git, "diff", "-z", "--name-only", commitRange, "--", recordsPathspec(paths))
7912
7912
  ).map((path) => basename3(path)).filter((name) => RECORD_FILE.test(name)).map((name) => recordNumber(name)).filter((number) => number <= includedNumber);
@@ -7927,17 +7927,17 @@ function formatSnapshotChanges(changes) {
7927
7927
  function updateSnapshotState(ctx, project, customArtifacts) {
7928
7928
  const { paths } = project;
7929
7929
  const timestamp = formatTimestamp(ctx.now());
7930
- const commit = shortHead(ctx, paths.root);
7930
+ const commit2 = shortHead(ctx, paths.root);
7931
7931
  const highest = readRecords(ctx, project).filter((record) => record.accepted).reduce((max, record) => Math.max(max, record.number), 0);
7932
7932
  const artifacts = /* @__PURE__ */ Object.create(null);
7933
7933
  for (const name of [...BUILT_IN_ARTIFACTS, ...customArtifacts]) artifacts[name] = timestamp;
7934
7934
  writeStateSection(ctx, paths, "snapshot", {
7935
7935
  last_run: timestamp,
7936
- commit_hash: commit,
7936
+ commit_hash: commit2,
7937
7937
  decisions_included: String(highest),
7938
7938
  artifacts
7939
7939
  });
7940
- return { timestamp, commit, highest };
7940
+ return { timestamp, commit: commit2, highest };
7941
7941
  }
7942
7942
 
7943
7943
  // src/cli/commands/collect-active-decisions.ts
@@ -7962,8 +7962,9 @@ import { basename as basename4 } from "node:path";
7962
7962
  // src/core/open-prs.ts
7963
7963
  var GITHUB_REMOTE = /github\.com[:/]/;
7964
7964
  var PR_LIMIT = "100";
7965
+ var COMMIT_ID = /^[0-9a-f]{40}([0-9a-f]{24})?$/;
7965
7966
  function openPrIds(ctx, paths, base) {
7966
- const skipped = (reason) => ({ ids: [], skipped: reason });
7967
+ const skipped = (reason) => ({ claims: [], skipped: reason });
7967
7968
  try {
7968
7969
  ctx.gh(["--version"]);
7969
7970
  } catch (error) {
@@ -7990,7 +7991,7 @@ function openPrIds(ctx, paths, base) {
7990
7991
  "open",
7991
7992
  `--base=${prBase}`,
7992
7993
  "--json",
7993
- "files,headRefName,isCrossRepository",
7994
+ "files,headRefName,headRefOid,isCrossRepository",
7994
7995
  "--limit",
7995
7996
  PR_LIMIT
7996
7997
  ]);
@@ -8004,14 +8005,15 @@ function openPrIds(ctx, paths, base) {
8004
8005
  if (prs === void 0) return skipped("gh pr list returned unexpected output");
8005
8006
  const current = gitOrEmpty(git, "rev-parse", "--abbrev-ref", "HEAD").trim();
8006
8007
  const prefix = `${recordsPathspec(paths)}/`;
8007
- const ids = [];
8008
+ const claims = [];
8008
8009
  for (const pr of prs) {
8009
8010
  if (!pr.isCrossRepository && pr.headRefName === current) continue;
8010
8011
  for (const path of pr.files) {
8011
- if (path.startsWith(prefix)) ids.push(...path.match(DECISION_MENTION) ?? []);
8012
+ if (!path.startsWith(prefix)) continue;
8013
+ for (const id of path.match(DECISION_MENTION) ?? []) claims.push({ id, head: pr.headRefOid });
8012
8014
  }
8013
8015
  }
8014
- return { ids };
8016
+ return { claims };
8015
8017
  }
8016
8018
  function parsePrList(output) {
8017
8019
  let value;
@@ -8027,6 +8029,7 @@ function parsePrList(output) {
8027
8029
  const files = Array.isArray(item.files) ? item.files : [];
8028
8030
  prs.push({
8029
8031
  headRefName: typeof item.headRefName === "string" ? item.headRefName : void 0,
8032
+ headRefOid: typeof item.headRefOid === "string" && COMMIT_ID.test(item.headRefOid) ? item.headRefOid : void 0,
8030
8033
  isCrossRepository: item.isCrossRepository === true,
8031
8034
  files: files.flatMap(
8032
8035
  (file) => isObject(file) && typeof file.path === "string" ? [file.path] : []
@@ -8095,24 +8098,56 @@ function takenIds(ctx, paths, base) {
8095
8098
  gitOrEmpty(git, "ls-tree", "-r", "-z", "--name-only", base, "--", recordsPathspec(paths))
8096
8099
  ).flatMap((path) => path.match(DECISION_MENTION) ?? []);
8097
8100
  const scan = openPrIds(ctx, paths, base);
8098
- const ids = [.../* @__PURE__ */ new Set([...onBase, ...scan.ids])].sort(compareIds);
8099
- return scan.skipped === void 0 ? { ids } : { ids, skipped: scan.skipped };
8101
+ const ids = [.../* @__PURE__ */ new Set([...onBase, ...scan.claims.map(({ id }) => id)])].sort(compareIds);
8102
+ const taken = { ids, onBase: new Set(onBase), claims: scan.claims };
8103
+ return scan.skipped === void 0 ? taken : { ...taken, skipped: scan.skipped };
8104
+ }
8105
+ function isAncestor(git, ancestor, commit2) {
8106
+ try {
8107
+ git("merge-base", "--is-ancestor", ancestor, commit2);
8108
+ return true;
8109
+ } catch (error) {
8110
+ if (error instanceof GitCommandError) return false;
8111
+ throw error;
8112
+ }
8113
+ }
8114
+ function collides(git, base, { path, id }, taken) {
8115
+ if (taken.onBase.has(id)) return true;
8116
+ const claims = taken.claims.filter((claim) => claim.id === id);
8117
+ if (claims.length === 0) return false;
8118
+ const added = git(
8119
+ "--literal-pathspecs",
8120
+ "log",
8121
+ // log.follow or log.showSignature in the user's config would change the output.
8122
+ "--no-follow",
8123
+ "--no-show-signature",
8124
+ "-1",
8125
+ "--format=%H",
8126
+ "--diff-filter=A",
8127
+ `${base}..HEAD`,
8128
+ "--",
8129
+ path
8130
+ ).trim();
8131
+ return claims.some(
8132
+ ({ head }) => head === void 0 || added === "" || !isAncestor(git, added, head)
8133
+ );
8100
8134
  }
8101
8135
  function listTakenIds(ctx, { paths }, base) {
8102
8136
  verifyBase(ctx, paths, base, " Fetch first or pass --base.");
8103
- return takenIds(ctx, paths, base);
8137
+ const { ids, skipped } = takenIds(ctx, paths, base);
8138
+ return skipped === void 0 ? { ids } : { ids, skipped };
8104
8139
  }
8105
8140
  function collisionsOf(ctx, paths, base) {
8106
- const added = localAdditions(gitAt(ctx, paths.root), paths, base);
8141
+ const git = gitAt(ctx, paths.root);
8142
+ const added = localAdditions(git, paths, base);
8107
8143
  const local = added.flatMap((path) => {
8108
8144
  const id = basename4(path, ".md");
8109
8145
  return RECORD_FILE.test(basename4(path)) ? [{ path, id }] : [];
8110
8146
  });
8111
8147
  if (local.length === 0) return { collisions: [], localIds: [], taken: [] };
8112
8148
  const taken = takenIds(ctx, paths, base);
8113
- const takenSet = new Set(taken.ids);
8114
8149
  const result = {
8115
- collisions: local.filter(({ id }) => takenSet.has(id)),
8150
+ collisions: local.filter((record) => collides(git, base, record, taken)),
8116
8151
  localIds: local.map(({ id }) => id),
8117
8152
  taken: taken.ids
8118
8153
  };
@@ -8190,7 +8225,7 @@ function parseRenamePlan(paths, text) {
8190
8225
 
8191
8226
  // src/core/commit-reindex.ts
8192
8227
  var SUBJECT_LIST_LIMIT = 3;
8193
- function reindexMessage(renames, originalSubjects) {
8228
+ function reindexMessage(renames, originalSubjects = "") {
8194
8229
  const pairs = renames.map(({ oldId, newId }) => `${oldId} -> ${newId}`);
8195
8230
  const subject = renames.length > SUBJECT_LIST_LIMIT ? `reindex ${renames.length} local decisions to avoid base-branch collisions` : `reindex local decisions: ${pairs.join(", ")}`;
8196
8231
  const message = `${subject}
@@ -8202,11 +8237,75 @@ ${pairs.map((pair) => `- ${pair}`).join("\n")}`;
8202
8237
  Squashed from original branch commits:
8203
8238
  ${originalSubjects}`;
8204
8239
  }
8205
- function commitReindex(ctx, { paths }, planText, base) {
8206
- const git = gitAt(ctx, paths.root);
8240
+ function commitReindex(ctx, { paths }, planText, base, { squash = false } = {}) {
8207
8241
  verifyBase(ctx, paths, base);
8208
8242
  const renames = parseRenamePlan(paths, planText);
8209
8243
  if (renames.length === 0) throw new DldError("no rename plan on stdin.");
8244
+ for (const { oldId, newId, path } of renames) {
8245
+ const renamed = posix2.join(posix2.dirname(path), `${newId}.md`);
8246
+ if (!ctx.fs.isRegularFile(join7(paths.root, renamed))) {
8247
+ throw new DldError(`${renamed} not found. Run rename-decision for ${oldId} first.`);
8248
+ }
8249
+ }
8250
+ const git = gitAt(ctx, paths.root);
8251
+ return squash ? squashReindex(ctx, git, paths, renames, base) : commitOnTop(ctx, git, paths, renames);
8252
+ }
8253
+ function commitOnTop(ctx, git, paths, renames) {
8254
+ const stage = /* @__PURE__ */ new Set();
8255
+ for (const { path, newId } of renames) {
8256
+ stage.add(path);
8257
+ stage.add(posix2.join(posix2.dirname(path), `${newId}.md`));
8258
+ }
8259
+ for (const file of nulSeparated(git("diff", "-z", "--no-renames", "--name-only", "HEAD"))) {
8260
+ stage.add(file);
8261
+ }
8262
+ const head = git("rev-parse", "HEAD").trim();
8263
+ const tree = git("write-tree").trim();
8264
+ let stepName = "staging";
8265
+ try {
8266
+ for (const path of [...stage].sort()) {
8267
+ stepName = `staging ${path}`;
8268
+ stagePath(ctx, git, join7(paths.root, path), path);
8269
+ }
8270
+ stepName = "checking the staged changes";
8271
+ if (!hasStagedChanges(git)) {
8272
+ throw new DldError(
8273
+ "nothing to commit. The reindex may have already been committed, or the plan didn't match the working tree."
8274
+ );
8275
+ }
8276
+ stepName = "committing";
8277
+ commit(git, reindexMessage(renames));
8278
+ } catch (error) {
8279
+ try {
8280
+ git("read-tree", tree);
8281
+ } catch (restoreError) {
8282
+ throw new DldError(
8283
+ `commit-reindex failed while ${stepName}: ${describe(error)}
8284
+ Restoring the index also failed: ${describe(restoreError)}
8285
+ To restore by hand: git read-tree ${tree}`
8286
+ );
8287
+ }
8288
+ if (!(error instanceof DldError)) throw error;
8289
+ throw new DldError(
8290
+ `commit-reindex failed while ${stepName}: ${error.message}
8291
+ The index was restored.`,
8292
+ error.exitCode
8293
+ );
8294
+ }
8295
+ return {
8296
+ commit: git("rev-parse", "--short", "HEAD").trim(),
8297
+ onto: git("rev-parse", "--short", head).trim()
8298
+ };
8299
+ }
8300
+ function commit(git, message) {
8301
+ try {
8302
+ git("commit", "--quiet", "-m", message);
8303
+ } catch (error) {
8304
+ if (error instanceof GitCommandError) throw new DldError(`git commit failed: ${error.stderr}`);
8305
+ throw error;
8306
+ }
8307
+ }
8308
+ function squashReindex(ctx, git, paths, renames, base) {
8210
8309
  const onto = mergeBase(ctx, paths, base);
8211
8310
  const head = git("rev-parse", "HEAD").trim();
8212
8311
  if (onto === head) throw new DldError("HEAD is already at the merge-base \u2014 nothing to squash.");
@@ -8255,15 +8354,7 @@ function commitReindex(ctx, { paths }, planText, base) {
8255
8354
  );
8256
8355
  }
8257
8356
  });
8258
- step("committing", () => {
8259
- try {
8260
- git("commit", "--quiet", "-m", message);
8261
- } catch (error) {
8262
- if (error instanceof GitCommandError)
8263
- throw new DldError(`git commit failed: ${error.stderr}`);
8264
- throw error;
8265
- }
8266
- });
8357
+ step("committing", () => commit(git, message));
8267
8358
  } catch (error) {
8268
8359
  throw rollback(ctx, git, indexFull, saved, stepName, error);
8269
8360
  }
@@ -8326,24 +8417,35 @@ function skippedNotice(reason) {
8326
8417
  // src/cli/commands/commit-reindex.ts
8327
8418
  var commitReindexCommand = {
8328
8419
  name: "commit-reindex",
8329
- summary: "Squash the branch into one reindex commit",
8420
+ summary: "Commit the renamed decisions",
8330
8421
  internal: true,
8331
- usage: `Usage: dld commit-reindex --base <ref> < plan
8422
+ usage: `Usage: dld commit-reindex --base <ref> [--squash] < plan
8332
8423
 
8333
- Read a rename plan on standard input and squash the branch's commits since the merge-base
8334
- with <ref> into one reindex commit. INDEX.md is left at its merge-base state. On failure the
8335
- branch, index and INDEX.md are restored.
8424
+ Read a rename plan on standard input and commit the renames, which rename-decision has
8425
+ already applied. By default this adds one commit on top of HEAD with the plan's paths and
8426
+ every tracked file changed since HEAD; untracked files are left out. On failure the index is
8427
+ restored.
8428
+
8429
+ With --squash, the branch's commits since the merge-base with <ref> are squashed into one
8430
+ reindex commit instead, and INDEX.md is left at its merge-base state. On failure the branch,
8431
+ index and INDEX.md are restored.
8336
8432
 
8337
8433
  Options:
8338
8434
  --base <ref> Base ref (required)
8435
+ --squash Squash the branch instead of adding a commit
8339
8436
  `,
8340
8437
  run(args, io, ctx) {
8341
- const { values } = parseCommandArgs({ args: [...args], options: { base: { type: "string" } } });
8438
+ const { values } = parseCommandArgs({
8439
+ args: [...args],
8440
+ options: { base: { type: "string" }, squash: { type: "boolean" } }
8441
+ });
8342
8442
  if (!values.base) throw new DldError("--base is required.");
8343
8443
  const base = baseOption(values.base);
8344
8444
  const project = loadProject(ctx);
8345
- const { commit, onto } = commitReindex(ctx, project, ctx.readStdin(), base);
8346
- io.stdout(`Created reindex commit ${commit} on top of ${onto}
8445
+ const { commit: commit2, onto } = commitReindex(ctx, project, ctx.readStdin(), base, {
8446
+ squash: values.squash === true
8447
+ });
8448
+ io.stdout(`Created reindex commit ${commit2} on top of ${onto}
8347
8449
  `);
8348
8450
  return EXIT_OK;
8349
8451
  }
@@ -8726,11 +8828,11 @@ var idNumber2 = (id) => Number.parseInt(id.slice(3), 10);
8726
8828
  function recordsChangedSinceAudit(ctx, { paths }) {
8727
8829
  const git = gitAt(ctx, paths.root);
8728
8830
  const stored = stateString(readStateSection(ctx, paths, "audit"), "commit_hash");
8729
- const commit = resolveStateCommit(git, stored);
8730
- if (commit === void 0) return void 0;
8831
+ const commit2 = resolveStateCommit(git, stored);
8832
+ if (commit2 === void 0) return void 0;
8731
8833
  const records = recordsPathspec(paths);
8732
8834
  return /* @__PURE__ */ new Set([
8733
- ...nulSeparated(git("diff", "-z", "--name-only", commit, "--", records)),
8835
+ ...nulSeparated(git("diff", "-z", "--name-only", commit2, "--", records)),
8734
8836
  ...nulSeparated(git("ls-files", "-z", "--others", "--exclude-standard", "--", records))
8735
8837
  ]);
8736
8838
  }
@@ -8756,9 +8858,9 @@ function findMissingAmends(ctx, project, { all }) {
8756
8858
  }
8757
8859
  function updateAuditState(ctx, { paths }) {
8758
8860
  const timestamp = formatTimestamp(ctx.now());
8759
- const commit = shortHead(ctx, paths.root);
8760
- writeStateSection(ctx, paths, "audit", { last_run: timestamp, commit_hash: commit });
8761
- return { timestamp, commit };
8861
+ const commit2 = shortHead(ctx, paths.root);
8862
+ writeStateSection(ctx, paths, "audit", { last_run: timestamp, commit_hash: commit2 });
8863
+ return { timestamp, commit: commit2 };
8762
8864
  }
8763
8865
 
8764
8866
  // src/cli/commands/find-missing-amends.ts
@@ -8787,7 +8889,7 @@ Options:
8787
8889
  import { Buffer as Buffer2 } from "node:buffer";
8788
8890
  import { join as join12, posix as posix3 } from "node:path";
8789
8891
  var idPattern = (id, flags = "") => new RegExp(`${id}(?![0-9])`, flags);
8790
- function changedFiles(ctx, paths, commit) {
8892
+ function changedFiles(ctx, paths, commit2) {
8791
8893
  return nulSeparated(
8792
8894
  gitAt(ctx, paths.root)(
8793
8895
  "diff",
@@ -8795,7 +8897,7 @@ function changedFiles(ctx, paths, commit) {
8795
8897
  "--find-renames",
8796
8898
  "--name-only",
8797
8899
  "--diff-filter=AMR",
8798
- commit
8900
+ commit2
8799
8901
  )
8800
8902
  );
8801
8903
  }
@@ -8846,7 +8948,7 @@ function renameDecision(ctx, project, rename, base) {
8846
8948
  }
8847
8949
  function findStaleMentions(ctx, { paths }, planText, base) {
8848
8950
  const renames = parseRenamePlan(paths, planText);
8849
- if (renames.length === 0) return [];
8951
+ if (renames.length === 0) throw new DldError("no rename plan on stdin.");
8850
8952
  verifyBase(ctx, paths, base);
8851
8953
  const decisions = `${decisionsPathspec(paths)}/`;
8852
8954
  const files = changedFiles(ctx, paths, mergeBase(ctx, paths, base)).flatMap((file) => {
@@ -9279,7 +9381,7 @@ function removeEmptyParents(ctx, dir, paths) {
9279
9381
  import { dirname as dirname3, join as join15, posix as posix4 } from "node:path";
9280
9382
 
9281
9383
  // templates/rules/dld-workflow.md
9282
- var dld_workflow_default = "# DLD (Decision-Linked Development)\n\nThis project uses Decision-Linked Development. Decision records (DL-*.md) live in the `records/` subdirectory of the decisions directory set in `dld.config.yaml` (`decisions/` by default). High-level docs (INDEX.md, OVERVIEW.md, SNAPSHOT.md) live in the decisions directory.\n\n## Rules\n\n- When you encounter `@decision(DL-XXX)` annotations in code, read the referenced decision with the dld-lookup skill BEFORE modifying the annotated code.\n- ALWAYS look up and verify related decisions before modifying annotated code. Do not skip this step.\n- NEVER modify code in a way that contradicts an existing decision without first confirming with the user. If the change requires breaking a previous decision, a new decision must be recorded (with the dld-decide skill) that explicitly supersedes the old one. If it only partially modifies a previous decision, record it as an amendment instead.\n\n## Skills\n\n- dld-decide: record a new decision\n- dld-plan: break down a feature into multiple grouped decisions\n- dld-implement: implement proposed decisions\n- dld-lookup: query decisions by ID, tag, or code path\n- dld-adjust: adjust or update existing decisions\n- dld-audit: scan for drift between decisions and code\n- dld-snapshot: regenerate SNAPSHOT.md and OVERVIEW.md from the decision log\n- dld-status: a quick overview of the decision log state\n- dld-retrofit: generate decisions from an existing codebase\n- dld-reindex: resolve decision-ID collisions with the base branch (and open PRs) before rebasing\n";
9384
+ var dld_workflow_default = "# DLD (Decision-Linked Development)\n\nThis project uses Decision-Linked Development. Decision records (DL-*.md) live in the `records/` subdirectory of the decisions directory set in `dld.config.yaml` (`decisions/` by default). High-level docs (INDEX.md, OVERVIEW.md, SNAPSHOT.md) live in the decisions directory.\n\n## Rules\n\n- When you encounter `@decision(DL-XXX)` annotations in code, read the referenced decision with the dld-lookup skill BEFORE modifying the annotated code.\n- ALWAYS look up and verify related decisions before modifying annotated code. Do not skip this step.\n- NEVER modify code in a way that contradicts an existing decision without first confirming with the user. If the change requires breaking a previous decision, a new decision must be recorded (with the dld-decide skill) that explicitly supersedes the old one. If it only partially modifies a previous decision, record it as an amendment instead.\n\n## Skills\n\n- dld-decide: record a new decision\n- dld-plan: break down a feature into multiple grouped decisions\n- dld-implement: implement proposed decisions\n- dld-lookup: query decisions by ID, tag, or code path\n- dld-adjust: adjust or update existing decisions\n- dld-audit: scan for drift between decisions and code\n- dld-snapshot: regenerate SNAPSHOT.md and OVERVIEW.md from the decision log\n- dld-status: a quick overview of the decision log state\n- dld-retrofit: generate decisions from an existing codebase\n- dld-reindex: resolve decision-ID collisions with the base branch and open PRs\n";
9283
9385
 
9284
9386
  // src/generate/rule.ts
9285
9387
  var RULE_TEXT = dld_workflow_default;
@@ -10194,8 +10296,8 @@ var updateAuditStateCommand = {
10194
10296
  usage: "Usage: dld update-audit-state\n\nRecord the current time and HEAD commit as the last audit.\n",
10195
10297
  run(args, io, ctx) {
10196
10298
  parseCommandArgs({ args: [...args], options: {} });
10197
- const { timestamp, commit } = updateAuditState(ctx, loadProject(ctx));
10198
- io.stdout(`Audit state updated: ${timestamp} at ${commit}
10299
+ const { timestamp, commit: commit2 } = updateAuditState(ctx, loadProject(ctx));
10300
+ io.stdout(`Audit state updated: ${timestamp} at ${commit2}
10199
10301
  `);
10200
10302
  return EXIT_OK;
10201
10303
  }
@@ -10217,8 +10319,8 @@ SNAPSHOT.md, OVERVIEW.md and any custom artifacts named.
10217
10319
  options: {},
10218
10320
  allowPositionals: true
10219
10321
  });
10220
- const { timestamp, commit, highest } = updateSnapshotState(ctx, loadProject(ctx), positionals);
10221
- io.stdout(`Snapshot state updated: ${timestamp} at ${commit} (through ${formatId(highest)})
10322
+ const { timestamp, commit: commit2, highest } = updateSnapshotState(ctx, loadProject(ctx), positionals);
10323
+ io.stdout(`Snapshot state updated: ${timestamp} at ${commit2} (through ${formatId(highest)})
10222
10324
  `);
10223
10325
  return EXIT_OK;
10224
10326
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dld-kit",
3
- "version": "1.0.0-rc.3",
3
+ "version": "1.0.0-rc.4",
4
4
  "description": "Decision-Linked Development: record, link, and audit development decisions alongside code",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -3,7 +3,7 @@ name: dld-adjust
3
3
  description: Adjust or update existing decision records. Handles permission gating for accepted decisions and correctly interprets adjustment requests.
4
4
  compatibility: Requires Node.js 20+ and git.
5
5
  metadata:
6
- dld-kit-version: "1.0.0-rc.3"
6
+ dld-kit-version: "1.0.0-rc.4"
7
7
  ---
8
8
  <!-- Generated by dld-kit from templates/skills/dld-adjust/SKILL.md. Do not edit: updating the skills overwrites this file. -->
9
9
 
@@ -3,7 +3,7 @@ name: dld-audit
3
3
  description: Scan for drift between decisions and code. Finds orphaned annotations, stale references, and undocumented changes.
4
4
  compatibility: Requires Node.js 20+ and git.
5
5
  metadata:
6
- dld-kit-version: "1.0.0-rc.3"
6
+ dld-kit-version: "1.0.0-rc.4"
7
7
  ---
8
8
  <!-- Generated by dld-kit from templates/skills/dld-audit/SKILL.md. Do not edit: updating the skills overwrites this file. -->
9
9
 
@@ -3,7 +3,7 @@ name: dld-audit-auto
3
3
  description: Autonomous audit — detects drift, fixes issues, and opens a PR. Designed for scheduled/CI execution without human interaction.
4
4
  compatibility: Requires Node.js 20+ and git.
5
5
  metadata:
6
- dld-kit-version: "1.0.0-rc.3"
6
+ dld-kit-version: "1.0.0-rc.4"
7
7
  ---
8
8
  <!-- Generated by dld-kit from templates/skills/dld-audit-auto/SKILL.md. Do not edit: updating the skills overwrites this file. -->
9
9
 
@@ -3,7 +3,7 @@ name: dld-common
3
3
  description: The dld CLI shared by the DLD skills. Not intended for direct invocation — the other DLD skills run it.
4
4
  compatibility: Requires Node.js 20+ and git.
5
5
  metadata:
6
- dld-kit-version: "1.0.0-rc.3"
6
+ dld-kit-version: "1.0.0-rc.4"
7
7
  ---
8
8
  <!-- Generated by dld-kit from templates/skills/dld-common/SKILL.md. Do not edit: updating the skills overwrites this file. -->
9
9