gitifact 0.5.0 → 0.5.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.
Files changed (25) hide show
  1. package/README.md +2 -2
  2. package/dist/browser/assets/{Markdown-C8C4nHPG.js → Markdown-CqZ4w2H_.js} +1 -1
  3. package/dist/browser/assets/{MetadataListItem-CcPRe-aG.js → MetadataListItem-B6xUZEC3.js} +1 -1
  4. package/dist/browser/assets/{Table-B_rvjexw.js → Table-DDKWqCdD.js} +1 -1
  5. package/dist/browser/assets/{about-D6bBZN8p.js → about-Chl-XBQg.js} +1 -1
  6. package/dist/browser/assets/{activity-B7x648pR.js → activity-F2_AhgBS.js} +1 -1
  7. package/dist/browser/assets/{changelog-DaxXahXm.js → changelog-DrJfyXDZ.js} +1 -1
  8. package/dist/browser/assets/{contributors._email-BZevZqRL.js → contributors._email-CINLTSX2.js} +1 -1
  9. package/dist/browser/assets/{contributors.index-BgA9LkC0.js → contributors.index-ChB89wcL.js} +1 -1
  10. package/dist/browser/assets/{document-CFtIdIPN.js → document-Jy6Buepz.js} +1 -1
  11. package/dist/browser/assets/{features._featureId-BBYORTqC.js → features._featureId-FySsJ2tl.js} +1 -1
  12. package/dist/browser/assets/{features.index-DuwIen6d.js → features.index-DWfPG8WV.js} +1 -1
  13. package/dist/browser/assets/{git-DVoIz_Mx.js → git-AnH-8SBT.js} +1 -1
  14. package/dist/browser/assets/{index-BP3PrawI.js → index-DXK4gUTr.js} +3 -3
  15. package/dist/browser/assets/{page-header-Zwbd52Q5.js → page-header-N7A_M6-B.js} +2 -2
  16. package/dist/browser/assets/{product-euizlTTB.js → product-BKOKDrzZ.js} +1 -1
  17. package/dist/browser/assets/{product.index-B4D5SxOO.js → product.index-BohDJK9z.js} +1 -1
  18. package/dist/browser/assets/{request-state-Dz-oeAkg.js → request-state-CO3OLoay.js} +1 -1
  19. package/dist/browser/assets/{requirements-wk9Joy7M.js → requirements-Dh2NEqNw.js} +1 -1
  20. package/dist/browser/assets/{settings-DwA6H4Ax.js → settings-DylPhHVJ.js} +1 -1
  21. package/dist/browser/assets/{wiki-DkAnuzON.js → wiki-DYxjYiPl.js} +1 -1
  22. package/dist/browser/index.html +8 -8
  23. package/dist/i18n/ko/changelog.md +8 -0
  24. package/dist/main.js +130 -74
  25. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -3510,7 +3510,8 @@ var messages_default = {
3510
3510
  "source.path": "\uCC38\uACE0 \uBB38\uC11C path\uB294 .md\uB85C \uB05D\uB098\uB294 \uC0C1\uB300 \uACBD\uB85C\uC5EC\uC57C \uD569\uB2C8\uB2E4: {path}",
3511
3511
  "edit.documentIdNotFound": "\uC704\uD0A4 \uD398\uC774\uC9C0 ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: {id}",
3512
3512
  "edit.invalidSources": "sources\uB294 \uCD5C\uB300 50\uAC1C\uC758 \uBC30\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
3513
- "config.unsupportedSchema": "\uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uC800\uC7A5 \uADDC\uC57D(schemaVersion {version})\uC740 \uC774 CLI\uAC00 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC815\uC2DD \uBC84\uC804 \uC804 \uADDC\uC57D\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC73C\uBA70 \uC0C8\uB85C init \uD569\uB2C8\uB2E4."
3513
+ "config.unsupportedSchema": "\uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uC800\uC7A5 \uADDC\uC57D(schemaVersion {version})\uC740 \uC774\uC804 \uBC84\uC804\uC758 \uAC83\uC774\uB77C \uC774 CLI\uAC00 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC815\uC2DD \uBC84\uC804 \uC804 \uADDC\uC57D\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. .gitifact\uC5D0 config.json\uB9CC \uC788\uC73C\uBA74 gitifact init\uC774 \uC0C8 \uADDC\uC57D\uC73C\uB85C \uBC14\uAFC9\uB2C8\uB2E4.",
3514
+ "config.newerSchema": "\uC774 \uD504\uB85C\uC81D\uD2B8\uB294 \uB354 \uC0C8\uB85C\uC6B4 \uC800\uC7A5 \uADDC\uC57D(schemaVersion {version})\uC744 \uC501\uB2C8\uB2E4. npm install -g gitifact@latest\uB85C CLI\uB97C \uC62C\uB9B0 \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694."
3514
3515
  };
3515
3516
 
