gitifact 0.3.2 → 0.4.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/README.md +8 -1
- package/dist/browser/assets/Markdown-BG_9T3yA.js +68 -0
- package/dist/browser/assets/MetadataListItem-BJjmYUP-.js +1 -0
- package/dist/browser/assets/about-C5lrF_v9.js +3 -0
- package/dist/browser/assets/changelog-CxmMo2wk.css +1 -0
- package/dist/browser/assets/changelog-hNvOtw70.js +2 -0
- package/dist/browser/assets/{contributors._email-bq12TRAr.js → contributors._email-CwG6z4oO.js} +1 -1
- package/dist/browser/assets/{contributors.index-eTu4P306.js → contributors.index-B9l1YPjl.js} +1 -1
- package/dist/browser/assets/{features._featureId-CGRWLMyZ.js → features._featureId-uB5QcPIl.js} +1 -1
- package/dist/browser/assets/{features.index-_wXeEia1.js → features.index-DzLFYkRG.js} +1 -1
- package/dist/browser/assets/git-DJKAcbnl.js +1 -0
- package/dist/browser/assets/{guides._documentId-D3RCTjtd.js → guides._documentId-DHM6effA.js} +1 -1
- package/dist/browser/assets/{guides.index-CFMN9ggJ.js → guides.index-BfJqdqJd.js} +1 -1
- package/dist/browser/assets/index-jaVGAf81.js +56 -0
- package/dist/browser/assets/{page-header-CYf1yQV1.js → page-header-DI5eoQC1.js} +4 -4
- package/dist/browser/assets/product-YuwMeOC0.js +8 -0
- package/dist/browser/assets/{product.index-AF24IXK3.js → product.index-RgfLdFqG.js} +1 -1
- package/dist/browser/assets/request-state-DpUKcy6G.js +1 -0
- package/dist/browser/assets/{requirements-DpTMK_Uu.js → requirements-BMLc9Fpl.js} +1 -1
- package/dist/browser/assets/{routes-jgWFqeRv.js → routes-XUldGkLf.js} +1 -1
- package/dist/browser/index.html +6 -5
- package/dist/i18n/ko/block.md +2 -1
- package/dist/i18n/ko/changelog.md +12 -0
- package/dist/i18n/ko/docs/workflow.md +1 -1
- package/dist/main.js +289 -34
- package/package.json +1 -1
- package/dist/browser/assets/Markdown-C8BT0YZz.js +0 -68
- package/dist/browser/assets/about-DMFBT-sA.js +0 -3
- package/dist/browser/assets/git-CTULSVR7.js +0 -1
- package/dist/browser/assets/index-Cl1J8uRf.js +0 -56
- package/dist/browser/assets/product-BxZktNQM.js +0 -8
- package/dist/browser/assets/request-state-DzkYXwJR.js +0 -1
package/dist/main.js
CHANGED
|
@@ -4030,6 +4030,70 @@ function comparePreviewBundles(before, after) {
|
|
|
4030
4030
|
return { specChanges: specs.specChanges, changes: [...specs.changes, ...compareDocumentSets(a.documents, b.documents)] };
|
|
4031
4031
|
}
|
|
4032
4032
|
|
|
4033
|
+
// ../../packages/core/dist/formats/changelog.js
|
|
4034
|
+
var changelogSections = ["added", "changed", "removed", "fixed"];
|
|
4035
|
+
var versionLine = /^## (\d+)\.(\d+)\.(\d+) - (\d{4})-(\d{2})-(\d{2})$/;
|
|
4036
|
+
var sectionLine = /^### (Added|Changed|Removed|Fixed)$/;
|
|
4037
|
+
var itemLine = /^- (\S.*)$/;
|
|
4038
|
+
var realDate = (year, month, day) => {
|
|
4039
|
+
const date5 = new Date(Date.UTC(year, month - 1, day));
|
|
4040
|
+
return date5.getUTCFullYear() === year && date5.getUTCMonth() === month - 1 && date5.getUTCDate() === day;
|
|
4041
|
+
};
|
|
4042
|
+
function parseChangelog(text2) {
|
|
4043
|
+
const entries = [];
|
|
4044
|
+
let previous;
|
|
4045
|
+
let entry2;
|
|
4046
|
+
let section;
|
|
4047
|
+
const fail8 = (line, key, values = {}) => new InitError("INVALID_CHANGELOG", t("changelog.atLine", { line, reason: t(key, values) }));
|
|
4048
|
+
const lines = text2.replace(/\r\n/g, "\n").split("\n");
|
|
4049
|
+
const close = (line) => {
|
|
4050
|
+
if (entry2 && changelogSections.every((name) => entry2[name].length === 0))
|
|
4051
|
+
throw fail8(line, "changelog.emptyVersion", { version: entry2.version });
|
|
4052
|
+
};
|
|
4053
|
+
lines.forEach((raw, index) => {
|
|
4054
|
+
const line = index + 1;
|
|
4055
|
+
if (raw.trim() === "")
|
|
4056
|
+
return;
|
|
4057
|
+
const version2 = versionLine.exec(raw);
|
|
4058
|
+
if (version2) {
|
|
4059
|
+
close(line);
|
|
4060
|
+
const core = [Number(version2[1]), Number(version2[2]), Number(version2[3])];
|
|
4061
|
+
if (!realDate(Number(version2[4]), Number(version2[5]), Number(version2[6])))
|
|
4062
|
+
throw fail8(line, "changelog.invalidDate", { text: raw });
|
|
4063
|
+
if (previous && !(core[0] < previous[0] || core[0] === previous[0] && (core[1] < previous[1] || core[1] === previous[1] && core[2] < previous[2]))) {
|
|
4064
|
+
throw fail8(line, "changelog.order", { version: core.join(".") });
|
|
4065
|
+
}
|
|
4066
|
+
previous = core;
|
|
4067
|
+
section = void 0;
|
|
4068
|
+
entry2 = { version: core.join("."), date: version2[4] + "-" + version2[5] + "-" + version2[6], added: [], changed: [], removed: [], fixed: [] };
|
|
4069
|
+
entries.push(entry2);
|
|
4070
|
+
return;
|
|
4071
|
+
}
|
|
4072
|
+
const heading = sectionLine.exec(raw);
|
|
4073
|
+
if (heading) {
|
|
4074
|
+
if (!entry2)
|
|
4075
|
+
throw fail8(line, "changelog.sectionBeforeVersion");
|
|
4076
|
+
const name = heading[1].toLowerCase();
|
|
4077
|
+
if (entry2[name].length > 0)
|
|
4078
|
+
throw fail8(line, "changelog.duplicateSection", { section: heading[1] });
|
|
4079
|
+
section = name;
|
|
4080
|
+
return;
|
|
4081
|
+
}
|
|
4082
|
+
const item = itemLine.exec(raw);
|
|
4083
|
+
if (item) {
|
|
4084
|
+
if (!entry2 || !section)
|
|
4085
|
+
throw fail8(line, "changelog.itemOutsideSection");
|
|
4086
|
+
entry2[section].push(item[1].trimEnd());
|
|
4087
|
+
return;
|
|
4088
|
+
}
|
|
4089
|
+
throw fail8(line, "changelog.unknownLine", { text: raw });
|
|
4090
|
+
});
|
|
4091
|
+
close(lines.length);
|
|
4092
|
+
if (entries.length === 0)
|
|
4093
|
+
throw fail8(1, "changelog.noVersions");
|
|
4094
|
+
return entries;
|
|
4095
|
+
}
|
|
4096
|
+
|
|
4033
4097
|
// ../../packages/core/dist/use-cases/edit-spec-preview.js
|
|
4034
4098
|
var fail2 = (message) => {
|
|
4035
4099
|
throw new SpecPreviewError(message);
|
|
@@ -24380,16 +24444,7 @@ var repositoryStatusFailureV1 = external_exports.strictObject({
|
|
|
24380
24444
|
});
|
|
24381
24445
|
var repositoryStatusV1 = external_exports.union([repositoryStatusSuccessV1, repositoryStatusFailureV1]);
|
|
24382
24446
|
|
|
24383
|
-
// ../../packages/contracts/dist/versions/browser-
|
|
24384
|
-
var browserSessionV1 = external_exports.strictObject({
|
|
24385
|
-
contract: external_exports.literal("browser-session"),
|
|
24386
|
-
version: external_exports.literal(1),
|
|
24387
|
-
sessionId: external_exports.uuid(),
|
|
24388
|
-
repository: external_exports.strictObject({
|
|
24389
|
-
key: external_exports.string().regex(/^repo:[0-9a-f]{64}$/),
|
|
24390
|
-
worktreeKey: external_exports.string().regex(/^worktree:[0-9a-f]{64}$/)
|
|
24391
|
-
})
|
|
24392
|
-
});
|
|
24447
|
+
// ../../packages/contracts/dist/versions/browser-http-error-v1.js
|
|
24393
24448
|
var browserHttpErrorV1 = external_exports.strictObject({
|
|
24394
24449
|
contract: external_exports.literal("browser-http-error"),
|
|
24395
24450
|
version: external_exports.literal(1),
|
|
@@ -24489,6 +24544,42 @@ var changelogV1 = external_exports.strictObject({
|
|
|
24489
24544
|
}
|
|
24490
24545
|
});
|
|
24491
24546
|
|
|
24547
|
+
// ../../packages/contracts/dist/versions/browser-session-v2.js
|
|
24548
|
+
var release = external_exports.string().regex(/^\d+\.\d+\.\d+$/);
|
|
24549
|
+
var updateStateV1 = external_exports.strictObject({
|
|
24550
|
+
status: external_exports.enum(["checking", "available", "up-to-date", "unavailable", "disabled"]),
|
|
24551
|
+
latestVersion: release.nullable()
|
|
24552
|
+
}).refine((value) => (value.status === "available" || value.status === "up-to-date") === (value.latestVersion !== null), "latestVersion is set exactly when the check produced a result.");
|
|
24553
|
+
var browserSessionV2 = external_exports.strictObject({
|
|
24554
|
+
contract: external_exports.literal("browser-session"),
|
|
24555
|
+
version: external_exports.literal(2),
|
|
24556
|
+
sessionId: external_exports.uuid(),
|
|
24557
|
+
repository: external_exports.strictObject({
|
|
24558
|
+
key: external_exports.string().regex(/^repo:[0-9a-f]{64}$/),
|
|
24559
|
+
worktreeKey: external_exports.string().regex(/^worktree:[0-9a-f]{64}$/)
|
|
24560
|
+
}),
|
|
24561
|
+
// The running CLI, the same value as `gitifact --version`. A development build may carry a pre-release suffix.
|
|
24562
|
+
cliVersion: external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/),
|
|
24563
|
+
update: updateStateV1
|
|
24564
|
+
});
|
|
24565
|
+
|
|
24566
|
+
// ../../packages/contracts/dist/versions/update-v1.js
|
|
24567
|
+
var updateV1 = external_exports.discriminatedUnion("ok", [
|
|
24568
|
+
external_exports.strictObject({
|
|
24569
|
+
contract: external_exports.literal("update"),
|
|
24570
|
+
version: external_exports.literal(1),
|
|
24571
|
+
ok: external_exports.literal(true),
|
|
24572
|
+
cliVersion: external_exports.string().min(1),
|
|
24573
|
+
update: updateStateV1,
|
|
24574
|
+
// Present only when a newer release exists. The command is for npm global installs; other installs differ.
|
|
24575
|
+
install: external_exports.strictObject({ npmGlobal: external_exports.string().min(1) }).nullable(),
|
|
24576
|
+
// refreshed: blocks whose version line differed were rewritten. current: every block already matched.
|
|
24577
|
+
// not-initialized: no .gitifact config here, so only the version check ran. no-block: no file carries a block.
|
|
24578
|
+
agentDocs: external_exports.strictObject({ state: external_exports.enum(["refreshed", "current", "not-initialized", "no-block"]), paths: external_exports.array(external_exports.string()) })
|
|
24579
|
+
}),
|
|
24580
|
+
external_exports.strictObject({ contract: external_exports.literal("update"), version: external_exports.literal(1), ok: external_exports.literal(false), error: external_exports.strictObject({ code: external_exports.string(), message: external_exports.string() }) })
|
|
24581
|
+
]);
|
|
24582
|
+
|
|
24492
24583
|
// src/shared/i18n/ko/messages.json
|
|
24493
24584
|
var messages_default2 = {
|
|
24494
24585
|
"help.program": "\uD504\uB85C\uC81D\uD2B8\uC758 \uC694\uAD6C\uC0AC\uD56D\uACFC \uACB0\uC815 \uC774\uB825\uC744 Git\uC5D0 \uB0A8\uAE30\uB294 \uB3C4\uAD6C",
|
|
@@ -24717,7 +24808,24 @@ var messages_default2 = {
|
|
|
24717
24808
|
"docs.summary.spec": "\uC0AC\uC6A9\uC790 \uC2A4\uD1A0\uB9AC\xB7\uC218\uC6A9 \uC870\uAC74 \uD615\uC2DD, ID \uADDC\uCE59, spec save \uC785\uB825",
|
|
24718
24809
|
"docs.summary.design": "design.md \uBAA9\uCC28, \uCC38\uC870 \uC8FC\uC11D, \uAC1C\uC815 \uBC29\uC2DD",
|
|
24719
24810
|
"docs.summary.product": "PRODUCT.md\uC640 guides \uBB38\uC11C\uC758 \uC5ED\uD560\uACFC \uC800\uC7A5 \uBA85\uB839",
|
|
24720
|
-
"docs.summary.commit": "spec commit \uC785\uB825, \uC774\uC720 \uAE30\uB85D, \uC2E4\uD328 \uD6C4 \uBCF5\uAD6C"
|
|
24811
|
+
"docs.summary.commit": "spec commit \uC785\uB825, \uC774\uC720 \uAE30\uB85D, \uC2E4\uD328 \uD6C4 \uBCF5\uAD6C",
|
|
24812
|
+
"help.browserNoUpdateCheck": "\uC0C8 \uBC84\uC804 \uD655\uC778\uC744 \uC704\uD55C npm \uB808\uC9C0\uC2A4\uD2B8\uB9AC \uC870\uD68C\uB97C \uB054 (GITIFACT_NO_UPDATE_CHECK\uC640 \uAC19\uC74C)",
|
|
24813
|
+
"help.update": "\uC0C8 \uBC84\uC804 \uD655\uC778\uACFC \uC124\uCE58 \uBC29\uBC95 \uC548\uB0B4, \uD504\uB85C\uC81D\uD2B8 \uC9C0\uCE68 \uD30C\uC77C\uC758 GITIFACT \uBE14\uB85D\uC744 \uD604\uC7AC \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0",
|
|
24814
|
+
"server.badLanguage": "\uC5B8\uC5B4 \uCF54\uB4DC\uB97C \uD655\uC778\uD558\uC138\uC694.",
|
|
24815
|
+
"server.changelogNotFound": "\uD328\uCE58\uB178\uD2B8\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
|
|
24816
|
+
"server.changelogUnreadable": "\uD328\uCE58\uB178\uD2B8\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
|
|
24817
|
+
"update.text.current": "\uD604\uC7AC \uBC84\uC804: {version}",
|
|
24818
|
+
"update.text.available": "\uC0C8 \uBC84\uC804: {version}",
|
|
24819
|
+
"update.text.upToDate": "\uCD5C\uC2E0 \uBC84\uC804\uC744 \uC0AC\uC6A9 \uC911\uC785\uB2C8\uB2E4.",
|
|
24820
|
+
"update.text.disabled": "\uC0C8 \uBC84\uC804 \uD655\uC778\uC774 \uAEBC\uC838 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
24821
|
+
"update.text.unavailable": "\uC0C8 \uBC84\uC804\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB124\uD2B8\uC6CC\uD06C \uC5F0\uACB0\uC744 \uD655\uC778\uD558\uC138\uC694.",
|
|
24822
|
+
"update.text.install": "npm \uC804\uC5ED \uC124\uCE58\uC6A9: {command}",
|
|
24823
|
+
"update.text.afterInstall": "\uC124\uCE58\uD55C \uB4A4 gitifact update\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uBA74 \uC9C0\uCE68 \uBE14\uB85D\uC774 \uC0C8 \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0\uB429\uB2C8\uB2E4.",
|
|
24824
|
+
"update.text.blockRefreshed": "\uC9C0\uCE68 \uBE14\uB85D \uAC31\uC2E0: {paths}",
|
|
24825
|
+
"update.text.blockCurrent": "\uC9C0\uCE68 \uBE14\uB85D\uC740 \uC774\uBBF8 \uD604\uC7AC \uBC84\uC804\uC785\uB2C8\uB2E4: {paths}",
|
|
24826
|
+
"update.text.noBlock": "GITIFACT \uBE14\uB85D\uC774 \uC788\uB294 \uC9C0\uCE68 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. gitifact init\uC73C\uB85C \uC124\uCE58\uD558\uC138\uC694.",
|
|
24827
|
+
"update.text.notInitialized": "\uCD08\uAE30\uD654\uB41C \uD504\uB85C\uC81D\uD2B8\uAC00 \uC544\uB2C8\uC5B4\uC11C \uBC84\uC804\uB9CC \uD655\uC778\uD588\uC2B5\uB2C8\uB2E4.",
|
|
24828
|
+
"update.failed": "\uC5C5\uB370\uC774\uD2B8 \uD655\uC778\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."
|
|
24721
24829
|
};
|
|
24722
24830
|
|
|
24723
24831
|
// src/shared/i18n/index.ts
|
|
@@ -24832,17 +24940,63 @@ function contentType(path3) {
|
|
|
24832
24940
|
|
|
24833
24941
|
// src/server/status-session.ts
|
|
24834
24942
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
24835
|
-
|
|
24836
|
-
|
|
24837
|
-
|
|
24838
|
-
|
|
24839
|
-
|
|
24840
|
-
|
|
24841
|
-
|
|
24943
|
+
|
|
24944
|
+
// src/shared/update-check.ts
|
|
24945
|
+
var updateCheckTimeoutMs = 3e3;
|
|
24946
|
+
var release2 = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
24947
|
+
var running = /^(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?$/;
|
|
24948
|
+
function isNewerRelease(latest, current) {
|
|
24949
|
+
const next = release2.exec(latest);
|
|
24950
|
+
const now = running.exec(current);
|
|
24951
|
+
if (!next || !now) return false;
|
|
24952
|
+
for (let index = 1; index <= 3; index++) {
|
|
24953
|
+
const difference = Number(next[index]) - Number(now[index]);
|
|
24954
|
+
if (difference !== 0) return difference > 0;
|
|
24955
|
+
}
|
|
24956
|
+
return now[4] !== void 0;
|
|
24957
|
+
}
|
|
24958
|
+
var updateCheckDisabled = (env, flagged = false) => flagged || env.GITIFACT_NO_UPDATE_CHECK !== void 0 && env.GITIFACT_NO_UPDATE_CHECK !== "" && env.GITIFACT_NO_UPDATE_CHECK !== "0";
|
|
24959
|
+
var checkingUpdate = { status: "checking", latestVersion: null };
|
|
24960
|
+
var disabledUpdate = { status: "disabled", latestVersion: null };
|
|
24961
|
+
async function resolveUpdate(current, fetchLatest, signal, timeoutMs = updateCheckTimeoutMs) {
|
|
24962
|
+
const controller = new AbortController();
|
|
24963
|
+
const abort = () => controller.abort();
|
|
24964
|
+
const timer = setTimeout(abort, timeoutMs);
|
|
24965
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
24966
|
+
if (signal?.aborted) controller.abort();
|
|
24967
|
+
try {
|
|
24968
|
+
const latest = await Promise.race([
|
|
24969
|
+
fetchLatest(controller.signal),
|
|
24970
|
+
new Promise((_resolve, reject) => {
|
|
24971
|
+
if (controller.signal.aborted) reject(new Error("aborted"));
|
|
24972
|
+
else controller.signal.addEventListener("abort", () => reject(new Error("aborted")), { once: true });
|
|
24973
|
+
})
|
|
24974
|
+
]);
|
|
24975
|
+
if (typeof latest !== "string" || !release2.test(latest)) return { status: "unavailable", latestVersion: null };
|
|
24976
|
+
return { status: isNewerRelease(latest, current) ? "available" : "up-to-date", latestVersion: latest };
|
|
24977
|
+
} catch {
|
|
24978
|
+
return { status: "unavailable", latestVersion: null };
|
|
24979
|
+
} finally {
|
|
24980
|
+
clearTimeout(timer);
|
|
24981
|
+
signal?.removeEventListener("abort", abort);
|
|
24982
|
+
}
|
|
24983
|
+
}
|
|
24984
|
+
var npmGlobalInstall = (version2) => "npm install -g gitifact@" + version2;
|
|
24985
|
+
|
|
24986
|
+
// src/server/status-session.ts
|
|
24987
|
+
function createStatusSession(initial, read, cliVersion = "0.0.0") {
|
|
24988
|
+
const identity2 = { sessionId: randomUUID2(), repository: { key: initial.repository.key, worktreeKey: initial.repository.worktreeKey } };
|
|
24989
|
+
let update = disabledUpdate;
|
|
24842
24990
|
let latest = initial;
|
|
24843
24991
|
let pending;
|
|
24844
24992
|
return {
|
|
24845
|
-
session
|
|
24993
|
+
// The identity never changes; only the update state moves (checking → a final state), so the session is built per read.
|
|
24994
|
+
get session() {
|
|
24995
|
+
return browserSessionV2.parse({ contract: "browser-session", version: 2, ...identity2, cliVersion, update });
|
|
24996
|
+
},
|
|
24997
|
+
setUpdate(next) {
|
|
24998
|
+
update = next;
|
|
24999
|
+
},
|
|
24846
25000
|
get latest() {
|
|
24847
25001
|
return latest;
|
|
24848
25002
|
},
|
|
@@ -24854,7 +25008,7 @@ function createStatusSession(initial, read) {
|
|
|
24854
25008
|
pending = (async () => {
|
|
24855
25009
|
try {
|
|
24856
25010
|
const next = await read();
|
|
24857
|
-
if (next.repository.key !==
|
|
25011
|
+
if (next.repository.key !== identity2.repository.key || next.repository.worktreeKey !== identity2.repository.worktreeKey) {
|
|
24858
25012
|
throw new RepositoryReadError("REPOSITORY_CHANGED");
|
|
24859
25013
|
}
|
|
24860
25014
|
latest = next;
|
|
@@ -25432,6 +25586,10 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
|
|
|
25432
25586
|
}
|
|
25433
25587
|
|
|
25434
25588
|
// src/server/browser-server.ts
|
|
25589
|
+
var readBundledChangelog = (language) => readFile4(new URL("./i18n/" + language + "/changelog.md", import.meta.url), "utf8").catch((error62) => {
|
|
25590
|
+
if (error62.code === "ENOENT") return null;
|
|
25591
|
+
throw error62;
|
|
25592
|
+
});
|
|
25435
25593
|
async function startBrowserServer(options) {
|
|
25436
25594
|
const controller = new AbortController();
|
|
25437
25595
|
const onAbort = () => controller.abort();
|
|
@@ -25451,11 +25609,13 @@ async function startBrowserServer(options) {
|
|
|
25451
25609
|
options.signal?.removeEventListener("abort", onAbort);
|
|
25452
25610
|
throw error62;
|
|
25453
25611
|
}
|
|
25454
|
-
const store = createStatusSession(initial, () => read(controller.signal));
|
|
25455
|
-
const
|
|
25612
|
+
const store = createStatusSession(initial, () => read(controller.signal), options.cliVersion);
|
|
25613
|
+
const sessionId = store.session.sessionId;
|
|
25614
|
+
const readChangelog = options.readChangelog ?? readBundledChangelog;
|
|
25615
|
+
let updatePending;
|
|
25456
25616
|
let closing = false;
|
|
25457
25617
|
let origin = "";
|
|
25458
|
-
const readSpecs = createSpecBrowserReader(initial.repository.rootPath,
|
|
25618
|
+
const readSpecs = createSpecBrowserReader(initial.repository.rootPath, sessionId, options.env);
|
|
25459
25619
|
function json2(response, status, value) {
|
|
25460
25620
|
response.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" });
|
|
25461
25621
|
response.end(JSON.stringify(value) + "\n");
|
|
@@ -25493,7 +25653,7 @@ async function startBrowserServer(options) {
|
|
|
25493
25653
|
const api = path3 === "/api" || path3.startsWith("/api/");
|
|
25494
25654
|
if (api) {
|
|
25495
25655
|
if (request.headers["sec-fetch-site"] === "cross-site" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.crossSite"));
|
|
25496
|
-
if (url2.search && path3 !== "/api/v1/specs") return fail8(response, 400, "BAD_REQUEST", t2("server.noQuery"));
|
|
25656
|
+
if (url2.search && path3 !== "/api/v1/specs" && path3 !== "/api/v1/changelog") return fail8(response, 400, "BAD_REQUEST", t2("server.noQuery"));
|
|
25497
25657
|
if (path3.startsWith("/api/v1/product/assets/")) {
|
|
25498
25658
|
const name = path3.slice("/api/v1/product/assets/".length);
|
|
25499
25659
|
if (request.method !== "GET") {
|
|
@@ -25510,13 +25670,13 @@ async function startBrowserServer(options) {
|
|
|
25510
25670
|
return;
|
|
25511
25671
|
}
|
|
25512
25672
|
const method = path3 === "/api/v1/status/refresh" ? "POST" : "GET";
|
|
25513
|
-
if (!["/api/v1/session", "/api/v1/status", "/api/v1/status/refresh", "/api/v1/specs"].includes(path3)) return fail8(response, 404, "NOT_FOUND", t2("server.apiNotFound"));
|
|
25673
|
+
if (!["/api/v1/session", "/api/v1/status", "/api/v1/status/refresh", "/api/v1/specs", "/api/v1/changelog"].includes(path3)) return fail8(response, 404, "NOT_FOUND", t2("server.apiNotFound"));
|
|
25514
25674
|
if (request.method !== method) {
|
|
25515
25675
|
response.setHeader("Allow", method);
|
|
25516
25676
|
return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
|
|
25517
25677
|
}
|
|
25518
|
-
if (path3 === "/api/v1/session") return json2(response, 200, session);
|
|
25519
|
-
if (request.headers["x-gitifact-session"] !==
|
|
25678
|
+
if (path3 === "/api/v1/session") return json2(response, 200, store.session);
|
|
25679
|
+
if (request.headers["x-gitifact-session"] !== sessionId) return fail8(response, 409, "SESSION_CHANGED", t2("server.sessionChanged"));
|
|
25520
25680
|
if (path3 === "/api/v1/specs") {
|
|
25521
25681
|
const cursor = url2.searchParams.get("cursor") ?? "0";
|
|
25522
25682
|
const head = url2.searchParams.get("head");
|
|
@@ -25528,6 +25688,19 @@ async function startBrowserServer(options) {
|
|
|
25528
25688
|
}
|
|
25529
25689
|
return;
|
|
25530
25690
|
}
|
|
25691
|
+
if (path3 === "/api/v1/changelog") {
|
|
25692
|
+
const language = url2.searchParams.get("lang") ?? defaultLanguage2;
|
|
25693
|
+
if ([...url2.searchParams.keys()].some((key) => key !== "lang") || url2.searchParams.getAll("lang").length > 1 || !/^[a-z]{2}(?:-[A-Z]{2})?$/.test(language)) return fail8(response, 400, "BAD_REQUEST", t2("server.badLanguage"));
|
|
25694
|
+
try {
|
|
25695
|
+
const own2 = await readChangelog(language);
|
|
25696
|
+
const text2 = own2 ?? (language === defaultLanguage2 ? null : await readChangelog(defaultLanguage2));
|
|
25697
|
+
if (text2 === null) return fail8(response, 404, "NOT_FOUND", t2("server.changelogNotFound"));
|
|
25698
|
+
json2(response, 200, changelogV1.parse({ contract: "changelog", version: 1, language: own2 === null ? defaultLanguage2 : language, fallback: own2 === null, entries: parseChangelog(text2) }));
|
|
25699
|
+
} catch (error62) {
|
|
25700
|
+
fail8(response, 503, "INTERNAL_ERROR", error62 instanceof Error ? error62.message : t2("server.changelogUnreadable"));
|
|
25701
|
+
}
|
|
25702
|
+
return;
|
|
25703
|
+
}
|
|
25531
25704
|
if (method === "POST" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.refreshOrigin"));
|
|
25532
25705
|
const value = method === "POST" ? await store.refresh() : store.latest;
|
|
25533
25706
|
if (!response.destroyed) json2(response, value.ok ? 200 : 503, value);
|
|
@@ -25573,6 +25746,12 @@ async function startBrowserServer(options) {
|
|
|
25573
25746
|
const address = server.address();
|
|
25574
25747
|
if (!address || typeof address === "string") throw new Error(t2("server.addressUnknown"));
|
|
25575
25748
|
origin = "http://127.0.0.1:" + address.port;
|
|
25749
|
+
if (options.fetchLatest) {
|
|
25750
|
+
store.setUpdate(checkingUpdate);
|
|
25751
|
+
updatePending = resolveUpdate(store.session.cliVersion, options.fetchLatest, controller.signal, options.updateCheckTimeoutMs).then((state) => {
|
|
25752
|
+
store.setUpdate(state);
|
|
25753
|
+
});
|
|
25754
|
+
}
|
|
25576
25755
|
let resolveClosed;
|
|
25577
25756
|
const closed = new Promise((resolve) => {
|
|
25578
25757
|
resolveClosed = resolve;
|
|
@@ -25588,6 +25767,7 @@ async function startBrowserServer(options) {
|
|
|
25588
25767
|
server.closeAllConnections();
|
|
25589
25768
|
});
|
|
25590
25769
|
await store.pending;
|
|
25770
|
+
await updatePending;
|
|
25591
25771
|
options.signal?.removeEventListener("abort", onAbort);
|
|
25592
25772
|
options.signal?.removeEventListener("abort", closeOnAbort);
|
|
25593
25773
|
resolveClosed();
|
|
@@ -25599,15 +25779,28 @@ async function startBrowserServer(options) {
|
|
|
25599
25779
|
};
|
|
25600
25780
|
options.signal?.addEventListener("abort", closeOnAbort, { once: true });
|
|
25601
25781
|
if (options.signal?.aborted) void close();
|
|
25602
|
-
return { url: origin, session
|
|
25782
|
+
return { url: origin, get session() {
|
|
25783
|
+
return store.session;
|
|
25784
|
+
}, close, closed };
|
|
25603
25785
|
}
|
|
25604
25786
|
|
|
25787
|
+
// src/adapters/registry/latest-version.ts
|
|
25788
|
+
var manifestUrl = "https://registry.npmjs.org/gitifact";
|
|
25789
|
+
var fetchLatestVersion = async (signal) => {
|
|
25790
|
+
const response = await fetch(manifestUrl, { signal, redirect: "error", headers: { Accept: "application/vnd.npm.install-v1+json" } });
|
|
25791
|
+
if (!response.ok) throw new Error("registry status " + response.status);
|
|
25792
|
+
const manifest = await response.json();
|
|
25793
|
+
const latest = manifest["dist-tags"]?.latest;
|
|
25794
|
+
if (typeof latest !== "string") throw new Error("registry answer has no latest tag");
|
|
25795
|
+
return latest;
|
|
25796
|
+
};
|
|
25797
|
+
|
|
25605
25798
|
// src/commands/browser.ts
|
|
25606
25799
|
function parsePort(value) {
|
|
25607
25800
|
if (!/^\d+$/.test(value) || Number(value) > 65535) throw new InvalidArgumentError(t2("browser.invalidPort"));
|
|
25608
25801
|
return Number(value);
|
|
25609
25802
|
}
|
|
25610
|
-
async function runBrowser(options) {
|
|
25803
|
+
async function runBrowser(options, version2) {
|
|
25611
25804
|
const controller = new AbortController();
|
|
25612
25805
|
const stop = () => controller.abort();
|
|
25613
25806
|
process.once("SIGINT", stop);
|
|
@@ -25617,7 +25810,10 @@ async function runBrowser(options) {
|
|
|
25617
25810
|
cwd: process.cwd(),
|
|
25618
25811
|
port: options.port,
|
|
25619
25812
|
dev: options.dev ?? false,
|
|
25620
|
-
signal: controller.signal
|
|
25813
|
+
signal: controller.signal,
|
|
25814
|
+
cliVersion: version2,
|
|
25815
|
+
// --no-update-check or GITIFACT_NO_UPDATE_CHECK keeps the server from contacting the npm registry.
|
|
25816
|
+
...updateCheckDisabled(process.env, options.updateCheck === false) ? {} : { fetchLatest: fetchLatestVersion }
|
|
25621
25817
|
});
|
|
25622
25818
|
if (!controller.signal.aborted) process.stdout.write(server.url + "/\n");
|
|
25623
25819
|
await server.closed;
|
|
@@ -25892,7 +26088,7 @@ async function planAgentDocs(root, options) {
|
|
|
25892
26088
|
return { mode: "remove", paths: paths2, writes };
|
|
25893
26089
|
}
|
|
25894
26090
|
const block = await renderAgentBlock(options.version, options);
|
|
25895
|
-
const { inject, create } = resolveAgentPaths(options.agent, existing);
|
|
26091
|
+
const { inject, create } = options.onlyExisting ? { inject: candidatePaths.filter((path3) => existing.has(path3) && findBlock(existing.get(path3)) && !isWrapperFile(existing.get(path3))), create: null } : resolveAgentPaths(options.agent, existing);
|
|
25896
26092
|
for (const path3 of inject) {
|
|
25897
26093
|
const previous = existing.get(path3);
|
|
25898
26094
|
const next = injectBlock(previous, block, boilerplateFor(path3));
|
|
@@ -26004,6 +26200,64 @@ ${t2("init.text.agentDocs")}: ${docs}
|
|
|
26004
26200
|
}
|
|
26005
26201
|
}
|
|
26006
26202
|
|
|
26203
|
+
// src/commands/update.ts
|
|
26204
|
+
async function refreshBlocks(cwd, version2, env, controls) {
|
|
26205
|
+
const repo = initRepository(cwd, env);
|
|
26206
|
+
let first;
|
|
26207
|
+
let config2;
|
|
26208
|
+
try {
|
|
26209
|
+
first = await repo.inspect();
|
|
26210
|
+
config2 = await readConfigFile(first.state.repository.rootPath);
|
|
26211
|
+
} catch (error62) {
|
|
26212
|
+
if (error62 instanceof RepositoryReadError && error62.code === "NOT_A_REPOSITORY" || error62 instanceof InitError && error62.code === "MIGRATION_REQUIRED") return { state: "not-initialized", paths: [] };
|
|
26213
|
+
throw error62;
|
|
26214
|
+
}
|
|
26215
|
+
if (config2 === void 0) return { state: "not-initialized", paths: [] };
|
|
26216
|
+
const root = first.state.repository.rootPath;
|
|
26217
|
+
const plan = await planAgentDocs(root, { version: version2, onlyExisting: true, ...controls });
|
|
26218
|
+
if (plan.paths.length === 0) return { state: "no-block", paths: [] };
|
|
26219
|
+
if (plan.writes.length === 0) return { state: "current", paths: plan.paths };
|
|
26220
|
+
const unchanged = async () => {
|
|
26221
|
+
if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== config2) throw new InitError("INPUT_CHANGED", t2("init.inputChanged"));
|
|
26222
|
+
};
|
|
26223
|
+
return { state: "refreshed", paths: await applyAgentDocs(root, plan, unchanged) };
|
|
26224
|
+
}
|
|
26225
|
+
async function updateCommand(cwd, version2, env = process.env, controls = {}) {
|
|
26226
|
+
const [update, agentDocs] = await Promise.all([
|
|
26227
|
+
updateCheckDisabled(env) ? disabledUpdate : resolveUpdate(version2, controls.fetchLatest ?? fetchLatestVersion, void 0, controls.timeoutMs),
|
|
26228
|
+
refreshBlocks(cwd, version2, env, controls)
|
|
26229
|
+
]);
|
|
26230
|
+
return updateV1.parse({
|
|
26231
|
+
contract: "update",
|
|
26232
|
+
version: 1,
|
|
26233
|
+
ok: true,
|
|
26234
|
+
cliVersion: version2,
|
|
26235
|
+
update,
|
|
26236
|
+
install: update.status === "available" ? { npmGlobal: npmGlobalInstall(update.latestVersion) } : null,
|
|
26237
|
+
agentDocs
|
|
26238
|
+
});
|
|
26239
|
+
}
|
|
26240
|
+
async function runUpdate(options, version2) {
|
|
26241
|
+
try {
|
|
26242
|
+
const dto = await updateCommand(process.cwd(), version2);
|
|
26243
|
+
if (!dto.ok) throw new Error("unreachable");
|
|
26244
|
+
if (options.format !== "text") {
|
|
26245
|
+
process.stdout.write(JSON.stringify(dto) + "\n");
|
|
26246
|
+
return;
|
|
26247
|
+
}
|
|
26248
|
+
const lines = [t2("update.text.current", { version: dto.cliVersion })];
|
|
26249
|
+
lines.push(dto.update.status === "available" ? t2("update.text.available", { version: dto.update.latestVersion }) : dto.update.status === "up-to-date" ? t2("update.text.upToDate") : dto.update.status === "disabled" ? t2("update.text.disabled") : t2("update.text.unavailable"));
|
|
26250
|
+
if (dto.install) lines.push(t2("update.text.install", { command: dto.install.npmGlobal }), t2("update.text.afterInstall"));
|
|
26251
|
+
lines.push(dto.agentDocs.state === "refreshed" ? t2("update.text.blockRefreshed", { paths: dto.agentDocs.paths.join(", ") }) : dto.agentDocs.state === "current" ? t2("update.text.blockCurrent", { paths: dto.agentDocs.paths.join(", ") }) : dto.agentDocs.state === "no-block" ? t2("update.text.noBlock") : t2("update.text.notInitialized"));
|
|
26252
|
+
process.stdout.write(lines.join("\n") + "\n");
|
|
26253
|
+
} catch (error62) {
|
|
26254
|
+
const known = error62 instanceof InitError || error62 instanceof RepositoryReadError;
|
|
26255
|
+
const failure2 = { code: known ? error62.code : "UPDATE_FAILED", message: known ? error62.message : t2("update.failed") };
|
|
26256
|
+
process.stderr.write(options.format === "text" ? failure2.code + ": " + failure2.message + "\n" : JSON.stringify(updateV1.parse({ contract: "update", version: 1, ok: false, error: failure2 })) + "\n");
|
|
26257
|
+
process.exitCode = 1;
|
|
26258
|
+
}
|
|
26259
|
+
}
|
|
26260
|
+
|
|
26007
26261
|
// src/commands/spec-preview.ts
|
|
26008
26262
|
import { join as join12 } from "node:path";
|
|
26009
26263
|
import { readFile as readFile12, stat as stat2 } from "node:fs/promises";
|
|
@@ -26682,15 +26936,16 @@ async function runMigrate(options) {
|
|
|
26682
26936
|
}
|
|
26683
26937
|
|
|
26684
26938
|
// src/main.ts
|
|
26685
|
-
var program2 = new Command().name("gitifact").description(t2("help.program")).version("0.
|
|
26939
|
+
var program2 = new Command().name("gitifact").description(t2("help.program")).version("0.4.0").allowExcessArguments(false).addHelpText("after", "\n" + t2("help.notYet")).action(() => program2.outputHelp());
|
|
26686
26940
|
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) => {
|
|
26687
26941
|
await runStatus(options.format);
|
|
26688
26942
|
});
|
|
26689
|
-
program2.command("browser").description(t2("help.browser")).allowExcessArguments(false).option("--port <port>", t2("help.browserPort"), parsePort, 0).option("--dev", t2("help.browserDev")).action(runBrowser);
|
|
26690
|
-
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.
|
|
26943
|
+
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.4.0"));
|
|
26944
|
+
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.4.0"));
|
|
26691
26945
|
program2.command("docs").description(t2("help.docs")).argument("[topic]", t2("help.docsTopic")).allowExcessArguments(false).action(async (topic) => {
|
|
26692
26946
|
await runDocs(topic);
|
|
26693
26947
|
});
|
|
26948
|
+
program2.command("update").description(t2("help.update")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action((options) => runUpdate(options, "0.4.0"));
|
|
26694
26949
|
program2.command("migrate").description(t2("help.migrate")).allowExcessArguments(false).option("--dry-run", t2("help.migrateDryRun")).action(runMigrate);
|
|
26695
26950
|
var spec = program2.command("spec").description(t2("help.spec"));
|
|
26696
26951
|
var replaced = t2("help.deprecated");
|