getculpa 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/assets/culpa-compose.yml +4 -4
- package/assets/culpa-relay-fly.toml +70 -0
- package/bin/getculpa.js +34 -6
- package/lib/assets.mjs +39 -36
- package/lib/bootstrap.d.mts +4 -0
- package/lib/bootstrap.mjs +25 -1
- package/lib/dispatch.d.mts +12 -0
- package/lib/dispatch.mjs +59 -0
- package/lib/doctor.mjs +17 -2
- package/lib/install-summary.d.mts +1 -1
- package/lib/install-summary.mjs +22 -10
- package/lib/provision.mjs +329 -318
- package/lib/start.mjs +8 -3
- package/lib/uninstall.mjs +45 -6
- package/package.json +1 -1
- package/scripts/install.js +7 -3
- package/scripts/prepack.js +16 -4
package/lib/start.mjs
CHANGED
|
@@ -415,10 +415,15 @@ async function runPosixStateMachine({ appDir, liveCompose, platform, spawnSync,
|
|
|
415
415
|
};
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
//
|
|
419
|
-
//
|
|
418
|
+
// V102 T-V102-14 (M4, D-113): the old line here said "no collector build
|
|
419
|
+
// ships for macOS/Linux yet" — verified FALSE on real hardware (the arm64
|
|
420
|
+
// collectord ships, was staged executable, install-state recorded
|
|
421
|
+
// collectorStaged: true). What IS true: the collector is not auto-started
|
|
422
|
+
// on this platform yet, while the server-side coding-tool log sweep works
|
|
423
|
+
// (proven live on the Mac: calls landed unattended, ~45 min cadence). Say
|
|
424
|
+
// exactly that — neither direction of the old overclaim.
|
|
420
425
|
stagesRun.push(STAGES.START_CULPA);
|
|
421
|
-
log("getculpa:
|
|
426
|
+
log("getculpa: your local coding-tool usage is captured by the built-in log sweep. The production traffic collector is not started automatically on this platform yet - everything else works normally.");
|
|
422
427
|
|
|
423
428
|
stagesRun.push(STAGES.OPEN_UI);
|
|
424
429
|
if (pinnedVersion) writeFileSync(path.join(appDir, "last-boot-version.txt"), `${pinnedVersion}\n`);
|
package/lib/uninstall.mjs
CHANGED
|
@@ -62,12 +62,36 @@ async function promptPgdataRemoval(createInterface, isTTY) {
|
|
|
62
62
|
if (!isTTY) return false;
|
|
63
63
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
64
64
|
const answer = await new Promise((resolve) => {
|
|
65
|
+
// V102 T-V102-16 (D-113): EOF (Ctrl-D, or a stdin that ends mid-prompt)
|
|
66
|
+
// fires `close` and NEVER invokes question()'s callback — this promise
|
|
67
|
+
// used to hang forever at the one prompt guarding DELETION of the cost
|
|
68
|
+
// database. An unanswered question is a NO, exactly like tty.mjs.
|
|
69
|
+
// Optional-call: older injected fakes without `once` keep working.
|
|
70
|
+
rl.once?.("close", () => resolve(""));
|
|
65
71
|
rl.question("Also DELETE all recorded cost data? This cannot be undone. (y/N) ", resolve);
|
|
66
72
|
});
|
|
67
73
|
rl.close();
|
|
68
74
|
return answer.trim().toLowerCase() === "y";
|
|
69
75
|
}
|
|
70
76
|
|
|
77
|
+
// V102 T-V102-16 (M11/W2, D-113): macOS uninstall exited 0 leaving ~7.3 MB
|
|
78
|
+
// (launcher, collector, compose, register.mjs) silently behind — the Windows
|
|
79
|
+
// ps1 removes the app dir and is "the more complete of the two" (W2). Remove
|
|
80
|
+
// the dir ONLY when it is provably a Culpa install dir (install-state.json,
|
|
81
|
+
// which every install writes); a mistargeted CULPA_APP_DIR is kept and said.
|
|
82
|
+
// Truthful beats a surprise rm -rf in both directions.
|
|
83
|
+
function removeAppDir(appDir) {
|
|
84
|
+
if (!existsSync(appDir)) return;
|
|
85
|
+
if (existsSync(path.join(appDir, "install-state.json"))) {
|
|
86
|
+
rmSync(appDir, { recursive: true, force: true });
|
|
87
|
+
console.log(`Removed: ${appDir} (launcher, collector, compose and capture shims).`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
console.log(
|
|
91
|
+
`Kept: ${appDir} - no install-state.json found there, so it is not provably a Culpa install directory. Remove it yourself if you are sure.`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
71
95
|
export async function uninstall(opts = {}) {
|
|
72
96
|
const appDir = opts.appDir ?? getAppDir();
|
|
73
97
|
const platform = opts.platform ?? process.platform;
|
|
@@ -82,13 +106,28 @@ export async function uninstall(opts = {}) {
|
|
|
82
106
|
if (!ok) console.error("getculpa: uninstall did not complete cleanly - see the output above.");
|
|
83
107
|
} else {
|
|
84
108
|
ok = composeDown(appDir, spawnSync);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
109
|
+
// Review-4 IMPORTANT + CodeRabbit PR#19 [7] (Major): a FAILED stop skips
|
|
110
|
+
// EVERY destructive step — the ps1's $stackStopped gate, whose comment
|
|
111
|
+
// records the prior real incident (CR-PR5 round 3). Not even the pgdata
|
|
112
|
+
// PROMPT is offered: after a partial teardown the volume can be
|
|
113
|
+
// unreferenced, so a user confirming deletion here could lose the cost
|
|
114
|
+
// database while being told the stack is still running. Nothing is
|
|
115
|
+
// removed; the one honest instruction is to stop the stack and rerun.
|
|
116
|
+
if (!ok) {
|
|
117
|
+
console.log(
|
|
118
|
+
`Files kept: ${appDir} - the stack is still running (\`docker compose down\` failed above). Nothing was removed. Stop the stack, then run this again.`,
|
|
119
|
+
);
|
|
90
120
|
} else {
|
|
91
|
-
|
|
121
|
+
removeShortcutEquivalents(homedir);
|
|
122
|
+
const wipe = await promptPgdataRemoval(createInterface, isTTY);
|
|
123
|
+
if (wipe) {
|
|
124
|
+
spawnSync("docker", ["volume", "rm", "culpa_pgdata"], { stdio: "inherit" });
|
|
125
|
+
console.log("Data volume removed.");
|
|
126
|
+
} else {
|
|
127
|
+
console.log("Data kept (volume culpa_pgdata). Reinstalling later will find it again.");
|
|
128
|
+
}
|
|
129
|
+
// M11/W2: after the data decision, remove the app dir itself (ps1 parity)
|
|
130
|
+
removeAppDir(appDir);
|
|
92
131
|
}
|
|
93
132
|
}
|
|
94
133
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "getculpa",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Culpa CLI: `npm i -g getculpa` provisions the full Culpa install (Windows-installer parity) and leaves it dormant. `getculpa` wakes the stack.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"bin": {
|
package/scripts/install.js
CHANGED
|
@@ -119,11 +119,15 @@ async function main() {
|
|
|
119
119
|
// `getculpa` dead-ends — the Mac tester's exact experience. Best-effort by
|
|
120
120
|
// construction: any failure leaves the payload deferred and the summary
|
|
121
121
|
// below names `getculpa update`, which is where we already were.
|
|
122
|
-
const { stageInitialPayload, vendoredLauncherPath } = await import("../lib/bootstrap.mjs");
|
|
123
|
-
|
|
122
|
+
const { readPayloadState, stageInitialPayload, vendoredLauncherPath } = await import("../lib/bootstrap.mjs");
|
|
123
|
+
stageInitialPayload({
|
|
124
124
|
launcherPath: vendoredLauncherPath(path.join(__dirname, "..")),
|
|
125
125
|
env: process.env,
|
|
126
126
|
});
|
|
127
|
+
// V102 T-V102-15 (M3): the summary reports what updates/state.json actually
|
|
128
|
+
// says, never the updater's exit code — "installed" was claimed on a Mac
|
|
129
|
+
// whose state read current: null while doctor FAILed the same install.
|
|
130
|
+
const payloadState = readPayloadState({ env: process.env });
|
|
127
131
|
|
|
128
132
|
// CF20-T6: the completion line names what actually happened — an upgrade
|
|
129
133
|
// is STAGED only; the new version applies at the next `getculpa`, not here.
|
|
@@ -139,7 +143,7 @@ async function main() {
|
|
|
139
143
|
dockerState,
|
|
140
144
|
imagesStaged,
|
|
141
145
|
collectorStaged,
|
|
142
|
-
|
|
146
|
+
payloadState,
|
|
143
147
|
platform: process.platform,
|
|
144
148
|
isTTY: Boolean(process.stdout.isTTY),
|
|
145
149
|
env: process.env,
|
package/scripts/prepack.js
CHANGED
|
@@ -14,6 +14,9 @@ const pkgRoot = path.join(__dirname, "..");
|
|
|
14
14
|
const repoRoot = path.join(pkgRoot, "..", "..");
|
|
15
15
|
const assetsDir = path.join(pkgRoot, "assets");
|
|
16
16
|
|
|
17
|
+
// An entry is either the repo-relative path parts (staged under its own
|
|
18
|
+
// basename) or { src: [...parts], as: "name" } when the canonical file's
|
|
19
|
+
// basename is too generic to sit in a customer's install folder.
|
|
17
20
|
const SOURCES = [
|
|
18
21
|
["installers", "culpa-compose.yml"],
|
|
19
22
|
["installers", "windows", "install-culpa.ps1"],
|
|
@@ -21,6 +24,14 @@ const SOURCES = [
|
|
|
21
24
|
["installers", "windows", "uninstall-culpa.ps1"],
|
|
22
25
|
["installers", "windows", "culpa-collector.ps1"],
|
|
23
26
|
["collector", "node", "register.mjs"],
|
|
27
|
+
// ISS-V103-9: the dashboard's Fly relay tab prints
|
|
28
|
+
// `flyctl deploy --config <this file>` and tells the customer to run it from
|
|
29
|
+
// their Culpa install folder. It shipped in NEITHER the install folder nor
|
|
30
|
+
// the npm package — it existed only in the source repo — so the Fly relay
|
|
31
|
+
// path could not be completed by anyone who installed via npm. Staged under
|
|
32
|
+
// an explicit name because a bare `fly.toml` in the install folder would
|
|
33
|
+
// read as the customer's OWN app config.
|
|
34
|
+
{ src: ["deploy", "relay", "fly.toml"], as: "culpa-relay-fly.toml" },
|
|
24
35
|
];
|
|
25
36
|
|
|
26
37
|
// CF20-R: clear assets/ before restaging — otherwise a canonical source file
|
|
@@ -29,13 +40,14 @@ const SOURCES = [
|
|
|
29
40
|
// hand-edited, so nothing else would ever remove it).
|
|
30
41
|
fs.rmSync(assetsDir, { recursive: true, force: true });
|
|
31
42
|
fs.mkdirSync(assetsDir, { recursive: true });
|
|
32
|
-
for (const
|
|
43
|
+
for (const entry of SOURCES) {
|
|
44
|
+
const parts = Array.isArray(entry) ? entry : entry.src;
|
|
33
45
|
const src = path.join(repoRoot, ...parts);
|
|
34
46
|
if (!fs.existsSync(src)) {
|
|
35
47
|
console.error(`prepack: missing canonical source ${src}`);
|
|
36
48
|
process.exit(1);
|
|
37
49
|
}
|
|
38
|
-
const
|
|
39
|
-
fs.copyFileSync(src,
|
|
40
|
-
console.log(`prepack: staged ${
|
|
50
|
+
const name = Array.isArray(entry) ? path.basename(src) : entry.as;
|
|
51
|
+
fs.copyFileSync(src, path.join(assetsDir, name));
|
|
52
|
+
console.log(`prepack: staged ${name}`);
|
|
41
53
|
}
|