3516
3517
  // ../../packages/core/dist/shared/i18n/index.js
@@ -3595,8 +3596,11 @@ function parseManagedConfig(text2) {
3595
3596
  const config2 = value;
3596
3597
  if (Object.keys(config2).sort().join(",") !== "baseline,schemaVersion")
3597
3598
  throw new InitError("INVALID_CONFIG", t("config.schemaFields"));
3598
- if (config2.schemaVersion !== SCHEMA_VERSION)
3599
- throw new InitError("UNSUPPORTED_SCHEMA", t("config.unsupportedSchema", { version: String(config2.schemaVersion) }));
3599
+ if (config2.schemaVersion !== SCHEMA_VERSION) {
3600
+ const found = config2.schemaVersion;
3601
+ const newer = typeof found === "number" && found > SCHEMA_VERSION;
3602
+ throw new InitError("UNSUPPORTED_SCHEMA", newer ? t("config.newerSchema", { version: String(found) }) : t("config.unsupportedSchema", { version: String(found) }));
3603
+ }
3600
3604
  const checked = parseProjectConfig(JSON.stringify({ kind: "tryce-project", format: "workflow-1", mode: "auto", baseline: config2.baseline }));
3601
3605
  return { schemaVersion: SCHEMA_VERSION, baseline: checked.baseline };
3602
3606
  }
@@ -24586,13 +24590,32 @@ var browserHttpErrorV1 = external_exports.strictObject({
24586
24590
  })
24587
24591
  });
24588
24592
 
24589
- // ../../packages/contracts/dist/versions/project-init-v4.js
24590
- var projectInitV4 = external_exports.discriminatedUnion("ok", [
24593
+ // ../../packages/contracts/dist/versions/browser-session-v2.js
24594
+ var release = external_exports.string().regex(/^\d+\.\d+\.\d+$/);
24595
+ var updateStateV1 = external_exports.strictObject({
24596
+ status: external_exports.enum(["checking", "available", "up-to-date", "unavailable", "disabled"]),
24597
+ latestVersion: release.nullable()
24598
+ }).refine((value) => (value.status === "available" || value.status === "up-to-date") === (value.latestVersion !== null), "latestVersion is set exactly when the check produced a result.");
24599
+ var browserSessionV2 = external_exports.strictObject({
24600
+ contract: external_exports.literal("browser-session"),
24601
+ version: external_exports.literal(2),
24602
+ sessionId: external_exports.uuid(),
24603
+ repository: external_exports.strictObject({
24604
+ key: external_exports.string().regex(/^repo:[0-9a-f]{64}$/),
24605
+ worktreeKey: external_exports.string().regex(/^worktree:[0-9a-f]{64}$/)
24606
+ }),
24607
+ // The running CLI, the same value as `gitifact --version`. A development build may carry a pre-release suffix.
24608
+ cliVersion: external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/),
24609
+ update: updateStateV1
24610
+ });
24611
+
24612
+ // ../../packages/contracts/dist/versions/project-init-v5.js
24613
+ var projectInitV5 = external_exports.discriminatedUnion("ok", [
24591
24614
  external_exports.strictObject({
24592
24615
  contract: external_exports.literal("project-init"),
24593
- version: external_exports.literal(4),
24616
+ version: external_exports.literal(5),
24594
24617
  ok: external_exports.literal(true),
24595
- outcome: external_exports.enum(["planned", "created", "already-initialized"]),
24618
+ outcome: external_exports.enum(["planned", "created", "replaced", "already-initialized"]),
24596
24619
  rootPath: external_exports.string(),
24597
24620
  configPath: external_exports.literal(".gitifact/config.json"),
24598
24621
  schemaVersion: external_exports.literal(2),
@@ -24600,9 +24623,12 @@ var projectInitV4 = external_exports.discriminatedUnion("ok", [
24600
24623
  external_exports.strictObject({ kind: external_exports.literal("empty") }),
24601
24624
  external_exports.strictObject({ kind: external_exports.literal("commit"), objectFormat: external_exports.enum(["sha1", "sha256"]), commit: external_exports.string() })
24602
24625
  ]),
24603
- agentDocs: external_exports.strictObject({ mode: external_exports.enum(["install", "remove", "skip"]), paths: external_exports.array(external_exports.string()) })
24626
+ agentDocs: external_exports.strictObject({ mode: external_exports.enum(["install", "remove", "skip"]), paths: external_exports.array(external_exports.string()) }),
24627
+ update: updateStateV1,
24628
+ // Present only when a newer release exists. The command is for npm global installs; other installs differ.
24629
+ install: external_exports.strictObject({ npmGlobal: external_exports.string().min(1) }).nullable()
24604
24630
  }),
24605
- external_exports.strictObject({ contract: external_exports.literal("project-init"), version: external_exports.literal(4), ok: external_exports.literal(false), error: external_exports.strictObject({ code: external_exports.string(), message: external_exports.string() }) })
24631
+ external_exports.strictObject({ contract: external_exports.literal("project-init"), version: external_exports.literal(5), ok: external_exports.literal(false), error: external_exports.strictObject({ code: external_exports.string(), message: external_exports.string() }) })
24606
24632
  ]);
24607
24633
 
24608
24634
  // ../../packages/contracts/dist/versions/browser-specs-v2.js
@@ -24677,25 +24703,6 @@ var changelogV1 = external_exports.strictObject({
24677
24703
  }
24678
24704
  });
