@launchsecure/launch-kit 0.0.24 → 0.0.26
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 +50 -0
- package/dist/beacon/beacon.mjs +1016 -0
- package/dist/beacon/beacon.mjs.map +1 -0
- package/dist/beacon/beacon.umd.js +87 -0
- package/dist/beacon/beacon.umd.js.map +1 -0
- package/dist/beacon/index-DAIDnjfR.mjs +513 -0
- package/dist/beacon/index-DAIDnjfR.mjs.map +1 -0
- package/dist/beacon/types/capture/element.d.ts +3 -0
- package/dist/beacon/types/capture/element.d.ts.map +1 -0
- package/dist/beacon/types/capture/framework.d.ts +3 -0
- package/dist/beacon/types/capture/framework.d.ts.map +1 -0
- package/dist/beacon/types/capture/metadata.d.ts +3 -0
- package/dist/beacon/types/capture/metadata.d.ts.map +1 -0
- package/dist/beacon/types/capture/overlay.d.ts +7 -0
- package/dist/beacon/types/capture/overlay.d.ts.map +1 -0
- package/dist/beacon/types/capture/picker.d.ts +12 -0
- package/dist/beacon/types/capture/picker.d.ts.map +1 -0
- package/dist/beacon/types/capture/screenshot.d.ts +7 -0
- package/dist/beacon/types/capture/screenshot.d.ts.map +1 -0
- package/dist/beacon/types/capture/selector.d.ts +2 -0
- package/dist/beacon/types/capture/selector.d.ts.map +1 -0
- package/dist/beacon/types/element.d.ts +50 -0
- package/dist/beacon/types/element.d.ts.map +1 -0
- package/dist/beacon/types/index.d.ts +4 -0
- package/dist/beacon/types/index.d.ts.map +1 -0
- package/dist/beacon/types/transport/submit.d.ts +3 -0
- package/dist/beacon/types/transport/submit.d.ts.map +1 -0
- package/dist/beacon/types/types.d.ts +88 -0
- package/dist/beacon/types/types.d.ts.map +1 -0
- package/dist/beacon/types/ui/button.d.ts +2 -0
- package/dist/beacon/types/ui/button.d.ts.map +1 -0
- package/dist/beacon/types/ui/drawer.d.ts +31 -0
- package/dist/beacon/types/ui/drawer.d.ts.map +1 -0
- package/dist/beacon/types/ui/icons.d.ts +9 -0
- package/dist/beacon/types/ui/icons.d.ts.map +1 -0
- package/dist/beacon/types/ui/pick-mode-overlay.d.ts +25 -0
- package/dist/beacon/types/ui/pick-mode-overlay.d.ts.map +1 -0
- package/dist/beacon/types/ui/pin-popover.d.ts +14 -0
- package/dist/beacon/types/ui/pin-popover.d.ts.map +1 -0
- package/dist/chart-client/assets/{index-C8ANseEa.js → index-Bk1hawjD.js} +63 -58
- package/dist/chart-client/assets/index-DpaGa3bY.css +1 -0
- package/dist/chart-client/index.html +2 -2
- package/dist/client/assets/index-Bfel4OQ5.css +32 -0
- package/dist/client/assets/{index-Ds9UP_cj.js → index-eC-WuUWB.js} +58 -58
- package/dist/client/index.html +2 -2
- package/dist/council-client/assets/{index-Dc41S-R2.js → index-Cs_MVXHf.js} +14 -14
- package/dist/council-client/assets/index-P5kMsT5a.css +1 -0
- package/dist/council-client/index.html +2 -2
- package/dist/deck-client/assets/{_baseUniq-2gclQXo7.js → _baseUniq-C2xT_eYu.js} +1 -1
- package/dist/deck-client/assets/{arc-DcMY5Wm0.js → arc-CmVL9pGd.js} +1 -1
- package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-B8iirmmJ.js → architectureDiagram-Q4EWVU46-BSFgdjve.js} +1 -1
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-B4JBLjmJ.js → blockDiagram-DXYQGD6D-DuLzscvP.js} +1 -1
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-CojrJAk8.js → c4Diagram-AHTNJAMY-CfCJB8eY.js} +1 -1
- package/dist/deck-client/assets/channel-B4aNO8ZB.js +1 -0
- package/dist/deck-client/assets/{chunk-4BX2VUAB-Bmb_BMDo.js → chunk-4BX2VUAB-DxmLYTWZ.js} +1 -1
- package/dist/deck-client/assets/{chunk-4TB4RGXK-CumBy8qe.js → chunk-4TB4RGXK-CCnf7GFE.js} +1 -1
- package/dist/deck-client/assets/{chunk-55IACEB6-Ka8Hb1wD.js → chunk-55IACEB6-Db9DApcj.js} +1 -1
- package/dist/deck-client/assets/{chunk-EDXVE4YY-B3sIPiQo.js → chunk-EDXVE4YY-DmYDq8ZI.js} +1 -1
- package/dist/deck-client/assets/{chunk-FMBD7UC4-C1tYkaqu.js → chunk-FMBD7UC4-BGhUlF20.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-D7Wacbky.js → chunk-OYMX7WX6-CpEnicQZ.js} +1 -1
- package/dist/deck-client/assets/{chunk-QZHKN3VN-ChXI0vO3.js → chunk-QZHKN3VN-Doa7LKwf.js} +1 -1
- package/dist/deck-client/assets/{chunk-YZCP3GAM-BXhiqf8u.js → chunk-YZCP3GAM-CpkIlH6V.js} +1 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-BHTI0yWz.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-BHTI0yWz.js +1 -0
- package/dist/deck-client/assets/clone-HduFm7qU.js +1 -0
- package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-Bqp3p68D.js → cose-bilkent-S5V4N54A-Bkh8Bfcb.js} +1 -1
- package/dist/deck-client/assets/{dagre-KV5264BT-BS-rtyhZ.js → dagre-KV5264BT-Bp0XpTgH.js} +1 -1
- package/dist/deck-client/assets/{diagram-5BDNPKRD-BIrj9YGI.js → diagram-5BDNPKRD-ZHiyGYPQ.js} +1 -1
- package/dist/deck-client/assets/{diagram-G4DWMVQ6-noHWPIg4.js → diagram-G4DWMVQ6-BW-Q8_H5.js} +1 -1
- package/dist/deck-client/assets/{diagram-MMDJMWI5-C2qHxvqV.js → diagram-MMDJMWI5-6I3LTafu.js} +1 -1
- package/dist/deck-client/assets/{diagram-TYMM5635-BytnGQr-.js → diagram-TYMM5635-CyM5YK28.js} +1 -1
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-BfK5m2YQ.js → erDiagram-SMLLAGMA-CjNxVJHk.js} +1 -1
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-Cq925G1Z.js → flowDiagram-DWJPFMVM-BDQHuAJR.js} +1 -1
- package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-DhhHPAmj.js → ganttDiagram-T4ZO3ILL-B7MnkpbP.js} +1 -1
- package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-B3Lc0h9q.js → gitGraphDiagram-UUTBAWPF-C9dZAcYD.js} +1 -1
- package/dist/deck-client/assets/{graph-RTawgVWm.js → graph-CjdBnzUy.js} +1 -1
- package/dist/deck-client/assets/{index-BfIfJXmS.js → index-DeIVPW63.js} +68 -68
- package/dist/deck-client/assets/index-LKZDAS9S.css +1 -0
- package/dist/deck-client/assets/{infoDiagram-42DDH7IO-BlR584kX.js → infoDiagram-42DDH7IO-C7d3iRC3.js} +1 -1
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DygKoNGY.js → ishikawaDiagram-UXIWVN3A-BcYGKj09.js} +1 -1
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-BnaiYp9N.js → journeyDiagram-VCZTEJTY-DqFlRrOL.js} +1 -1
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-BQBUBzJC.js → kanban-definition-6JOO6SKY-BJhPp1NR.js} +1 -1
- package/dist/deck-client/assets/{layout-DeZ8HI1T.js → layout-DIeS6GvK.js} +1 -1
- package/dist/deck-client/assets/{linear-C6roLi_9.js → linear-He_yJy5H.js} +1 -1
- package/dist/deck-client/assets/{min-CbUksbuI.js → min-DQ6Kx06t.js} +1 -1
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-iNxV62yN.js → mindmap-definition-QFDTVHPH-sQ62L8T2.js} +1 -1
- package/dist/deck-client/assets/{pieDiagram-DEJITSTG-DHVA0jaG.js → pieDiagram-DEJITSTG-BqCWmU2K.js} +1 -1
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-DBeKKLUQ.js → quadrantDiagram-34T5L4WZ-rQ1TJOoe.js} +1 -1
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-CBwITx7p.js → requirementDiagram-MS252O5E-BO2MPBOM.js} +1 -1
- package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BtE-1YTU.js → sankeyDiagram-XADWPNL6-BgsHEVex.js} +1 -1
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-DN96yPP2.js → sequenceDiagram-FGHM5R23-B3j1yMLU.js} +1 -1
- package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-VUkKC2uJ.js → stateDiagram-FHFEXIEX-C8jFlZou.js} +1 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BoqepHW0.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-oUeZhRns.js → timeline-definition-GMOUNBTQ-tM-qo4Zk.js} +1 -1
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-D87fK90n.js → vennDiagram-DHZGUBPP-B0-6kOEu.js} +1 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-HpBk07P-.js +162 -0
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-Ca_i0QRA.js → wardleyDiagram-NUSXRM2D-BkA1NLDE.js} +1 -1
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CUOJVIvq.js → xychartDiagram-5P7HB3ND-CEKGSuI-.js} +1 -1
- package/dist/deck-client/index.html +2 -2
- package/dist/server/chart-serve.js +1336 -141
- package/dist/server/cli.js +28423 -6671
- package/dist/server/council-entry.js +0 -0
- package/dist/server/deck-mcp-entry.js +332 -3
- package/dist/server/deck-serve.js +288 -0
- package/dist/server/fb-wizard.js +0 -0
- package/dist/server/graph/queries/classify.scm +8 -0
- package/dist/server/graph/queries/exports.scm +7 -0
- package/dist/server/graph-mcp-entry.js +1987 -224
- package/dist/server/recall-entry.js +1112 -0
- package/package.json +47 -21
- package/dist/chart-client/assets/index--120d9P9.css +0 -1
- package/dist/client/assets/index-Bf8zdL3x.css +0 -32
- package/dist/council-client/assets/index-CofZh7pS.css +0 -1
- package/dist/deck-client/assets/channel-ERh5jKXV.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CMi1Gaev.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CMi1Gaev.js +0 -1
- package/dist/deck-client/assets/clone-DfWhlD4X.js +0 -1
- package/dist/deck-client/assets/index-765AIQ9z.css +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CA0IjulK.js +0 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-DYbYcpDp.js +0 -162
- package/dist/server/deck-server/deck-mcp-entry.js +0 -1789
- package/dist/server/deck-server/deck-serve.js +0 -1275
- package/dist/server/server/chart-serve.js +0 -4643
- package/dist/server/server/cli.js +0 -13360
- package/dist/server/server/fb-wizard.js +0 -136
- package/dist/server/server/graph-mcp-entry.js +0 -6776
|
@@ -0,0 +1,1112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
29
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
30
|
+
mod
|
|
31
|
+
));
|
|
32
|
+
|
|
33
|
+
// src/server/recall/git.ts
|
|
34
|
+
function gitEnv(gitDir, workTree) {
|
|
35
|
+
const env = { ...process.env, GIT_DIR: gitDir };
|
|
36
|
+
if (workTree) env.GIT_WORK_TREE = workTree;
|
|
37
|
+
return env;
|
|
38
|
+
}
|
|
39
|
+
function runGitSync(args, opts) {
|
|
40
|
+
const result = (0, import_node_child_process.spawnSync)("git", args, {
|
|
41
|
+
env: opts.env,
|
|
42
|
+
cwd: opts.cwd,
|
|
43
|
+
encoding: "utf8"
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
status: result.status ?? 1,
|
|
47
|
+
stdout: result.stdout ?? "",
|
|
48
|
+
stderr: result.stderr ?? ""
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function runGit(args, opts) {
|
|
52
|
+
return new Promise((resolve3) => {
|
|
53
|
+
const proc = (0, import_node_child_process.spawn)("git", args, {
|
|
54
|
+
env: opts.env,
|
|
55
|
+
cwd: opts.cwd,
|
|
56
|
+
stdio: opts.stdio ?? "inherit"
|
|
57
|
+
});
|
|
58
|
+
proc.on("exit", (code) => resolve3(code ?? 1));
|
|
59
|
+
proc.on("error", () => resolve3(1));
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
var import_node_child_process;
|
|
63
|
+
var init_git = __esm({
|
|
64
|
+
"src/server/recall/git.ts"() {
|
|
65
|
+
"use strict";
|
|
66
|
+
import_node_child_process = require("node:child_process");
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// src/server/recall/paths.ts
|
|
71
|
+
function resolveRecallPaths(cwd = process.cwd()) {
|
|
72
|
+
const workTree = path.resolve(cwd);
|
|
73
|
+
const recallDir = path.join(workTree, RECALL_DIR_NAME);
|
|
74
|
+
const gitDir = path.join(recallDir, RECALL_REPO_DIRNAME);
|
|
75
|
+
return { workTree, recallDir, gitDir };
|
|
76
|
+
}
|
|
77
|
+
var path, RECALL_DIR_NAME, RECALL_REPO_DIRNAME;
|
|
78
|
+
var init_paths = __esm({
|
|
79
|
+
"src/server/recall/paths.ts"() {
|
|
80
|
+
"use strict";
|
|
81
|
+
path = __toESM(require("node:path"));
|
|
82
|
+
RECALL_DIR_NAME = ".recall";
|
|
83
|
+
RECALL_REPO_DIRNAME = "repo.git";
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// src/server/recall/config.ts
|
|
88
|
+
function isPlainObject(v) {
|
|
89
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
90
|
+
}
|
|
91
|
+
function mergeConfig(raw) {
|
|
92
|
+
if (!isPlainObject(raw)) return { ...DEFAULT_CONFIG };
|
|
93
|
+
const out = {
|
|
94
|
+
debounce: DEFAULT_CONFIG.debounce,
|
|
95
|
+
ignore: [...DEFAULT_CONFIG.ignore],
|
|
96
|
+
retention: { ...DEFAULT_CONFIG.retention }
|
|
97
|
+
};
|
|
98
|
+
if (typeof raw.debounce === "number" && raw.debounce > 0) {
|
|
99
|
+
out.debounce = raw.debounce;
|
|
100
|
+
}
|
|
101
|
+
if (Array.isArray(raw.ignore) && raw.ignore.every((x) => typeof x === "string")) {
|
|
102
|
+
out.ignore = raw.ignore;
|
|
103
|
+
}
|
|
104
|
+
if (isPlainObject(raw.retention)) {
|
|
105
|
+
const r = raw.retention;
|
|
106
|
+
if (r.keepLast === null) {
|
|
107
|
+
out.retention.keepLast = null;
|
|
108
|
+
} else if (typeof r.keepLast === "number" && r.keepLast >= 0) {
|
|
109
|
+
out.retention.keepLast = r.keepLast;
|
|
110
|
+
}
|
|
111
|
+
if (r.maxAgeDays === null) {
|
|
112
|
+
out.retention.maxAgeDays = null;
|
|
113
|
+
} else if (typeof r.maxAgeDays === "number" && r.maxAgeDays >= 0) {
|
|
114
|
+
out.retention.maxAgeDays = r.maxAgeDays;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
function loadConfig(workTree) {
|
|
120
|
+
const configPath = path2.join(workTree, CONFIG_FILENAME);
|
|
121
|
+
if (!fs.existsSync(configPath)) {
|
|
122
|
+
return { config: { ...DEFAULT_CONFIG }, source: "defaults", path: configPath };
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const text = fs.readFileSync(configPath, "utf8");
|
|
126
|
+
const raw = JSON.parse(text);
|
|
127
|
+
return { config: mergeConfig(raw), source: "file", path: configPath };
|
|
128
|
+
} catch (err) {
|
|
129
|
+
process.stderr.write(
|
|
130
|
+
`[launch-recall] warning: failed to parse ${CONFIG_FILENAME} (${err instanceof Error ? err.message : String(err)}) \u2014 using defaults
|
|
131
|
+
`
|
|
132
|
+
);
|
|
133
|
+
return { config: { ...DEFAULT_CONFIG }, source: "defaults", path: configPath };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function writeDefaultConfig(workTree) {
|
|
137
|
+
const configPath = path2.join(workTree, CONFIG_FILENAME);
|
|
138
|
+
if (fs.existsSync(configPath)) return "present";
|
|
139
|
+
fs.writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n");
|
|
140
|
+
return "created";
|
|
141
|
+
}
|
|
142
|
+
function escapeRegex(s) {
|
|
143
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
144
|
+
}
|
|
145
|
+
function buildIgnoreRegex(ignore) {
|
|
146
|
+
if (ignore.length === 0) return /^\b$/;
|
|
147
|
+
const alt = ignore.map(escapeRegex).join("|");
|
|
148
|
+
return new RegExp(`(^|/)(${alt})(/|$)`);
|
|
149
|
+
}
|
|
150
|
+
function buildPathspecExcludes(ignore) {
|
|
151
|
+
return ignore.map((name) => `:!${name}`);
|
|
152
|
+
}
|
|
153
|
+
var fs, path2, CONFIG_FILENAME, DEFAULT_CONFIG;
|
|
154
|
+
var init_config = __esm({
|
|
155
|
+
"src/server/recall/config.ts"() {
|
|
156
|
+
"use strict";
|
|
157
|
+
fs = __toESM(require("node:fs"));
|
|
158
|
+
path2 = __toESM(require("node:path"));
|
|
159
|
+
CONFIG_FILENAME = ".launch-recall.json";
|
|
160
|
+
DEFAULT_CONFIG = {
|
|
161
|
+
debounce: 3e3,
|
|
162
|
+
ignore: [
|
|
163
|
+
"node_modules",
|
|
164
|
+
".next",
|
|
165
|
+
"dist",
|
|
166
|
+
"build",
|
|
167
|
+
".turbo",
|
|
168
|
+
".git",
|
|
169
|
+
".recall",
|
|
170
|
+
"coverage"
|
|
171
|
+
],
|
|
172
|
+
retention: {
|
|
173
|
+
keepLast: 5e3,
|
|
174
|
+
maxAgeDays: 30
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// src/server/recall/init.ts
|
|
181
|
+
var init_exports = {};
|
|
182
|
+
__export(init_exports, {
|
|
183
|
+
runInit: () => runInit
|
|
184
|
+
});
|
|
185
|
+
function ensureGitignoreEntry(workTree) {
|
|
186
|
+
const gitignorePath = path3.join(workTree, ".gitignore");
|
|
187
|
+
if (!fs2.existsSync(gitignorePath)) return "no-gitignore";
|
|
188
|
+
const contents = fs2.readFileSync(gitignorePath, "utf8");
|
|
189
|
+
const lines = contents.split(/\r?\n/);
|
|
190
|
+
const already = lines.some((l) => {
|
|
191
|
+
const t = l.trim();
|
|
192
|
+
return t === GITIGNORE_LINE || t === `${RECALL_DIR_NAME}/` || t === RECALL_DIR_NAME || t === `/${RECALL_DIR_NAME}` || t === `${RECALL_DIR_NAME}/**`;
|
|
193
|
+
});
|
|
194
|
+
if (already) return "present";
|
|
195
|
+
const needsLeadingNewline = contents.length > 0 && !contents.endsWith("\n");
|
|
196
|
+
fs2.appendFileSync(
|
|
197
|
+
gitignorePath,
|
|
198
|
+
`${needsLeadingNewline ? "\n" : ""}${GITIGNORE_LINE}
|
|
199
|
+
`
|
|
200
|
+
);
|
|
201
|
+
return "added";
|
|
202
|
+
}
|
|
203
|
+
async function runInit(_args) {
|
|
204
|
+
const { workTree, recallDir, gitDir } = resolveRecallPaths();
|
|
205
|
+
if (fs2.existsSync(gitDir)) {
|
|
206
|
+
process.stderr.write(`[launch-recall] already initialised at ${gitDir}
|
|
207
|
+
`);
|
|
208
|
+
} else {
|
|
209
|
+
fs2.mkdirSync(recallDir, { recursive: true });
|
|
210
|
+
const init = runGitSync(["init", "--bare", gitDir], { env: process.env });
|
|
211
|
+
if (init.status !== 0) {
|
|
212
|
+
process.stderr.write(`[launch-recall] git init --bare failed:
|
|
213
|
+
${init.stderr}`);
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
runGitSync(["config", "gc.auto", "256"], { env: gitEnv(gitDir) });
|
|
217
|
+
runGitSync(["config", "core.logAllRefUpdates", "true"], { env: gitEnv(gitDir) });
|
|
218
|
+
process.stderr.write(`[launch-recall] created shadow repo at ${gitDir}
|
|
219
|
+
`);
|
|
220
|
+
}
|
|
221
|
+
const gitignoreResult = ensureGitignoreEntry(workTree);
|
|
222
|
+
switch (gitignoreResult) {
|
|
223
|
+
case "added":
|
|
224
|
+
process.stderr.write(`[launch-recall] added ${GITIGNORE_LINE} to .gitignore
|
|
225
|
+
`);
|
|
226
|
+
break;
|
|
227
|
+
case "present":
|
|
228
|
+
process.stderr.write(`[launch-recall] .gitignore already excludes ${RECALL_DIR_NAME}
|
|
229
|
+
`);
|
|
230
|
+
break;
|
|
231
|
+
case "no-gitignore":
|
|
232
|
+
process.stderr.write(
|
|
233
|
+
`[launch-recall] no .gitignore in ${workTree} \u2014 create one and add "${GITIGNORE_LINE}"
|
|
234
|
+
`
|
|
235
|
+
);
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
const configResult = writeDefaultConfig(workTree);
|
|
239
|
+
if (configResult === "created") {
|
|
240
|
+
process.stderr.write(`[launch-recall] wrote default ${CONFIG_FILENAME}
|
|
241
|
+
`);
|
|
242
|
+
} else {
|
|
243
|
+
process.stderr.write(`[launch-recall] ${CONFIG_FILENAME} already present
|
|
244
|
+
`);
|
|
245
|
+
}
|
|
246
|
+
process.stderr.write(`[launch-recall] ready. start the watcher with: launch-recall watch
|
|
247
|
+
`);
|
|
248
|
+
}
|
|
249
|
+
var fs2, path3, GITIGNORE_LINE;
|
|
250
|
+
var init_init = __esm({
|
|
251
|
+
"src/server/recall/init.ts"() {
|
|
252
|
+
"use strict";
|
|
253
|
+
fs2 = __toESM(require("node:fs"));
|
|
254
|
+
path3 = __toESM(require("node:path"));
|
|
255
|
+
init_git();
|
|
256
|
+
init_paths();
|
|
257
|
+
init_config();
|
|
258
|
+
GITIGNORE_LINE = `/${RECALL_DIR_NAME}/`;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// src/server/recall/stop.ts
|
|
263
|
+
var stop_exports = {};
|
|
264
|
+
__export(stop_exports, {
|
|
265
|
+
pidFilePath: () => pidFilePath,
|
|
266
|
+
runStop: () => runStop,
|
|
267
|
+
stopWatcher: () => stopWatcher
|
|
268
|
+
});
|
|
269
|
+
function pidFilePath(recallDir) {
|
|
270
|
+
return path4.join(recallDir, "watch.pid");
|
|
271
|
+
}
|
|
272
|
+
function isAlive(pid) {
|
|
273
|
+
try {
|
|
274
|
+
process.kill(pid, 0);
|
|
275
|
+
return true;
|
|
276
|
+
} catch (err) {
|
|
277
|
+
const code = err.code;
|
|
278
|
+
if (code === "ESRCH") return false;
|
|
279
|
+
if (code === "EPERM") return true;
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function sleep(ms) {
|
|
284
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
285
|
+
}
|
|
286
|
+
async function stopWatcher(quiet = false) {
|
|
287
|
+
const { recallDir } = resolveRecallPaths();
|
|
288
|
+
const pf = pidFilePath(recallDir);
|
|
289
|
+
if (!fs3.existsSync(pf)) {
|
|
290
|
+
if (!quiet) process.stderr.write(`[launch-recall] no PID file at ${pf}
|
|
291
|
+
`);
|
|
292
|
+
return { state: "no-pid-file" };
|
|
293
|
+
}
|
|
294
|
+
const raw = fs3.readFileSync(pf, "utf8").trim();
|
|
295
|
+
const pid = Number(raw);
|
|
296
|
+
if (!Number.isFinite(pid) || pid <= 0) {
|
|
297
|
+
if (!quiet) process.stderr.write(`[launch-recall] invalid PID file content: ${raw}
|
|
298
|
+
`);
|
|
299
|
+
fs3.unlinkSync(pf);
|
|
300
|
+
return { state: "kill-failed" };
|
|
301
|
+
}
|
|
302
|
+
if (!isAlive(pid)) {
|
|
303
|
+
if (!quiet) process.stderr.write(`[launch-recall] process ${pid} not running (stale PID file)
|
|
304
|
+
`);
|
|
305
|
+
fs3.unlinkSync(pf);
|
|
306
|
+
return { state: "already-dead", pid };
|
|
307
|
+
}
|
|
308
|
+
try {
|
|
309
|
+
process.kill(pid, "SIGTERM");
|
|
310
|
+
if (!quiet) process.stderr.write(`[launch-recall] sent SIGTERM to ${pid}
|
|
311
|
+
`);
|
|
312
|
+
} catch (err) {
|
|
313
|
+
if (!quiet)
|
|
314
|
+
process.stderr.write(
|
|
315
|
+
`[launch-recall] SIGTERM failed: ${err instanceof Error ? err.message : String(err)}
|
|
316
|
+
`
|
|
317
|
+
);
|
|
318
|
+
return { state: "kill-failed", pid };
|
|
319
|
+
}
|
|
320
|
+
for (let i = 0; i < 8; i++) {
|
|
321
|
+
await sleep(250);
|
|
322
|
+
if (!isAlive(pid)) {
|
|
323
|
+
if (fs3.existsSync(pf)) fs3.unlinkSync(pf);
|
|
324
|
+
if (!quiet) process.stderr.write(`[launch-recall] watcher ${pid} stopped
|
|
325
|
+
`);
|
|
326
|
+
return { state: "stopped", pid };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
process.kill(pid, "SIGKILL");
|
|
331
|
+
if (!quiet) process.stderr.write(`[launch-recall] sent SIGKILL to ${pid}
|
|
332
|
+
`);
|
|
333
|
+
} catch {
|
|
334
|
+
}
|
|
335
|
+
if (fs3.existsSync(pf)) fs3.unlinkSync(pf);
|
|
336
|
+
return { state: "stopped", pid };
|
|
337
|
+
}
|
|
338
|
+
async function runStop(_args) {
|
|
339
|
+
await stopWatcher(false);
|
|
340
|
+
}
|
|
341
|
+
var fs3, path4;
|
|
342
|
+
var init_stop = __esm({
|
|
343
|
+
"src/server/recall/stop.ts"() {
|
|
344
|
+
"use strict";
|
|
345
|
+
fs3 = __toESM(require("node:fs"));
|
|
346
|
+
path4 = __toESM(require("node:path"));
|
|
347
|
+
init_paths();
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
// src/server/recall/watch.ts
|
|
352
|
+
var watch_exports = {};
|
|
353
|
+
__export(watch_exports, {
|
|
354
|
+
runWatch: () => runWatch
|
|
355
|
+
});
|
|
356
|
+
function isPidAlive(pid) {
|
|
357
|
+
try {
|
|
358
|
+
process.kill(pid, 0);
|
|
359
|
+
return true;
|
|
360
|
+
} catch (err) {
|
|
361
|
+
const code = err.code;
|
|
362
|
+
if (code === "ESRCH") return false;
|
|
363
|
+
return code === "EPERM";
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function parseDebounceOverride(args) {
|
|
367
|
+
const idx = args.indexOf("--debounce");
|
|
368
|
+
if (idx === -1) return null;
|
|
369
|
+
const raw = args[idx + 1];
|
|
370
|
+
const n = Number(raw);
|
|
371
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
372
|
+
process.stderr.write(`[launch-recall] invalid --debounce value: ${raw}
|
|
373
|
+
`);
|
|
374
|
+
process.exit(2);
|
|
375
|
+
}
|
|
376
|
+
return n;
|
|
377
|
+
}
|
|
378
|
+
function log(msg) {
|
|
379
|
+
process.stderr.write(`[launch-recall] ${msg}
|
|
380
|
+
`);
|
|
381
|
+
}
|
|
382
|
+
async function runWatch(args) {
|
|
383
|
+
const { workTree, gitDir, recallDir } = resolveRecallPaths();
|
|
384
|
+
if (!fs4.existsSync(gitDir)) {
|
|
385
|
+
log(`not initialised \u2014 run: launch-recall init`);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
const pf = pidFilePath(recallDir);
|
|
389
|
+
if (fs4.existsSync(pf)) {
|
|
390
|
+
const existing = Number(fs4.readFileSync(pf, "utf8").trim());
|
|
391
|
+
if (Number.isFinite(existing) && isPidAlive(existing)) {
|
|
392
|
+
log(`watcher already running (pid ${existing}) \u2014 run \`launch-recall stop\` first`);
|
|
393
|
+
process.exit(1);
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
fs4.unlinkSync(pf);
|
|
397
|
+
} catch {
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
fs4.writeFileSync(pf, String(process.pid));
|
|
401
|
+
const cleanupPidFile = () => {
|
|
402
|
+
try {
|
|
403
|
+
fs4.unlinkSync(pf);
|
|
404
|
+
} catch {
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
const { config, source } = loadConfig(workTree);
|
|
408
|
+
const debounceOverride = parseDebounceOverride(args);
|
|
409
|
+
const debounceMs = debounceOverride ?? config.debounce;
|
|
410
|
+
const ignoreRegex = buildIgnoreRegex(config.ignore);
|
|
411
|
+
const pathspecExcludes = buildPathspecExcludes(config.ignore);
|
|
412
|
+
log(`watching ${workTree}`);
|
|
413
|
+
log(`shadow repo ${gitDir}`);
|
|
414
|
+
log(`config ${source === "file" ? "from .launch-recall.json" : "defaults"}`);
|
|
415
|
+
log(`debounce ${debounceMs}ms`);
|
|
416
|
+
log(`ignoring [${config.ignore.join(", ")}]`);
|
|
417
|
+
let busy = false;
|
|
418
|
+
let queued = false;
|
|
419
|
+
let timer = null;
|
|
420
|
+
const env = gitEnv(gitDir, workTree);
|
|
421
|
+
const addArgs = ["add", "-f", "--", ".", ...pathspecExcludes];
|
|
422
|
+
const stamp = () => (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
423
|
+
const snap = () => {
|
|
424
|
+
if (busy) {
|
|
425
|
+
queued = true;
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
busy = true;
|
|
429
|
+
const add = (0, import_node_child_process2.spawn)("git", addArgs, { env, stdio: "ignore" });
|
|
430
|
+
add.on("exit", (addCode) => {
|
|
431
|
+
if (addCode !== 0) {
|
|
432
|
+
busy = false;
|
|
433
|
+
if (queued) {
|
|
434
|
+
queued = false;
|
|
435
|
+
snap();
|
|
436
|
+
}
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const check = (0, import_node_child_process2.spawn)("git", ["diff", "--cached", "--quiet"], { env, stdio: "ignore" });
|
|
440
|
+
check.on("exit", (checkCode) => {
|
|
441
|
+
if (checkCode === 0) {
|
|
442
|
+
busy = false;
|
|
443
|
+
if (queued) {
|
|
444
|
+
queued = false;
|
|
445
|
+
snap();
|
|
446
|
+
}
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const commit = (0, import_node_child_process2.spawn)(
|
|
450
|
+
"git",
|
|
451
|
+
["commit", "-q", "-m", `snap ${stamp()}`],
|
|
452
|
+
{ env, stdio: "ignore" }
|
|
453
|
+
);
|
|
454
|
+
commit.on("exit", () => {
|
|
455
|
+
busy = false;
|
|
456
|
+
if (queued) {
|
|
457
|
+
queued = false;
|
|
458
|
+
snap();
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
};
|
|
464
|
+
const scheduleSnap = () => {
|
|
465
|
+
if (timer) clearTimeout(timer);
|
|
466
|
+
timer = setTimeout(snap, debounceMs);
|
|
467
|
+
};
|
|
468
|
+
const abort = new AbortController();
|
|
469
|
+
const shutdown = (sig, code) => {
|
|
470
|
+
if (sig === "SIGINT") log("stopping");
|
|
471
|
+
abort.abort();
|
|
472
|
+
if (timer) clearTimeout(timer);
|
|
473
|
+
cleanupPidFile();
|
|
474
|
+
process.exit(code);
|
|
475
|
+
};
|
|
476
|
+
process.on("SIGINT", () => shutdown("SIGINT", 0));
|
|
477
|
+
process.on("SIGTERM", () => shutdown("SIGTERM", 0));
|
|
478
|
+
process.on("exit", cleanupPidFile);
|
|
479
|
+
try {
|
|
480
|
+
const watcher = fsp.watch(workTree, { recursive: true, signal: abort.signal });
|
|
481
|
+
for await (const ev of watcher) {
|
|
482
|
+
if (ev.filename && ignoreRegex.test(ev.filename)) continue;
|
|
483
|
+
scheduleSnap();
|
|
484
|
+
}
|
|
485
|
+
} catch (err) {
|
|
486
|
+
if (err.name === "AbortError") {
|
|
487
|
+
cleanupPidFile();
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
log(`watcher error: ${err instanceof Error ? err.message : String(err)}`);
|
|
491
|
+
cleanupPidFile();
|
|
492
|
+
process.exit(1);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
var fs4, fsp, import_node_child_process2;
|
|
496
|
+
var init_watch = __esm({
|
|
497
|
+
"src/server/recall/watch.ts"() {
|
|
498
|
+
"use strict";
|
|
499
|
+
fs4 = __toESM(require("node:fs"));
|
|
500
|
+
fsp = __toESM(require("node:fs/promises"));
|
|
501
|
+
import_node_child_process2 = require("node:child_process");
|
|
502
|
+
init_git();
|
|
503
|
+
init_paths();
|
|
504
|
+
init_config();
|
|
505
|
+
init_stop();
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// src/server/recall/log.ts
|
|
510
|
+
var log_exports = {};
|
|
511
|
+
__export(log_exports, {
|
|
512
|
+
runLog: () => runLog
|
|
513
|
+
});
|
|
514
|
+
async function runLog(args) {
|
|
515
|
+
const { workTree, gitDir } = resolveRecallPaths();
|
|
516
|
+
if (!fs5.existsSync(gitDir)) {
|
|
517
|
+
process.stderr.write(`[launch-recall] not initialised \u2014 run: launch-recall init
|
|
518
|
+
`);
|
|
519
|
+
process.exit(1);
|
|
520
|
+
}
|
|
521
|
+
const env = gitEnv(gitDir, workTree);
|
|
522
|
+
const gitArgs = ["log", "--oneline", "--decorate"];
|
|
523
|
+
if (args.length > 0) {
|
|
524
|
+
gitArgs.push("--", ...args);
|
|
525
|
+
}
|
|
526
|
+
const code = await runGit(gitArgs, { env });
|
|
527
|
+
process.exit(code);
|
|
528
|
+
}
|
|
529
|
+
var fs5;
|
|
530
|
+
var init_log = __esm({
|
|
531
|
+
"src/server/recall/log.ts"() {
|
|
532
|
+
"use strict";
|
|
533
|
+
fs5 = __toESM(require("node:fs"));
|
|
534
|
+
init_git();
|
|
535
|
+
init_paths();
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// src/server/recall/restore.ts
|
|
540
|
+
var restore_exports = {};
|
|
541
|
+
__export(restore_exports, {
|
|
542
|
+
runRestore: () => runRestore
|
|
543
|
+
});
|
|
544
|
+
function parseArgs(args) {
|
|
545
|
+
let target = null;
|
|
546
|
+
let at = "HEAD";
|
|
547
|
+
let outPath = null;
|
|
548
|
+
for (let i = 0; i < args.length; i++) {
|
|
549
|
+
const a = args[i];
|
|
550
|
+
if (a === "--at") {
|
|
551
|
+
at = args[++i] ?? "HEAD";
|
|
552
|
+
} else if (a === "--out" || a === "-o") {
|
|
553
|
+
outPath = args[++i] ?? null;
|
|
554
|
+
} else if (!target) {
|
|
555
|
+
target = a;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return { target, at, outPath };
|
|
559
|
+
}
|
|
560
|
+
async function runRestore(args) {
|
|
561
|
+
const { target, at, outPath } = parseArgs(args);
|
|
562
|
+
if (!target) {
|
|
563
|
+
process.stderr.write(
|
|
564
|
+
"Usage: launch-recall restore <path> [--at <ref>] [--out <path>]\n"
|
|
565
|
+
);
|
|
566
|
+
process.exit(2);
|
|
567
|
+
}
|
|
568
|
+
const { workTree, gitDir } = resolveRecallPaths();
|
|
569
|
+
if (!fs6.existsSync(gitDir)) {
|
|
570
|
+
process.stderr.write(`[launch-recall] not initialised \u2014 run: launch-recall init
|
|
571
|
+
`);
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
const env = gitEnv(gitDir, workTree);
|
|
575
|
+
const spec = `${at}:${target}`;
|
|
576
|
+
const result = runGitSync(["show", spec], { env });
|
|
577
|
+
if (result.status !== 0) {
|
|
578
|
+
process.stderr.write(
|
|
579
|
+
`[launch-recall] could not read ${spec} from shadow:
|
|
580
|
+
${result.stderr}`
|
|
581
|
+
);
|
|
582
|
+
process.exit(result.status);
|
|
583
|
+
}
|
|
584
|
+
const destination = outPath ?? path5.resolve(workTree, target);
|
|
585
|
+
if (outPath) {
|
|
586
|
+
fs6.mkdirSync(path5.dirname(path5.resolve(destination)), { recursive: true });
|
|
587
|
+
}
|
|
588
|
+
if (fs6.existsSync(destination)) {
|
|
589
|
+
process.stderr.write(
|
|
590
|
+
`[launch-recall] refusing to overwrite existing file: ${destination}
|
|
591
|
+
use --out to write to a different location
|
|
592
|
+
`
|
|
593
|
+
);
|
|
594
|
+
process.exit(1);
|
|
595
|
+
}
|
|
596
|
+
fs6.writeFileSync(destination, result.stdout);
|
|
597
|
+
process.stderr.write(`[launch-recall] restored ${spec} \u2192 ${destination}
|
|
598
|
+
`);
|
|
599
|
+
}
|
|
600
|
+
var fs6, path5;
|
|
601
|
+
var init_restore = __esm({
|
|
602
|
+
"src/server/recall/restore.ts"() {
|
|
603
|
+
"use strict";
|
|
604
|
+
fs6 = __toESM(require("node:fs"));
|
|
605
|
+
path5 = __toESM(require("node:path"));
|
|
606
|
+
init_git();
|
|
607
|
+
init_paths();
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
// src/server/recall/forget.ts
|
|
612
|
+
var forget_exports = {};
|
|
613
|
+
__export(forget_exports, {
|
|
614
|
+
runForget: () => runForget
|
|
615
|
+
});
|
|
616
|
+
function parseArgs2(args) {
|
|
617
|
+
const out = {
|
|
618
|
+
keepLast: void 0,
|
|
619
|
+
maxAgeDays: void 0,
|
|
620
|
+
dryRun: false
|
|
621
|
+
};
|
|
622
|
+
for (let i = 0; i < args.length; i++) {
|
|
623
|
+
const a = args[i];
|
|
624
|
+
if (a === "--dry-run" || a === "-n") {
|
|
625
|
+
out.dryRun = true;
|
|
626
|
+
} else if (a === "--keep-last") {
|
|
627
|
+
const raw = args[++i];
|
|
628
|
+
if (raw === "off") {
|
|
629
|
+
out.keepLast = null;
|
|
630
|
+
} else {
|
|
631
|
+
const n = Number(raw);
|
|
632
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
633
|
+
process.stderr.write(`[launch-recall] invalid --keep-last: ${raw}
|
|
634
|
+
`);
|
|
635
|
+
process.exit(2);
|
|
636
|
+
}
|
|
637
|
+
out.keepLast = n;
|
|
638
|
+
}
|
|
639
|
+
} else if (a === "--max-age") {
|
|
640
|
+
const raw = args[++i] ?? "";
|
|
641
|
+
if (raw === "off") {
|
|
642
|
+
out.maxAgeDays = null;
|
|
643
|
+
} else {
|
|
644
|
+
const m = /^(\d+)\s*(d|days?)?$/i.exec(raw);
|
|
645
|
+
if (!m) {
|
|
646
|
+
process.stderr.write(`[launch-recall] invalid --max-age: ${raw} (expected e.g. 30 or 30d)
|
|
647
|
+
`);
|
|
648
|
+
process.exit(2);
|
|
649
|
+
}
|
|
650
|
+
out.maxAgeDays = Number(m[1]);
|
|
651
|
+
}
|
|
652
|
+
} else {
|
|
653
|
+
process.stderr.write(`[launch-recall] unknown forget arg: ${a}
|
|
654
|
+
`);
|
|
655
|
+
process.exit(2);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return out;
|
|
659
|
+
}
|
|
660
|
+
function resolveRetention(args, configRetention) {
|
|
661
|
+
return {
|
|
662
|
+
keepLast: args.keepLast === void 0 ? configRetention.keepLast : args.keepLast,
|
|
663
|
+
maxAgeDays: args.maxAgeDays === void 0 ? configRetention.maxAgeDays : args.maxAgeDays
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
function listCommitsOldestFirst(env) {
|
|
667
|
+
const result = runGitSync(
|
|
668
|
+
["log", "--reverse", "--format=%H %ct", "main"],
|
|
669
|
+
{ env }
|
|
670
|
+
);
|
|
671
|
+
if (result.status !== 0) {
|
|
672
|
+
return [];
|
|
673
|
+
}
|
|
674
|
+
return result.stdout.split("\n").filter(Boolean).map((line) => {
|
|
675
|
+
const [sha, ct] = line.split(" ");
|
|
676
|
+
return { sha, committerEpoch: Number(ct) };
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
function pickCutoff(commits, retention) {
|
|
680
|
+
if (commits.length === 0) return { dropCount: 0, firstKeptIndex: 0 };
|
|
681
|
+
let firstKept = 0;
|
|
682
|
+
if (typeof retention.keepLast === "number" && commits.length > retention.keepLast) {
|
|
683
|
+
firstKept = Math.max(firstKept, commits.length - retention.keepLast);
|
|
684
|
+
}
|
|
685
|
+
if (typeof retention.maxAgeDays === "number") {
|
|
686
|
+
const cutoffEpoch = Math.floor(Date.now() / 1e3) - retention.maxAgeDays * 86400;
|
|
687
|
+
let idx = commits.findIndex((c) => c.committerEpoch >= cutoffEpoch);
|
|
688
|
+
if (idx === -1) idx = commits.length;
|
|
689
|
+
firstKept = Math.max(firstKept, idx);
|
|
690
|
+
}
|
|
691
|
+
if (firstKept >= commits.length) {
|
|
692
|
+
firstKept = commits.length - 1;
|
|
693
|
+
}
|
|
694
|
+
return { dropCount: firstKept, firstKeptIndex: firstKept };
|
|
695
|
+
}
|
|
696
|
+
function rewriteHistory(env, kept) {
|
|
697
|
+
if (kept.length === 0) return { error: "no commits to keep" };
|
|
698
|
+
const first = kept[0];
|
|
699
|
+
const treeResult = runGitSync(["rev-parse", `${first.sha}^{tree}`], { env });
|
|
700
|
+
if (treeResult.status !== 0) return { error: `rev-parse tree failed: ${treeResult.stderr}` };
|
|
701
|
+
const firstTree = treeResult.stdout.trim();
|
|
702
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
703
|
+
const newRoot = runGitSync(
|
|
704
|
+
["commit-tree", firstTree, "-m", `snap (truncated ${stamp})`],
|
|
705
|
+
{ env }
|
|
706
|
+
);
|
|
707
|
+
if (newRoot.status !== 0) return { error: `commit-tree (root) failed: ${newRoot.stderr}` };
|
|
708
|
+
let parent = newRoot.stdout.trim();
|
|
709
|
+
for (let i = 1; i < kept.length; i++) {
|
|
710
|
+
const c = kept[i];
|
|
711
|
+
const t = runGitSync(["rev-parse", `${c.sha}^{tree}`], { env });
|
|
712
|
+
if (t.status !== 0) return { error: `rev-parse tree ${c.sha} failed: ${t.stderr}` };
|
|
713
|
+
const msg = runGitSync(["log", "-1", "--format=%B", c.sha], { env });
|
|
714
|
+
if (msg.status !== 0) return { error: `log -1 ${c.sha} failed: ${msg.stderr}` };
|
|
715
|
+
const next = runGitSync(
|
|
716
|
+
["commit-tree", t.stdout.trim(), "-p", parent, "-m", msg.stdout.trim() || "snap"],
|
|
717
|
+
{ env }
|
|
718
|
+
);
|
|
719
|
+
if (next.status !== 0) return { error: `commit-tree ${c.sha} failed: ${next.stderr}` };
|
|
720
|
+
parent = next.stdout.trim();
|
|
721
|
+
}
|
|
722
|
+
const update = runGitSync(
|
|
723
|
+
["update-ref", "refs/heads/main", parent],
|
|
724
|
+
{ env }
|
|
725
|
+
);
|
|
726
|
+
if (update.status !== 0) return { error: `update-ref failed: ${update.stderr}` };
|
|
727
|
+
return { newTipSha: parent };
|
|
728
|
+
}
|
|
729
|
+
async function runForget(args) {
|
|
730
|
+
const parsed = parseArgs2(args);
|
|
731
|
+
const { workTree, gitDir } = resolveRecallPaths();
|
|
732
|
+
if (!fs7.existsSync(gitDir)) {
|
|
733
|
+
process.stderr.write(`[launch-recall] not initialised \u2014 run: launch-recall init
|
|
734
|
+
`);
|
|
735
|
+
process.exit(1);
|
|
736
|
+
}
|
|
737
|
+
const { config } = loadConfig(workTree);
|
|
738
|
+
const retention = resolveRetention(parsed, config.retention);
|
|
739
|
+
if (retention.keepLast === null && retention.maxAgeDays === null) {
|
|
740
|
+
process.stderr.write(`[launch-recall] no retention rules set \u2014 nothing to do
|
|
741
|
+
`);
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
const env = gitEnv(gitDir, workTree);
|
|
745
|
+
const commits = listCommitsOldestFirst(env);
|
|
746
|
+
if (commits.length === 0) {
|
|
747
|
+
process.stderr.write(`[launch-recall] no commits in shadow repo
|
|
748
|
+
`);
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
const { dropCount } = pickCutoff(commits, retention);
|
|
752
|
+
const kept = commits.slice(dropCount);
|
|
753
|
+
process.stderr.write(
|
|
754
|
+
`[launch-recall] retention: keepLast=${retention.keepLast ?? "off"} maxAgeDays=${retention.maxAgeDays ?? "off"}
|
|
755
|
+
`
|
|
756
|
+
);
|
|
757
|
+
process.stderr.write(
|
|
758
|
+
`[launch-recall] ${commits.length} snapshots total, ${dropCount} to drop, ${kept.length} to keep
|
|
759
|
+
`
|
|
760
|
+
);
|
|
761
|
+
if (dropCount === 0) {
|
|
762
|
+
process.stderr.write(`[launch-recall] nothing to drop
|
|
763
|
+
`);
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
if (parsed.dryRun) {
|
|
767
|
+
process.stderr.write(`[launch-recall] --dry-run \u2014 no changes written
|
|
768
|
+
`);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
process.stderr.write(`[launch-recall] rewriting history\u2026
|
|
772
|
+
`);
|
|
773
|
+
const result = rewriteHistory(env, kept);
|
|
774
|
+
if ("error" in result) {
|
|
775
|
+
process.stderr.write(`[launch-recall] rewrite failed: ${result.error}
|
|
776
|
+
`);
|
|
777
|
+
process.exit(1);
|
|
778
|
+
}
|
|
779
|
+
process.stderr.write(`[launch-recall] new main tip: ${result.newTipSha.slice(0, 7)}
|
|
780
|
+
`);
|
|
781
|
+
process.stderr.write(`[launch-recall] expiring reflog\u2026
|
|
782
|
+
`);
|
|
783
|
+
runGitSync(["reflog", "expire", "--expire=now", "--all"], { env });
|
|
784
|
+
process.stderr.write(`[launch-recall] running gc --prune=now\u2026
|
|
785
|
+
`);
|
|
786
|
+
const gc = runGitSync(["gc", "--prune=now", "--quiet"], { env });
|
|
787
|
+
if (gc.status !== 0) {
|
|
788
|
+
process.stderr.write(`[launch-recall] gc warning:
|
|
789
|
+
${gc.stderr}`);
|
|
790
|
+
}
|
|
791
|
+
process.stderr.write(`[launch-recall] done
|
|
792
|
+
`);
|
|
793
|
+
}
|
|
794
|
+
var fs7;
|
|
795
|
+
var init_forget = __esm({
|
|
796
|
+
"src/server/recall/forget.ts"() {
|
|
797
|
+
"use strict";
|
|
798
|
+
fs7 = __toESM(require("node:fs"));
|
|
799
|
+
init_git();
|
|
800
|
+
init_config();
|
|
801
|
+
init_paths();
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
// src/server/recall/push.ts
|
|
806
|
+
var push_exports = {};
|
|
807
|
+
__export(push_exports, {
|
|
808
|
+
runPush: () => runPush
|
|
809
|
+
});
|
|
810
|
+
async function runPush(args) {
|
|
811
|
+
const remote = args[0];
|
|
812
|
+
if (!remote) {
|
|
813
|
+
process.stderr.write("Usage: launch-recall push <remote-url-or-path>\n");
|
|
814
|
+
process.exit(2);
|
|
815
|
+
}
|
|
816
|
+
const { workTree, gitDir } = resolveRecallPaths();
|
|
817
|
+
if (!fs8.existsSync(gitDir)) {
|
|
818
|
+
process.stderr.write(`[launch-recall] not initialised \u2014 run: launch-recall init
|
|
819
|
+
`);
|
|
820
|
+
process.exit(1);
|
|
821
|
+
}
|
|
822
|
+
const env = gitEnv(gitDir, workTree);
|
|
823
|
+
const code = await runGit(["push", "--mirror", remote], { env });
|
|
824
|
+
process.exit(code);
|
|
825
|
+
}
|
|
826
|
+
var fs8;
|
|
827
|
+
var init_push = __esm({
|
|
828
|
+
"src/server/recall/push.ts"() {
|
|
829
|
+
"use strict";
|
|
830
|
+
fs8 = __toESM(require("node:fs"));
|
|
831
|
+
init_git();
|
|
832
|
+
init_paths();
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
// src/server/recall/gc.ts
|
|
837
|
+
var gc_exports = {};
|
|
838
|
+
__export(gc_exports, {
|
|
839
|
+
runGc: () => runGc
|
|
840
|
+
});
|
|
841
|
+
async function runGc(_args) {
|
|
842
|
+
const { workTree, gitDir } = resolveRecallPaths();
|
|
843
|
+
if (!fs9.existsSync(gitDir)) {
|
|
844
|
+
process.stderr.write(`[launch-recall] not initialised \u2014 run: launch-recall init
|
|
845
|
+
`);
|
|
846
|
+
process.exit(1);
|
|
847
|
+
}
|
|
848
|
+
const env = gitEnv(gitDir, workTree);
|
|
849
|
+
const code = await runGit(["gc", "--auto"], { env });
|
|
850
|
+
process.exit(code);
|
|
851
|
+
}
|
|
852
|
+
var fs9;
|
|
853
|
+
var init_gc = __esm({
|
|
854
|
+
"src/server/recall/gc.ts"() {
|
|
855
|
+
"use strict";
|
|
856
|
+
fs9 = __toESM(require("node:fs"));
|
|
857
|
+
init_git();
|
|
858
|
+
init_paths();
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
// src/server/recall/uninstall.ts
|
|
863
|
+
var uninstall_exports = {};
|
|
864
|
+
__export(uninstall_exports, {
|
|
865
|
+
runUninstall: () => runUninstall
|
|
866
|
+
});
|
|
867
|
+
function parseArgs3(args) {
|
|
868
|
+
const out = { keepHistory: false, keepConfig: false, force: false };
|
|
869
|
+
for (const a of args) {
|
|
870
|
+
if (a === "--keep-history") out.keepHistory = true;
|
|
871
|
+
else if (a === "--keep-config") out.keepConfig = true;
|
|
872
|
+
else if (a === "--force" || a === "-y") out.force = true;
|
|
873
|
+
else {
|
|
874
|
+
process.stderr.write(`[launch-recall] unknown uninstall arg: ${a}
|
|
875
|
+
`);
|
|
876
|
+
process.exit(2);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
return out;
|
|
880
|
+
}
|
|
881
|
+
function formatSize(bytes) {
|
|
882
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
883
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
884
|
+
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
885
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
|
886
|
+
}
|
|
887
|
+
function dirSizeBytes(dir) {
|
|
888
|
+
if (!fs10.existsSync(dir)) return 0;
|
|
889
|
+
let total = 0;
|
|
890
|
+
const stack = [dir];
|
|
891
|
+
while (stack.length > 0) {
|
|
892
|
+
const cur = stack.pop();
|
|
893
|
+
let entries;
|
|
894
|
+
try {
|
|
895
|
+
entries = fs10.readdirSync(cur, { withFileTypes: true });
|
|
896
|
+
} catch {
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
for (const e of entries) {
|
|
900
|
+
const full = path6.join(cur, e.name);
|
|
901
|
+
try {
|
|
902
|
+
if (e.isDirectory()) {
|
|
903
|
+
stack.push(full);
|
|
904
|
+
} else if (e.isFile()) {
|
|
905
|
+
total += fs10.statSync(full).size;
|
|
906
|
+
}
|
|
907
|
+
} catch {
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return total;
|
|
912
|
+
}
|
|
913
|
+
function promptYesNo(question) {
|
|
914
|
+
return new Promise((resolve3) => {
|
|
915
|
+
if (!process.stdin.isTTY) {
|
|
916
|
+
process.stderr.write(
|
|
917
|
+
`${question} \u2014 non-interactive shell, refusing without --force
|
|
918
|
+
`
|
|
919
|
+
);
|
|
920
|
+
resolve3(false);
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
924
|
+
rl.question(`${question} (y/N): `, (answer) => {
|
|
925
|
+
rl.close();
|
|
926
|
+
const a = answer.trim().toLowerCase();
|
|
927
|
+
resolve3(a === "y" || a === "yes");
|
|
928
|
+
});
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
function removeGitignoreLine(gitignorePath) {
|
|
932
|
+
if (!fs10.existsSync(gitignorePath)) return "no-file";
|
|
933
|
+
const text = fs10.readFileSync(gitignorePath, "utf8");
|
|
934
|
+
const lines = text.split(/\r?\n/);
|
|
935
|
+
const matches = (l) => {
|
|
936
|
+
const t = l.trim();
|
|
937
|
+
return t === `/${RECALL_DIR_NAME}/` || t === `${RECALL_DIR_NAME}/` || t === RECALL_DIR_NAME || t === `/${RECALL_DIR_NAME}` || t === `${RECALL_DIR_NAME}/**`;
|
|
938
|
+
};
|
|
939
|
+
if (!lines.some(matches)) return "no-line";
|
|
940
|
+
const kept = lines.filter((l) => !matches(l));
|
|
941
|
+
fs10.writeFileSync(gitignorePath, kept.join("\n"));
|
|
942
|
+
return "removed";
|
|
943
|
+
}
|
|
944
|
+
async function runUninstall(args) {
|
|
945
|
+
const parsed = parseArgs3(args);
|
|
946
|
+
const { workTree, recallDir } = resolveRecallPaths();
|
|
947
|
+
const configPath = path6.join(workTree, CONFIG_FILENAME);
|
|
948
|
+
const gitignorePath = path6.join(workTree, ".gitignore");
|
|
949
|
+
const pf = pidFilePath(recallDir);
|
|
950
|
+
const watcherRunning = fs10.existsSync(pf);
|
|
951
|
+
const shadowPresent = fs10.existsSync(recallDir);
|
|
952
|
+
const configPresent = fs10.existsSync(configPath);
|
|
953
|
+
const shadowSize = shadowPresent ? dirSizeBytes(recallDir) : 0;
|
|
954
|
+
let gitignoreHasLine = false;
|
|
955
|
+
if (fs10.existsSync(gitignorePath)) {
|
|
956
|
+
const text = fs10.readFileSync(gitignorePath, "utf8");
|
|
957
|
+
gitignoreHasLine = text.split(/\r?\n/).some((l) => {
|
|
958
|
+
const t = l.trim();
|
|
959
|
+
return t === `/${RECALL_DIR_NAME}/` || t === `${RECALL_DIR_NAME}/` || t === RECALL_DIR_NAME || t === `/${RECALL_DIR_NAME}` || t === `${RECALL_DIR_NAME}/**`;
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
const willStopWatcher = watcherRunning;
|
|
963
|
+
const willRemoveShadow = !parsed.keepHistory && shadowPresent;
|
|
964
|
+
const willRemoveConfig = !parsed.keepConfig && configPresent;
|
|
965
|
+
const willPatchGitignore = !parsed.keepConfig && gitignoreHasLine;
|
|
966
|
+
const plan = [];
|
|
967
|
+
if (willStopWatcher) plan.push("Stop running watcher");
|
|
968
|
+
if (willRemoveShadow) plan.push(`Delete ${recallDir} (${formatSize(shadowSize)})`);
|
|
969
|
+
if (willRemoveConfig) plan.push(`Delete ${configPath}`);
|
|
970
|
+
if (willPatchGitignore) plan.push(`Remove /${RECALL_DIR_NAME}/ from .gitignore`);
|
|
971
|
+
if (plan.length === 0) {
|
|
972
|
+
process.stderr.write("[launch-recall] nothing to uninstall\n");
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
process.stderr.write("[launch-recall] uninstall plan:\n");
|
|
976
|
+
for (const a of plan) process.stderr.write(` - ${a}
|
|
977
|
+
`);
|
|
978
|
+
if (!parsed.force) {
|
|
979
|
+
const ok = await promptYesNo("Proceed?");
|
|
980
|
+
if (!ok) {
|
|
981
|
+
process.stderr.write("[launch-recall] aborted\n");
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
if (willStopWatcher) {
|
|
986
|
+
await stopWatcher(false);
|
|
987
|
+
}
|
|
988
|
+
if (willRemoveShadow) {
|
|
989
|
+
fs10.rmSync(recallDir, { recursive: true, force: true });
|
|
990
|
+
process.stderr.write(`[launch-recall] removed ${recallDir}
|
|
991
|
+
`);
|
|
992
|
+
}
|
|
993
|
+
if (willRemoveConfig) {
|
|
994
|
+
try {
|
|
995
|
+
fs10.unlinkSync(configPath);
|
|
996
|
+
process.stderr.write(`[launch-recall] removed ${configPath}
|
|
997
|
+
`);
|
|
998
|
+
} catch {
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
if (willPatchGitignore) {
|
|
1002
|
+
const res = removeGitignoreLine(gitignorePath);
|
|
1003
|
+
if (res === "removed") {
|
|
1004
|
+
process.stderr.write(`[launch-recall] removed /${RECALL_DIR_NAME}/ from .gitignore
|
|
1005
|
+
`);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
process.stderr.write("[launch-recall] uninstall complete\n");
|
|
1009
|
+
}
|
|
1010
|
+
var fs10, path6, readline;
|
|
1011
|
+
var init_uninstall = __esm({
|
|
1012
|
+
"src/server/recall/uninstall.ts"() {
|
|
1013
|
+
"use strict";
|
|
1014
|
+
fs10 = __toESM(require("node:fs"));
|
|
1015
|
+
path6 = __toESM(require("node:path"));
|
|
1016
|
+
readline = __toESM(require("node:readline"));
|
|
1017
|
+
init_config();
|
|
1018
|
+
init_paths();
|
|
1019
|
+
init_stop();
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// src/server/recall-entry.ts
|
|
1024
|
+
function logStderr(msg) {
|
|
1025
|
+
process.stderr.write(`[launch-recall] ${msg}
|
|
1026
|
+
`);
|
|
1027
|
+
}
|
|
1028
|
+
function printUsage() {
|
|
1029
|
+
process.stdout.write(
|
|
1030
|
+
[
|
|
1031
|
+
"Usage: launch-recall <command> [options]",
|
|
1032
|
+
"",
|
|
1033
|
+
"Commands:",
|
|
1034
|
+
" init create .recall/repo.git + gitignore entry + default config",
|
|
1035
|
+
" watch [--debounce <ms>] foreground watcher (defaults from .launch-recall.json)",
|
|
1036
|
+
" stop terminate the running watcher",
|
|
1037
|
+
" log [path] show shadow history (passthrough to git log)",
|
|
1038
|
+
" restore <path> [--at <ref>] extract a file from a snapshot",
|
|
1039
|
+
" forget [--keep-last N] [--max-age 30d] [--dry-run]",
|
|
1040
|
+
" prune history per retention rules",
|
|
1041
|
+
" push <remote> mirror shadow to an external bare repo",
|
|
1042
|
+
" gc pack and prune the shadow repo",
|
|
1043
|
+
" uninstall [--keep-history] [--keep-config] [--force]",
|
|
1044
|
+
" stop watcher + remove shadow + config + gitignore line",
|
|
1045
|
+
""
|
|
1046
|
+
].join("\n")
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
async function main() {
|
|
1050
|
+
const argv = process.argv.slice(2);
|
|
1051
|
+
const subcommand = argv[0];
|
|
1052
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
1053
|
+
printUsage();
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
switch (subcommand) {
|
|
1057
|
+
case "init": {
|
|
1058
|
+
const { runInit: runInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
1059
|
+
await runInit2(argv.slice(1));
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
case "watch": {
|
|
1063
|
+
const { runWatch: runWatch2 } = await Promise.resolve().then(() => (init_watch(), watch_exports));
|
|
1064
|
+
await runWatch2(argv.slice(1));
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
case "stop": {
|
|
1068
|
+
const { runStop: runStop2 } = await Promise.resolve().then(() => (init_stop(), stop_exports));
|
|
1069
|
+
await runStop2(argv.slice(1));
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
case "log": {
|
|
1073
|
+
const { runLog: runLog2 } = await Promise.resolve().then(() => (init_log(), log_exports));
|
|
1074
|
+
await runLog2(argv.slice(1));
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
case "restore": {
|
|
1078
|
+
const { runRestore: runRestore2 } = await Promise.resolve().then(() => (init_restore(), restore_exports));
|
|
1079
|
+
await runRestore2(argv.slice(1));
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
case "forget": {
|
|
1083
|
+
const { runForget: runForget2 } = await Promise.resolve().then(() => (init_forget(), forget_exports));
|
|
1084
|
+
await runForget2(argv.slice(1));
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
case "push": {
|
|
1088
|
+
const { runPush: runPush2 } = await Promise.resolve().then(() => (init_push(), push_exports));
|
|
1089
|
+
await runPush2(argv.slice(1));
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
case "gc": {
|
|
1093
|
+
const { runGc: runGc2 } = await Promise.resolve().then(() => (init_gc(), gc_exports));
|
|
1094
|
+
await runGc2(argv.slice(1));
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
case "uninstall": {
|
|
1098
|
+
const { runUninstall: runUninstall2 } = await Promise.resolve().then(() => (init_uninstall(), uninstall_exports));
|
|
1099
|
+
await runUninstall2(argv.slice(1));
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
default: {
|
|
1103
|
+
logStderr(`unknown command: ${subcommand}`);
|
|
1104
|
+
printUsage();
|
|
1105
|
+
process.exit(2);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
main().catch((err) => {
|
|
1110
|
+
logStderr(`fatal: ${err instanceof Error ? err.message : String(err)}`);
|
|
1111
|
+
process.exit(1);
|
|
1112
|
+
});
|