agent-afk 5.249.0 → 5.249.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/_lib/commit-block.d.ts +1 -0
- package/dist/cli/commands/interactive/tool-lane.scrollback-separator.d.ts +1 -0
- package/dist/cli.mjs +247 -245
- package/dist/index.mjs +111 -111
- package/dist/postinstall.mjs +70 -12
- package/dist/telegram.mjs +130 -130
- package/package.json +1 -1
- package/scripts/postinstall.mjs +70 -12
package/dist/postinstall.mjs
CHANGED
|
@@ -30,6 +30,47 @@ export function detectPathGap(prefix, pathEnv) {
|
|
|
30
30
|
return { onPath, binDir };
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Pure function. Determines whether this postinstall run is part of a global
|
|
35
|
+
* package install (`npm install -g` / `pnpm add -g`) as opposed to a local
|
|
36
|
+
* dev-checkout `pnpm install` or a worktree install.
|
|
37
|
+
*
|
|
38
|
+
* Detection uses two independent signals and fails CLOSED toward NOT-global
|
|
39
|
+
* (i.e. no restart) whenever either signal is uncertain:
|
|
40
|
+
*
|
|
41
|
+
* 1. npm_config_global env var — npm and pnpm both set this to the string
|
|
42
|
+
* "true" for every global install. A local `pnpm install` inside a repo
|
|
43
|
+
* never sets it. This is the primary, cheapest signal.
|
|
44
|
+
*
|
|
45
|
+
* 2. git-worktree presence check — if the package root contains a .git
|
|
46
|
+
* entry (file or directory) it is a source checkout or managed worktree,
|
|
47
|
+
* never a globally-installed package. A global install lands under
|
|
48
|
+
* node_modules inside the global npm prefix, never inside a git tree.
|
|
49
|
+
* This is a belt-and-suspenders guard: even if npm_config_global were
|
|
50
|
+
* wrong or missing, a .git marker unambiguously rules out a global install.
|
|
51
|
+
*
|
|
52
|
+
* // History: Daemon was unconditionally restarted on every postinstall.
|
|
53
|
+
* // A cron job that ran `pnpm install` inside a repo worktree triggered this
|
|
54
|
+
* // path and restarted the running daemon mid-session, orphaning 438 subagents
|
|
55
|
+
* // and leaving the daemon stopped. The guard introduced here ensures restarts
|
|
56
|
+
* // occur ONLY for genuine global upgrades. See PR #2194.
|
|
57
|
+
*
|
|
58
|
+
* @param {string} pkgRoot - Absolute path to the package root.
|
|
59
|
+
* @param {object} [env] - Environment variable bag; defaults to process.env.
|
|
60
|
+
* @param {function} [existsFn] - Injectable fs.existsSync for testing.
|
|
61
|
+
* @returns {boolean} true only when both signals confirm a global install.
|
|
62
|
+
*/
|
|
63
|
+
export function isGlobalInstall(pkgRoot, env = process.env, existsFn = existsSync) {
|
|
64
|
+
// Signal 1: npm/pnpm lifecycle env var. Absent or non-"true" → not global.
|
|
65
|
+
if (env['npm_config_global'] !== 'true') return false;
|
|
66
|
+
|
|
67
|
+
// Signal 2: .git marker. Present → source checkout / worktree → not global.
|
|
68
|
+
const gitMarker = join(pkgRoot, '.git');
|
|
69
|
+
if (existsFn(gitMarker)) return false;
|
|
70
|
+
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
33
74
|
/**
|
|
34
75
|
* Pure function. Attempts to SIGTERM a daemon whose PID is written in the
|
|
35
76
|
* given file. All errors are silently discarded — this is best-effort cleanup
|
|
@@ -102,6 +143,13 @@ export function isManualBotRunning(pidFilePath, probeFn = process.kill) {
|
|
|
102
143
|
* is swallowed so the install never fails. macOS only — the caller gates on
|
|
103
144
|
* platform; elsewhere ~/Library/LaunchAgents won't exist so nothing restarts.
|
|
104
145
|
*
|
|
146
|
+
* // Invariant: the daemon is NOT stateless. It may be mid-run on one or more
|
|
147
|
+
* // scheduled agent sessions. This function MUST only be called from a global
|
|
148
|
+
* // package upgrade path (verified by isGlobalInstall()) — never from a local
|
|
149
|
+
* // `pnpm install` inside a source checkout or worktree. The caller in the main
|
|
150
|
+
* // block enforces this via isGlobalInstall(); callers in tests must pass stubs
|
|
151
|
+
* // for execFn/restartFn so real launchctl is never invoked.
|
|
152
|
+
*
|
|
105
153
|
* Label / path / domain conventions mirror src/service/launchd/paths.ts
|
|
106
154
|
* (labelFor → `com.afk.<name>`, plist under ~/Library/LaunchAgents, guiDomain →
|
|
107
155
|
* `gui/<uid>`). Kept in sync by hand — this plain .mjs cannot import the
|
|
@@ -260,20 +308,30 @@ if (isMain) {
|
|
|
260
308
|
// here bypasses that session-safety logic and is the root cause of "sessions
|
|
261
309
|
// that work but never respond" — see telegram-stuck-diagnosis.md.
|
|
262
310
|
//
|
|
263
|
-
//
|
|
311
|
+
// Invariant: the daemon may be mid-run on scheduled agent sessions and is
|
|
312
|
+
// NOT safe to restart unconditionally. Service restart is only correct for a
|
|
313
|
+
// global package upgrade (`npm install -g`). A local `pnpm install` inside a
|
|
314
|
+
// source checkout or managed worktree must NEVER trigger a restart — doing so
|
|
315
|
+
// kills any in-flight sessions owned by that daemon. The isGlobalInstall()
|
|
316
|
+
// guard below enforces this; it fails closed toward NOT restarting whenever
|
|
317
|
+
// either detection signal is absent or ambiguous.
|
|
264
318
|
if (process.platform === 'darwin') {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
319
|
+
const scriptDir = new URL('.', import.meta.url).pathname;
|
|
320
|
+
const pkgRoot = join(scriptDir, '..');
|
|
321
|
+
if (isGlobalInstall(pkgRoot, process.env, existsSync)) {
|
|
322
|
+
try {
|
|
323
|
+
const restarted = restartLaunchdServices({
|
|
324
|
+
labels: ['com.afk.daemon'],
|
|
325
|
+
});
|
|
326
|
+
if (restarted.length > 0) {
|
|
327
|
+
const names = restarted.map((l) => l.replace(/^com\.afk\./, '')).join(', ');
|
|
328
|
+
process.stdout.write(
|
|
329
|
+
`\n↻ Restarted AFK service(s) onto the new version: ${names}\n`,
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
} catch {
|
|
333
|
+
// restartLaunchdServices is already fail-open; belt-and-suspenders.
|
|
274
334
|
}
|
|
275
|
-
} catch {
|
|
276
|
-
// restartLaunchdServices is already fail-open; belt-and-suspenders.
|
|
277
335
|
}
|
|
278
336
|
}
|
|
279
337
|
|