24679
24705
 
24680
- // ../../packages/contracts/dist/versions/browser-session-v2.js
24681
- var release = external_exports.string().regex(/^\d+\.\d+\.\d+$/);
24682
- var updateStateV1 = external_exports.strictObject({
24683
- status: external_exports.enum(["checking", "available", "up-to-date", "unavailable", "disabled"]),
24684
- latestVersion: release.nullable()
24685
- }).refine((value) => (value.status === "available" || value.status === "up-to-date") === (value.latestVersion !== null), "latestVersion is set exactly when the check produced a result.");
24686
- var browserSessionV2 = external_exports.strictObject({
24687
- contract: external_exports.literal("browser-session"),
24688
- version: external_exports.literal(2),
24689
- sessionId: external_exports.uuid(),
24690
- repository: external_exports.strictObject({
24691
- key: external_exports.string().regex(/^repo:[0-9a-f]{64}$/),
24692
- worktreeKey: external_exports.string().regex(/^worktree:[0-9a-f]{64}$/)
24693
- }),
24694
- // The running CLI, the same value as `gitifact --version`. A development build may carry a pre-release suffix.
24695
- cliVersion: external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/),
24696
- update: updateStateV1
24697
- });
24698
-
24699
24706
  // ../../packages/contracts/dist/versions/update-v3.js
24700
24707
  var commitReason = external_exports.enum(["untracked", "other-changes", "commit-failed"]);
24701
24708
  var agentDocsCommit = external_exports.strictObject({
@@ -24910,6 +24917,7 @@ var messages_default2 = {
24910
24917
  "init.configDeleted": "\uAE30\uC874 \uC124\uC815\uC758 \uC0AD\uC81C\uB97C \uC2E0\uADDC \uB3C4\uC785\uC73C\uB85C \uCC98\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24911
24918
  "init.existingSpecs": "\uAE30\uC874 specs \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.",
24912
24919
  "init.orphanStore": "\uC124\uC815 \uC5C6\uB294 .gitifact \uC790\uB8CC\uB97C \uC790\uB3D9 \uCC44\uD0DD\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24920
+ "init.legacyRecords": "\uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0\uB294 \uC774\uC804 \uC800\uC7A5 \uADDC\uC57D(schemaVersion {version})\uC73C\uB85C \uC4F4 \uBA85\uC138\uB098 \uAE30\uB85D\uC774 \uC788\uC5B4 \uC124\uC815\uC744 \uBC14\uAFB8\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC774 CLI\uB294 \uC774\uC804 \uADDC\uC57D\uC744 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uAE30\uB85D\uC744 \uB2E4\uB978 \uACF3\uC5D0 \uBCF4\uAD00\uD558\uACE0 .gitifact\uC5D0 config.json\uB9CC \uB0A8\uAE34 \uB4A4 \uB2E4\uC2DC init \uD558\uC138\uC694.",
24913
24921
  "init.headOrIndexChanged": "HEAD \uB610\uB294 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24914
24922
  "init.configAppeared": "\uB2E4\uB978 \uC2E4\uD589\uC774 \uC124\uC815\uC744 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4.",
24915
24923
  "init.changedAfterWrite": "\uC124\uC815 \uC0DD\uC131 \uD6C4 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694.",
@@ -24919,6 +24927,7 @@ var messages_default2 = {
24919
24927
  "init.text.blockUpdated": "\uBE14\uB85D \uAC31\uC2E0",
24920
24928
  "init.text.storage": "\uC800\uC7A5 \uADDC\uC57D",
24921
24929
  "init.text.agentDocs": "\uC5D0\uC774\uC804\uD2B8 \uC9C0\uCE68",
24930
+ "init.text.updateAvailable": "\uC0C8 \uBC84\uC804 {version}\uC774 \uC788\uC2B5\uB2C8\uB2E4. {command}\uB85C \uC124\uCE58\uD55C \uB4A4 gitifact init\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD558\uBA74 \uC9C0\uCE68 \uBE14\uB85D\uC774 \uC0C8 \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0\uB429\uB2C8\uB2E4.",
24922
24931
  "init.failed": "\uCD08\uAE30\uD654\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uD30C\uC77C \uC811\uADFC \uAD8C\uD55C\uACFC \uC0DD\uC131\uB41C \uC124\uC815\xB7\uC784\uC2DC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694.",
24923
24932
  "config.storeNotDirectory": ".gitifact\uB294 \uB9C1\uD06C\uAC00 \uC544\uB2CC \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
24924
24933
  "config.migrateFirst": ".tryce \uC800\uC7A5\uC18C\uC785\uB2C8\uB2E4. gitifact migrate\uB85C .gitifact\uC5D0 \uC804\uD658\uD558\uC138\uC694.",
@@ -25331,7 +25340,7 @@ function specPreviewReader(cwd) {
25331
25340
  }
25332
25341
 
25333
25342
  // src/adapters/filesystem/spec-preview-store.ts
25334
- import { lstat as lstat3, readdir as readdir3, readFile as readFile3, mkdir as mkdir2, writeFile, rename, unlink as unlink2, rmdir } from "node:fs/promises";
25343
+ import { lstat as lstat3, readdir as readdir3, readFile as readFile3, mkdir as mkdir2, writeFile, rename as rename2, unlink as unlink2, rmdir } from "node:fs/promises";
25335
25344
  import { join as join4, dirname } from "node:path";
25336
25345
  import { createHash as createHash2, randomBytes } from "node:crypto";
25337
25346
 
@@ -25383,7 +25392,7 @@ async function workingWarnings(root, bundle) {
25383
25392
  }
25384
25393
 
25385
25394
  // src/adapters/filesystem/config-file.ts
25386
- import { lstat as lstat2, readFile as readFile2, realpath, mkdir, open as open2, link, unlink } from "node:fs/promises";
25395
+ import { lstat as lstat2, readFile as readFile2, realpath, mkdir, open as open2, link, rename, unlink } from "node:fs/promises";
25387
25396
  import { join as join3 } from "node:path";
25388
25397
  import { randomUUID as randomUUID3 } from "node:crypto";
25389
25398
  var missing = (error62) => error62.code === "ENOENT";
@@ -25418,7 +25427,7 @@ async function readConfigFile(root) {
25418
25427
  throw new InitError("INVALID_CONFIG", t2("config.notUtf8Json"));
25419
25428
  }
25420
25429
  }
25421
- async function publishConfig(root, text2, recheck, beforePublish) {
25430
+ async function publishConfig(root, text2, recheck, beforePublish, replace = false) {
25422
25431
  const directory = join3(root, ".gitifact");
25423
25432
  await configDirectory(root);
25424
25433
  await mkdir(directory).catch((error62) => {
@@ -25449,7 +25458,8 @@ async function publishConfig(root, text2, recheck, beforePublish) {
25449
25458
  const bytes = await readFile2(temporary, "utf8");
25450
25459
  if (bytes !== text2) throw new InitError("INPUT_CHANGED", t2("config.temporaryChanged"));
25451
25460
  parseManagedConfig(bytes);
25452
- await link(temporary, join3(directory, "config.json"));
25461
+ if (replace) await rename(temporary, join3(directory, "config.json"));
25462
+ else await link(temporary, join3(directory, "config.json"));
25453
25463
  } finally {
25454
25464
  await unchanged();
25455
25465
  const current = await fileInfo(temporary);
@@ -25521,7 +25531,7 @@ async function readWorkingPreview(cwd) {
25521
25531
  const { root, stamp, specs, wiki, bundle } = await readWorkingPreviewState(cwd);
25522
25532
  return { stamp, specs, wiki, warnings: await workingWarnings(root, bundle) };
25523
25533
  }
25524
- async function saveWorkingPreview(cwd, input2, publish = rename) {
25534
+ async function saveWorkingPreview(cwd, input2, publish = rename2) {
25525
25535
  if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail4(t2("store.invalidInput"));
25526
25536
  const request = input2;
25527
25537
  if (Object.keys(request).sort().join(",") !== "expected,operations" || typeof request.expected !== "string") fail4(t2("store.expectedOperations"));
@@ -25545,7 +25555,7 @@ async function saveWorkingPreview(cwd, input2, publish = rename) {
25545
25555
  }, publish);
25546
25556
  }
25547
25557
  var readLockedPreviewState = (root) => snapshot2(root);
25548
- async function previewTransaction(cwd, expected2, build, publish = rename, afterPublish) {
25558
+ async function previewTransaction(cwd, expected2, build, publish = rename2, afterPublish) {
25549
25559
  const { root, gitDir } = await specPreviewReader(cwd).location();
25550
25560
  await failOnLegacyLock(gitDir);
25551
25561
  const lock = join4(gitDir, "gitifact-spec-preview.lock");
@@ -25630,7 +25640,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
25630
25640
  const temp = join4(dirname(path3), ".gitifact-restore-" + randomBytes(12).toString("hex"));
25631
25641
  temporary.push(temp);
25632
25642
  await writeFile(temp, c.before, { flag: "wx" });
25633
- await rename(temp, path3);
25643
+ await rename2(temp, path3);
25634
25644
  }
25635
25645
  } catch {
25636
25646
  keepRecovery = true;
@@ -26108,7 +26118,7 @@ function initRepository(cwd, inherited = process.env) {
26108
26118
  }
26109
26119
 
26110
26120
  // src/adapters/filesystem/managed-file.ts
26111
- import { open as open3, readFile as readFile6, mkdir as mkdir3, realpath as realpath2, rename as rename2, link as link2, unlink as unlink3 } from "node:fs/promises";
26121
+ import { open as open3, readFile as readFile6, mkdir as mkdir3, realpath as realpath2, rename as rename3, link as link2, unlink as unlink3 } from "node:fs/promises";
26112
26122
  import { join as join7, dirname as dirname2 } from "node:path";
26113
26123
  import { randomUUID as randomUUID5 } from "node:crypto";
26114
26124
  var DEFAULT_LIMIT = 1024 * 1024;
@@ -26178,7 +26188,7 @@ async function managedWrite(root, path3, previous, next, recheck) {
26178
26188
  await unchanged();
26179
26189
  if (await managedRead(root, path3) !== previous || await readFile6(temp, "utf8") !== next) throw new InitError("INPUT_CHANGED", t2("managedFile.publishTargetChanged", { path: path3 }));
26180
26190
  if (previous === null) await link2(temp, full);
26181
- else await rename2(temp, full);
26191
+ else await rename3(temp, full);
26182
26192
  } finally {
26183
26193
  await unchanged();
26184
26194
  const now = await fileInfo(temp);
@@ -26389,22 +26399,27 @@ async function applyAgentDocs(root, plan, recheck) {
26389
26399
  }
26390
26400
 
26391
26401
  // src/commands/spec-init.ts
26392
- async function initializeSpecProject(cwd, dryRun = false, env = process.env, beforePublish, agentDocs, readDoc = (name) => readBundledDoc(name, defaultLanguage2)) {
26402
+ async function initializeSpecProject(cwd, dryRun = false, env = process.env, beforePublish, agentDocs, readDoc = (name) => readBundledDoc(name, defaultLanguage2), update = disabledUpdate) {
26393
26403
  const repo = initRepository(cwd, env);
26394
26404
  const first = await repo.inspect();
26395
26405
  const root = first.state.repository.rootPath;
26396
26406
  const docsPlan = agentDocs ? await planAgentDocs(root, agentDocs) : skippedAgentDocs;
26397
- const result = (config3, outcome) => projectInitV4.parse({
26398
- contract: "project-init",
26399
- version: 4,
26400
- ok: true,
26401
- outcome,
26402
- rootPath: root,
26403
- configPath: ".gitifact/config.json",
26404
- schemaVersion: config3.schemaVersion,
26405
- baseline: config3.baseline,
26406
- agentDocs: { mode: docsPlan.mode, paths: docsPlan.paths }
26407
- });
26407
+ const result = async (config3, outcome) => {
26408
+ const checked = await update;
26409
+ return projectInitV5.parse({
26410
+ contract: "project-init",
26411
+ version: 5,
26412
+ ok: true,
26413
+ outcome,
26414
+ rootPath: root,
26415
+ configPath: ".gitifact/config.json",
26416
+ schemaVersion: config3.schemaVersion,
26417
+ baseline: config3.baseline,
26418
+ agentDocs: { mode: docsPlan.mode, paths: docsPlan.paths },
26419
+ update: checked,
26420
+ install: checked.status === "available" ? { npmGlobal: npmGlobalInstall(checked.latestVersion) } : null
26421
+ });
26422
+ };
26408
26423
  const existing = async (text3) => {
26409
26424
  const config3 = parseManagedConfig(text3);
26410
26425
  if (!("schemaVersion" in config3)) throw new InitError("MIGRATION_REQUIRED", t2("init.migrationRequired"));
@@ -26416,8 +26431,40 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
26416
26431
  if (!dryRun) await applyAgentDocs(root, docsPlan, unchanged);
26417
26432
  return result(config3, "already-initialized");
26418
26433
  };
26434
+ const config2 = { schemaVersion: SCHEMA_VERSION, baseline: first.state.head.commit ? { kind: "commit", objectFormat: first.state.repository.objectFormat, commit: first.state.head.commit } : { kind: "empty" } };
26435
+ const text2 = JSON.stringify(config2, null, 2) + "\n";
26436
+ const replaceLegacy = async (before, version2) => {
26437
+ const onlyConfig = async () => {
26438
+ const entries = await readdir4(join9(root, ".gitifact"));
26439
+ if (await fileInfo(join9(root, "specs")) || entries.some((name) => name !== "config.json" && !/^\.init-[a-f0-9-]+\.tmp$/.test(name))) {
26440
+ throw new InitError("UNSUPPORTED_SCHEMA", t2("init.legacyRecords", { version: String(version2) }));
26441
+ }
26442
+ };
26443
+ const recheck2 = async () => {
26444
+ await onlyConfig();
26445
+ await repo.checkIgnore(root);
26446
+ if ((await repo.inspect()).stamp !== first.stamp) throw new InitError("INPUT_CHANGED", t2("init.headOrIndexChanged"));
26447
+ if (await readConfigFile(root) !== before) throw new InitError("INPUT_CHANGED", t2("init.inputChanged"));
26448
+ };
26449
+ await recheck2();
26450
+ if (dryRun) return result(config2, "planned");
26451
+ await publishConfig(root, text2, recheck2, beforePublish, true);
26452
+ return finish("replaced");
26453
+ };
26454
+ const finish = async (outcome) => {
26455
+ const published = async () => {
26456
+ if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text2) throw new InitError("INPUT_CHANGED_AFTER_WRITE", t2("init.changedAfterWrite"));
26457
+ };
26458
+ await published();
26459
+ await applyAgentDocs(root, docsPlan, published);
26460
+ await writeWikiPolicy(root, readDoc);
26461
+ return result(config2, outcome);
26462
+ };
26419
26463
  const old = await readConfigFile(root);
26420
- if (old !== void 0) return existing(old);
26464
+ if (old !== void 0) {
26465
+ const legacy = legacySchemaVersion(old);
26466
+ return legacy === void 0 ? existing(old) : replaceLegacy(old, legacy);
26467
+ }
26421
26468
  if (first.trackedConfig) throw new InitError("CONFIG_DELETED", t2("init.configDeleted"));
26422
26469
  const checkRecords = async () => {
26423
26470
  if (await fileInfo(join9(root, "specs"))) throw new InitError("EXISTING_RECORDS", t2("init.existingSpecs"));
@@ -26427,8 +26474,6 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
26427
26474
  });
26428
26475
  if (entries.some((name) => !/^\.init-[a-f0-9-]+\.tmp$/.test(name))) throw new InitError("EXISTING_RECORDS", t2("init.orphanStore"));
26429
26476
  };
26430
- const config2 = { schemaVersion: SCHEMA_VERSION, baseline: first.state.head.commit ? { kind: "commit", objectFormat: first.state.repository.objectFormat, commit: first.state.head.commit } : { kind: "empty" } };
26431
- const text2 = JSON.stringify(config2, null, 2) + "\n";
26432
26477
  const recheck = async () => {
26433
26478
  await checkRecords();
26434
26479
  await repo.checkIgnore(root);
@@ -26446,13 +26491,18 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
26446
26491
  }
26447
26492
  throw error62;
26448
26493
  }
26449
- const published = async () => {
26450
- if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text2) throw new InitError("INPUT_CHANGED_AFTER_WRITE", t2("init.changedAfterWrite"));
26451
- };
26452
- await published();
26453
- await applyAgentDocs(root, docsPlan, published);
26454
- await writeWikiPolicy(root, readDoc);
26455
- return result(config2, "created");
26494
+ return finish("created");
26495
+ }
26496
+ function legacySchemaVersion(text2) {
26497
+ let value;
26498
+ try {
26499
+ value = JSON.parse(text2);
26500
+ } catch {
26501
+ return void 0;
26502
+ }
26503
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
26504
+ const version2 = value.schemaVersion;
26505
+ return Number.isInteger(version2) && version2 < SCHEMA_VERSION ? version2 : void 0;
26456
26506
  }
26457
26507
  async function writeWikiPolicy(root, readDoc) {
26458
26508
  if (await fileInfo(join9(root, ...WIKI_DIR.split("/")))) return;
@@ -26470,24 +26520,30 @@ async function writeWikiPolicy(root, readDoc) {
26470
26520
 
26471
26521
  // src/commands/init.ts
26472
26522
  async function runInit(options, version2) {
26523
+ const cancel = new AbortController();
26524
+ const update = updateCheckDisabled(process.env) ? disabledUpdate : resolveUpdate(version2, fetchLatestVersion, cancel.signal);
26473
26525
  try {
26474
26526
  const dto = await initializeSpecProject(
26475
26527
  process.cwd(),
26476
26528
  options.dryRun,
26477
26529
  process.env,
26478
26530
  void 0,
26479
- { version: version2, agent: options.agent, remove: options.removeAgents, skip: options.skipAgents }
26531
+ { version: version2, agent: options.agent, remove: options.removeAgents, skip: options.skipAgents },
26532
+ void 0,
26533
+ update
26480
26534
  );
26481
26535
  if (!dto.ok) throw new Error("unreachable");
26482
26536
  const docs = dto.agentDocs.mode === "skip" ? t2("init.text.skipped") : dto.agentDocs.paths.join(", ") + (dto.agentDocs.mode === "remove" ? " (" + t2("init.text.blockRemoved") + ")" : dto.outcome === "planned" ? " (" + t2("init.text.blockPlanned") + ")" : " (" + t2("init.text.blockUpdated") + ")");
26537
+ const newer = dto.install ? t2("init.text.updateAvailable", { version: dto.update.latestVersion, command: dto.install.npmGlobal }) + "\n" : "";
26483
26538
  process.stdout.write(options.format === "text" ? `${dto.outcome}: ${dto.rootPath}/.gitifact/config.json
26484
26539
  ${t2("init.text.storage")}: schemaVersion ${dto.schemaVersion}
26485
26540
  ${t2("init.text.agentDocs")}: ${docs}
26486
- ` : JSON.stringify(dto) + "\n");
26541
+ ${newer}` : JSON.stringify(dto) + "\n");
26487
26542
  } catch (error62) {
26543
+ cancel.abort();
26488
26544
  const known = error62 instanceof InitError || error62 instanceof RepositoryReadError;
26489
26545
  const failure2 = { code: known ? error62.code : "INIT_FAILED", message: known ? error62.message : t2("init.failed") };
26490
- process.stderr.write(options.format === "text" ? failure2.code + ": " + failure2.message + "\n" : JSON.stringify(projectInitV4.parse({ contract: "project-init", version: 4, ok: false, error: failure2 })) + "\n");
26546
+ process.stderr.write(options.format === "text" ? failure2.code + ": " + failure2.message + "\n" : JSON.stringify(projectInitV5.parse({ contract: "project-init", version: 5, ok: false, error: failure2 })) + "\n");
26491
26547
  process.exitCode = 1;
26492
26548
  }
26493
26549
  }
@@ -26786,7 +26842,7 @@ async function discardAgentInput(root, file2, controls = {}) {
26786
26842
 
26787
26843
  // src/commands/spec-preview-commit.ts
26788
26844
  import { randomUUID as randomUUID6 } from "node:crypto";
26789
- import { readFile as readFile10, mkdir as mkdir6, open as open4, rename as rename3, unlink as unlink5, rmdir as rmdir2, writeFile as writeFile4 } from "node:fs/promises";
26845
+ import { readFile as readFile10, mkdir as mkdir6, open as open4, rename as rename4, unlink as unlink5, rmdir as rmdir2, writeFile as writeFile4 } from "node:fs/promises";
26790
26846
  import { join as join13 } from "node:path";
26791
26847
 
26792
26848
  // src/commands/spec-commit-files.ts
@@ -26985,7 +27041,7 @@ async function previewCommit(cwd, action, input2) {
26985
27041
  await indexLock.writeFile(await readFile10(temporary));
26986
27042
  await indexLock.sync();
26987
27043
  await indexLock.close();
26988
- await rename3(indexPath + ".lock", indexPath);
27044
+ await rename4(indexPath + ".lock", indexPath);
26989
27045
  indexLock = void 0;
26990
27046
  return { outcome: "committed", commit: after.head, paths: actual, requirements: plan.requirements, pushed: false };
26991
27047
  } catch (error62) {
@@ -27016,7 +27072,7 @@ async function previewCommit(cwd, action, input2) {
27016
27072
 
27017
27073
  // src/commands/spec-commit.ts
27018
27074
  import { createHash as createHash8, randomUUID as randomUUID7 } from "node:crypto";
27019
- import { mkdir as mkdir7, open as open5, readFile as readFile11, rename as rename4, rmdir as rmdir3, unlink as unlink6, writeFile as writeFile5 } from "node:fs/promises";
27075
+ import { mkdir as mkdir7, open as open5, readFile as readFile11, rename as rename5, rmdir as rmdir3, unlink as unlink6, writeFile as writeFile5 } from "node:fs/promises";
27020
27076
  import { join as join14 } from "node:path";
27021
27077
  var fields = ["reasons", "paths", "message", "authorization", "requirements", "policyFiles", "expected"];
27022
27078
  var integration = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"];
@@ -27123,7 +27179,7 @@ async function specCommit(cwd, input2, dryRun) {
27123
27179
  if (e.code === "EEXIST") fail6(t2("commit.busy", { path: busy }));
27124
27180
  throw e;
27125
27181
  }
27126
- await previewTransaction(cwd, current.stamp, async () => ({ writes, data: {}, recheck: c.recheck }), rename4, async (published) => {
27182
+ await previewTransaction(cwd, current.stamp, async () => ({ writes, data: {}, recheck: c.recheck }), rename5, async (published) => {
27127
27183
  let commitStarted = false;
27128
27184
  try {
27129
27185
  const lock = indexLock = await open5(indexPath + ".lock", "wx", 384);
@@ -27173,7 +27229,7 @@ async function specCommit(cwd, input2, dryRun) {
27173
27229
  await lock.writeFile(await readFile11(temporary));
27174
27230
  await lock.sync();
27175
27231
  await lock.close();
27176
- await rename4(indexPath + ".lock", indexPath);
27232
+ await rename5(indexPath + ".lock", indexPath);
27177
27233
  indexLock = void 0;
27178
27234
  committed = { commit: after.head, paths: actual };
27179
27235
  } catch (error62) {
@@ -27293,7 +27349,7 @@ function narrowWorking(working, options, inputs) {
27293
27349
  }
27294
27350
 
27295
27351
  // src/commands/migrate.ts
27296
- import { lstat as lstat10, readdir as readdir6, readFile as readFile13, rename as rename5, writeFile as writeFile6, unlink as unlink7 } from "node:fs/promises";
27352
+ import { lstat as lstat10, readdir as readdir6, readFile as readFile13, rename as rename6, writeFile as writeFile6, unlink as unlink7 } from "node:fs/promises";
27297
27353
  import { join as join16 } from "node:path";
27298
27354
  import { randomBytes as randomBytes3 } from "node:crypto";
27299
27355
  var operations2 = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"];
@@ -27384,13 +27440,13 @@ async function migrateStore(cwd, dryRun = false) {
27384
27440
  ]
27385
27441
  });
27386
27442
  if (dryRun) return result("planned");
27387
- await rename5(from, to);
27443
+ await rename6(from, to);
27388
27444
  for (const r of rewrites) {
27389
27445
  const full = join16(root, r.path);
27390
27446
  const temp = join16(root, ".gitifact", "spec", ".gitifact-migrate-" + randomBytes3(8).toString("hex"));
27391
27447
  await writeFile6(temp, r.content, { flag: "wx" });
27392
27448
  try {
27393
- await rename5(temp, full);
27449
+ await rename6(temp, full);
27394
27450
  } finally {
27395
27451
  await unlink7(temp).catch(() => {
27396
27452
  });
@@ -27410,16 +27466,16 @@ async function runMigrate(options) {
27410
27466
  }
27411
27467
 
27412
27468
  // src/main.ts
27413
- var program2 = new Command().name("gitifact").description(t2("help.program")).version("0.5.0").allowExcessArguments(false).addHelpText("after", "\n" + t2("help.notYet")).action(() => program2.outputHelp());
27469
+ var program2 = new Command().name("gitifact").description(t2("help.program")).version("0.5.1").allowExcessArguments(false).addHelpText("after", "\n" + t2("help.notYet")).action(() => program2.outputHelp());
27414
27470
  program2.command("status").description(t2("help.status")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action(async (options) => {
27415
27471
  await runStatus(options.format);
27416
27472
  });
27417
- program2.command("browser").description(t2("help.browser")).allowExcessArguments(false).option("--port <port>", t2("help.browserPort"), parsePort, 0).option("--dev", t2("help.browserDev")).option("--no-update-check", t2("help.browserNoUpdateCheck")).action((options) => runBrowser(options, "0.5.0"));
27418
- program2.command("init").description(t2("help.init")).allowExcessArguments(false).option("--dry-run", t2("help.initDryRun")).addOption(new Option("--agent <agent>", t2("help.initAgent")).choices([...agentPresetNames])).addOption(new Option("--remove-agents", t2("help.initRemoveAgents")).conflicts("skipAgents")).option("--skip-agents", t2("help.initSkipAgents")).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action((options) => runInit(options, "0.5.0"));
27473
+ program2.command("browser").description(t2("help.browser")).allowExcessArguments(false).option("--port <port>", t2("help.browserPort"), parsePort, 0).option("--dev", t2("help.browserDev")).option("--no-update-check", t2("help.browserNoUpdateCheck")).action((options) => runBrowser(options, "0.5.1"));
27474
+ program2.command("init").description(t2("help.init")).allowExcessArguments(false).option("--dry-run", t2("help.initDryRun")).addOption(new Option("--agent <agent>", t2("help.initAgent")).choices([...agentPresetNames])).addOption(new Option("--remove-agents", t2("help.initRemoveAgents")).conflicts("skipAgents")).option("--skip-agents", t2("help.initSkipAgents")).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action((options) => runInit(options, "0.5.1"));
27419
27475
  program2.command("docs").description(t2("help.docs")).argument("[topic]", t2("help.docsTopic")).allowExcessArguments(false).action(async (topic) => {
27420
27476
  await runDocs(topic);
27421
27477
  });
27422
- program2.command("update").description(t2("help.update")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).option("--commit", t2("help.updateCommit")).action((options) => runUpdate(options, "0.5.0"));
27478
+ program2.command("update").description(t2("help.update")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).option("--commit", t2("help.updateCommit")).action((options) => runUpdate(options, "0.5.1"));
27423
27479
  program2.command("migrate").description(t2("help.migrate")).allowExcessArguments(false).option("--dry-run", t2("help.migrateDryRun")).action(runMigrate);
27424
27480
  var spec = program2.command("spec").description(t2("help.spec"));
27425
27481
  var replaced = t2("help.deprecated");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitifact",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Git-backed requirements and change history for coding agents.",
5
5
  "license": "MIT",
6
6
  "repository": {