mthds 0.6.3 → 0.7.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/dist/agent/binaries.js +2 -2
- package/dist/agent/commands/bootstrap.js +2 -10
- package/dist/agent/commands/bootstrap.js.map +1 -1
- package/dist/agent/commands/codex-config.d.ts +29 -15
- package/dist/agent/commands/codex-config.js +206 -127
- package/dist/agent/commands/codex-config.js.map +1 -1
- package/dist/agent/commands/codex-hook.d.ts +4 -6
- package/dist/agent/commands/codex-hook.js +6 -8
- package/dist/agent/commands/codex-hook.js.map +1 -1
- package/dist/agent/commands/codex.d.ts +32 -19
- package/dist/agent/commands/codex.js +87 -134
- package/dist/agent/commands/codex.js.map +1 -1
- package/dist/agent/commands/doctor.js +49 -13
- package/dist/agent/commands/doctor.js.map +1 -1
- package/dist/agent/commands/update-check.js +1 -30
- package/dist/agent/commands/update-check.js.map +1 -1
- package/dist/agent/commands/upgrade.js +3 -12
- package/dist/agent/commands/upgrade.js.map +1 -1
- package/dist/agent/plugin-version.d.ts +19 -17
- package/dist/agent/plugin-version.js +21 -20
- package/dist/agent/plugin-version.js.map +1 -1
- package/dist/agent/snooze.d.ts +30 -4
- package/dist/agent/snooze.js +99 -35
- package/dist/agent/snooze.js.map +1 -1
- package/dist/agent/update-cache.d.ts +59 -15
- package/dist/agent/update-cache.js +178 -24
- package/dist/agent/update-cache.js.map +1 -1
- package/dist/agent-cli.js +2 -10
- package/dist/agent-cli.js.map +1 -1
- package/package.json +1 -1
package/dist/agent/snooze.js
CHANGED
|
@@ -1,23 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Snooze state for update-check upgrade prompts.
|
|
3
3
|
*
|
|
4
|
-
* Manages
|
|
4
|
+
* Manages a single-line file:
|
|
5
5
|
* <versionKey> <level> <epoch>
|
|
6
6
|
*
|
|
7
|
+
* Primary location: ~/.mthds/state/update-snoozed.
|
|
8
|
+
* Fallback location: $TMPDIR/mthds-agent/update-snoozed — used when the
|
|
9
|
+
* primary location is not writable (Codex `workspaceWrite` sandbox permits
|
|
10
|
+
* writes only under cwd / configured roots / $TMPDIR, not under the user's
|
|
11
|
+
* home dir). Same dual-path policy as the update-check cache and the
|
|
12
|
+
* just-upgraded marker — see update-cache.ts.
|
|
13
|
+
*
|
|
14
|
+
* Reads consult both paths and prefer the newer mtime, so escalation
|
|
15
|
+
* (level 1 → 2 → 3+) stays correct as sessions move between sandboxed and
|
|
16
|
+
* non-sandboxed contexts.
|
|
17
|
+
*
|
|
7
18
|
* Version key is a plain concatenation of binary statuses (human-readable).
|
|
8
19
|
* Escalating backoff: level 1 = 24h, level 2 = 48h, level 3+ = 7d.
|
|
9
20
|
* Snooze resets when the version key changes (any binary constraint updated).
|
|
10
21
|
*/
|
|
11
22
|
import { join } from "node:path";
|
|
12
|
-
import { readFileSync,
|
|
13
|
-
import {
|
|
23
|
+
import { readFileSync, statSync, existsSync } from "node:fs";
|
|
24
|
+
import { homedir, tmpdir } from "node:os";
|
|
25
|
+
import { SANDBOX_WRITE_ERRORS, writeFileAt, invalidateFileAt, } from "./update-cache.js";
|
|
14
26
|
// ── Constants ──────────────────────────────────────────────────────
|
|
15
|
-
const
|
|
27
|
+
const STATE_DIR = join(homedir(), ".mthds", "state");
|
|
28
|
+
const PRIMARY_SNOOZE_PATH = join(STATE_DIR, "update-snoozed");
|
|
29
|
+
const FALLBACK_DIR = join(tmpdir(), "mthds-agent");
|
|
30
|
+
const FALLBACK_SNOOZE_PATH = join(FALLBACK_DIR, "update-snoozed");
|
|
16
31
|
const SNOOZE_DURATIONS_MS = {
|
|
17
32
|
1: 24 * 60 * 60 * 1000, // 24h
|
|
18
33
|
2: 48 * 60 * 60 * 1000, // 48h
|
|
19
34
|
};
|
|
20
35
|
const SNOOZE_DEFAULT_MS = 7 * 24 * 60 * 60 * 1000; // 7d for level 3+
|
|
36
|
+
// ── Per-process warning latches ────────────────────────────────────
|
|
37
|
+
let warnedAboutSnoozeWrite = false;
|
|
38
|
+
let warnedAboutSnoozeClear = false;
|
|
21
39
|
// ── Functions ──────────────────────────────────────────────────────
|
|
22
40
|
/**
|
|
23
41
|
* Compute a human-readable version key from a cache payload.
|
|
@@ -37,22 +55,17 @@ export function computeVersionKey(payload) {
|
|
|
37
55
|
}
|
|
38
56
|
return parts.join(":");
|
|
39
57
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
content = readFileSync(SNOOZE_PATH, "utf-8").trim();
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
58
|
+
function parseSnoozeContent(content) {
|
|
59
|
+
const trimmed = content.trim();
|
|
60
|
+
if (!trimmed)
|
|
47
61
|
return null;
|
|
48
|
-
}
|
|
49
62
|
// Format: "<versionKey> <level> <epoch>"
|
|
50
63
|
// The version key may contain colons but not spaces, so split from the right.
|
|
51
|
-
const lastSpace =
|
|
64
|
+
const lastSpace = trimmed.lastIndexOf(" ");
|
|
52
65
|
if (lastSpace === -1)
|
|
53
66
|
return null;
|
|
54
|
-
const epochStr =
|
|
55
|
-
const rest =
|
|
67
|
+
const epochStr = trimmed.slice(lastSpace + 1);
|
|
68
|
+
const rest = trimmed.slice(0, lastSpace);
|
|
56
69
|
const secondLastSpace = rest.lastIndexOf(" ");
|
|
57
70
|
if (secondLastSpace === -1)
|
|
58
71
|
return null;
|
|
@@ -64,27 +77,67 @@ export function readSnooze() {
|
|
|
64
77
|
return null;
|
|
65
78
|
return { versionKey, level, epoch };
|
|
66
79
|
}
|
|
80
|
+
function readSnoozeAt(path) {
|
|
81
|
+
let mtimeMs;
|
|
82
|
+
let content;
|
|
83
|
+
try {
|
|
84
|
+
mtimeMs = statSync(path).mtimeMs;
|
|
85
|
+
content = readFileSync(path, "utf-8");
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const state = parseSnoozeContent(content);
|
|
91
|
+
if (!state)
|
|
92
|
+
return null;
|
|
93
|
+
return { state, mtimeMs };
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Read current snooze state. Returns null if missing or corrupt.
|
|
97
|
+
*
|
|
98
|
+
* Inspects both the primary and the fallback path; when both have valid
|
|
99
|
+
* contents, the one with the newer mtime wins. This keeps escalation
|
|
100
|
+
* correct when a session moves between sandboxed and non-sandboxed contexts:
|
|
101
|
+
* the older file is a stale snapshot from before the redirect happened.
|
|
102
|
+
*/
|
|
103
|
+
export function readSnooze() {
|
|
104
|
+
const primary = readSnoozeAt(PRIMARY_SNOOZE_PATH);
|
|
105
|
+
const fallback = readSnoozeAt(FALLBACK_SNOOZE_PATH);
|
|
106
|
+
if (!primary)
|
|
107
|
+
return fallback?.state ?? null;
|
|
108
|
+
if (!fallback)
|
|
109
|
+
return primary.state;
|
|
110
|
+
return fallback.mtimeMs > primary.mtimeMs ? fallback.state : primary.state;
|
|
111
|
+
}
|
|
67
112
|
/**
|
|
68
|
-
* Write snooze state. Escalates level if same versionKey, resets if
|
|
113
|
+
* Write snooze state. Escalates level if same versionKey, resets to 1 if
|
|
114
|
+
* different. Sandbox-aware: falls back to $TMPDIR when ~/.mthds/state/ is
|
|
115
|
+
* not writable. Write failures emit a one-shot stderr warning per process.
|
|
69
116
|
*/
|
|
70
117
|
export function writeSnooze(versionKey) {
|
|
71
|
-
ensureStateDir();
|
|
72
118
|
const existing = readSnooze();
|
|
73
|
-
|
|
74
|
-
if (existing && existing.versionKey === versionKey) {
|
|
75
|
-
level = existing.level + 1;
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
level = 1;
|
|
79
|
-
}
|
|
119
|
+
const level = existing && existing.versionKey === versionKey ? existing.level + 1 : 1;
|
|
80
120
|
const content = `${versionKey} ${level} ${Date.now()}\n`;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
121
|
+
const primary = writeFileAt(STATE_DIR, PRIMARY_SNOOZE_PATH, content);
|
|
122
|
+
if (primary.ok)
|
|
123
|
+
return;
|
|
124
|
+
if (primary.code && SANDBOX_WRITE_ERRORS.has(primary.code)) {
|
|
125
|
+
const fallback = writeFileAt(FALLBACK_DIR, FALLBACK_SNOOZE_PATH, content);
|
|
126
|
+
if (fallback.ok)
|
|
127
|
+
return;
|
|
128
|
+
emitSnoozeWriteWarning(primary.code, fallback.code);
|
|
129
|
+
return;
|
|
87
130
|
}
|
|
131
|
+
emitSnoozeWriteWarning(primary.code);
|
|
132
|
+
}
|
|
133
|
+
function emitSnoozeWriteWarning(primaryCode, fallbackCode) {
|
|
134
|
+
if (warnedAboutSnoozeWrite)
|
|
135
|
+
return;
|
|
136
|
+
warnedAboutSnoozeWrite = true;
|
|
137
|
+
const detail = fallbackCode
|
|
138
|
+
? `primary=${primaryCode ?? "?"}, fallback=${fallbackCode}`
|
|
139
|
+
: (primaryCode ?? "?");
|
|
140
|
+
process.stderr.write(`Warning: could not write snooze state (${detail}). The upgrade prompt may re-appear next time.\n`);
|
|
88
141
|
}
|
|
89
142
|
/** Check if snooze is active for the given versionKey. */
|
|
90
143
|
export function isSnoozed(versionKey) {
|
|
@@ -99,13 +152,24 @@ export function isSnoozed(versionKey) {
|
|
|
99
152
|
// Negative elapsed beyond 1 minute means clock skew — treat snooze as expired
|
|
100
153
|
return elapsed >= -60_000 && elapsed < duration;
|
|
101
154
|
}
|
|
102
|
-
/**
|
|
155
|
+
/**
|
|
156
|
+
* Clear snooze. Hits both primary and fallback paths. When unlink is blocked
|
|
157
|
+
* (sandbox EPERM), overwrites with empty content so the next read parses as
|
|
158
|
+
* null. Warns at most once per process when a present file cannot be cleared
|
|
159
|
+
* by either route. Silent when both paths were absent to begin with — no
|
|
160
|
+
* spurious 0-byte file is created in that case.
|
|
161
|
+
*/
|
|
103
162
|
export function clearSnooze() {
|
|
104
|
-
|
|
105
|
-
|
|
163
|
+
let blocked = false;
|
|
164
|
+
for (const path of [PRIMARY_SNOOZE_PATH, FALLBACK_SNOOZE_PATH]) {
|
|
165
|
+
if (!existsSync(path))
|
|
166
|
+
continue;
|
|
167
|
+
if (!invalidateFileAt(path))
|
|
168
|
+
blocked = true;
|
|
106
169
|
}
|
|
107
|
-
|
|
108
|
-
|
|
170
|
+
if (blocked && !warnedAboutSnoozeClear) {
|
|
171
|
+
warnedAboutSnoozeClear = true;
|
|
172
|
+
process.stderr.write(`Warning: could not clear snooze state. The upgrade prompt may stay suppressed until the TTL expires.\n`);
|
|
109
173
|
}
|
|
110
174
|
}
|
|
111
175
|
//# sourceMappingURL=snooze.js.map
|
package/dist/agent/snooze.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snooze.js","sourceRoot":"","sources":["../../src/agent/snooze.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"snooze.js","sourceRoot":"","sources":["../../src/agent/snooze.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cache for update-check results.
|
|
2
|
+
* Cache for update-check results, plus the just-upgraded marker.
|
|
3
3
|
*
|
|
4
|
-
* Primary location: ~/.mthds/state
|
|
5
|
-
* Fallback location: $TMPDIR/mthds-agent/
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* user's home dir).
|
|
4
|
+
* Primary location: ~/.mthds/state/.
|
|
5
|
+
* Fallback location: $TMPDIR/mthds-agent/ — used when the primary location is
|
|
6
|
+
* not writable (e.g. Codex's workspaceWrite sandbox permits writes only under
|
|
7
|
+
* cwd / configured roots / $TMPDIR, not under the user's home dir).
|
|
9
8
|
*
|
|
10
|
-
* Two
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Two files live in each location:
|
|
10
|
+
*
|
|
11
|
+
* 1. `last-update-check` — TTL'd cache of update-check results.
|
|
12
|
+
* Two-line format: aggregate status, then JSON payload of per-binary results.
|
|
13
|
+
* Split TTL: 60 min for UP_TO_DATE, 720 min for UPGRADE_AVAILABLE.
|
|
14
|
+
*
|
|
15
|
+
* 2. `just-upgraded-from` — one-shot marker written by `mthds-agent upgrade`
|
|
16
|
+
* (and bootstrap) so the next update-check can announce what was upgraded.
|
|
17
|
+
* Consumed within the same skill flow, so a short TTL is enough; older
|
|
18
|
+
* markers are treated as stuck (sandbox blocked cleanup last time) and
|
|
19
|
+
* ignored to stop the announcement from replaying forever.
|
|
13
20
|
*
|
|
14
21
|
* TTL is based on file mtime (like gstack), not an embedded timestamp.
|
|
15
|
-
* Split TTL: 60 min for UP_TO_DATE, 720 min for UPGRADE_AVAILABLE.
|
|
16
22
|
*/
|
|
17
23
|
import type { VersionStatus } from "../installer/runtime/version-check.js";
|
|
18
24
|
export type AggregateStatus = "UP_TO_DATE" | "UPGRADE_AVAILABLE";
|
|
@@ -34,18 +40,30 @@ export interface CacheResult {
|
|
|
34
40
|
aggregate: AggregateStatus;
|
|
35
41
|
payload: CachePayload;
|
|
36
42
|
}
|
|
37
|
-
export declare const
|
|
38
|
-
/** Ensure the state directory exists. */
|
|
39
|
-
export declare function ensureStateDir(): void;
|
|
43
|
+
export declare const SANDBOX_WRITE_ERRORS: ReadonlySet<string>;
|
|
40
44
|
/** Compute aggregate status from a payload. */
|
|
41
45
|
export declare function computeAggregate(payload: CachePayload): AggregateStatus;
|
|
42
46
|
/**
|
|
43
47
|
* Read the update-check cache.
|
|
44
48
|
*
|
|
45
|
-
*
|
|
46
|
-
* the
|
|
49
|
+
* Both the primary and the fallback path may hold valid contents — primary
|
|
50
|
+
* from a session where the home dir was writable, fallback from a session
|
|
51
|
+
* where writes had to be redirected (sandbox EPERM). When both exist and
|
|
52
|
+
* have unexpired contents, return whichever was written most recently; the
|
|
53
|
+
* older one is a stale snapshot from before the redirect happened.
|
|
47
54
|
*/
|
|
48
55
|
export declare function readCache(): CacheResult | null;
|
|
56
|
+
export interface WriteAttempt {
|
|
57
|
+
ok: boolean;
|
|
58
|
+
code?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Best-effort `mkdir -p` + `writeFile`. Returns `{ok: true}` on success, or
|
|
62
|
+
* `{ok: false, code}` on any failure (errno code if available, else stringified
|
|
63
|
+
* error). Callers decide whether to retry on a fallback path based on `code`
|
|
64
|
+
* — see `SANDBOX_WRITE_ERRORS` for the sandbox-fallback predicate.
|
|
65
|
+
*/
|
|
66
|
+
export declare function writeFileAt(dir: string, file: string, content: string): WriteAttempt;
|
|
49
67
|
/**
|
|
50
68
|
* Write cache. Tries the primary path first; on sandbox / permission failures
|
|
51
69
|
* falls back to $TMPDIR. Both failing emits at most one warning per process.
|
|
@@ -53,3 +71,29 @@ export declare function readCache(): CacheResult | null;
|
|
|
53
71
|
export declare function writeCache(result: CacheResult): void;
|
|
54
72
|
/** Delete cache files (used by --force and after upgrade). */
|
|
55
73
|
export declare function clearCache(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Write the just-upgraded marker. Sandbox-aware: falls back to $TMPDIR when
|
|
76
|
+
* ~/.mthds/state/ is not writable. The marker is best-effort — a write
|
|
77
|
+
* failure is warned (once per process) but never thrown.
|
|
78
|
+
*/
|
|
79
|
+
export declare function writeUpgradeMarker(data: Record<string, unknown>): void;
|
|
80
|
+
/**
|
|
81
|
+
* Best-effort invalidation. unlinkSync first (the desired outcome); if that
|
|
82
|
+
* fails — typically EPERM under the sandbox — overwrite with empty content so
|
|
83
|
+
* the next read parses as invalid (empty content fails JSON.parse and is also
|
|
84
|
+
* rejected by the single-line snooze parser). Returns true when the file is
|
|
85
|
+
* either gone or guaranteed unparseable.
|
|
86
|
+
*/
|
|
87
|
+
export declare function invalidateFileAt(path: string): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Read and consume the just-upgraded marker. Returns null when no marker is
|
|
90
|
+
* present, when the most recent marker is older than MARKER_TTL_MS (stale —
|
|
91
|
+
* likely stuck from a session where the sandbox blocked cleanup), or when
|
|
92
|
+
* the content cannot be parsed.
|
|
93
|
+
*
|
|
94
|
+
* Sandbox-aware: inspects both the primary and the fallback path, prefers the
|
|
95
|
+
* newer one, and best-effort cleans up both regardless of whether the marker
|
|
96
|
+
* was honored or rejected — so a stuck marker stops replaying as soon as we
|
|
97
|
+
* regain write access to its directory.
|
|
98
|
+
*/
|
|
99
|
+
export declare function readAndClearUpgradeMarker(): Record<string, unknown> | null;
|
|
@@ -1,34 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cache for update-check results.
|
|
2
|
+
* Cache for update-check results, plus the just-upgraded marker.
|
|
3
3
|
*
|
|
4
|
-
* Primary location: ~/.mthds/state
|
|
5
|
-
* Fallback location: $TMPDIR/mthds-agent/
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* user's home dir).
|
|
4
|
+
* Primary location: ~/.mthds/state/.
|
|
5
|
+
* Fallback location: $TMPDIR/mthds-agent/ — used when the primary location is
|
|
6
|
+
* not writable (e.g. Codex's workspaceWrite sandbox permits writes only under
|
|
7
|
+
* cwd / configured roots / $TMPDIR, not under the user's home dir).
|
|
9
8
|
*
|
|
10
|
-
* Two
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Two files live in each location:
|
|
10
|
+
*
|
|
11
|
+
* 1. `last-update-check` — TTL'd cache of update-check results.
|
|
12
|
+
* Two-line format: aggregate status, then JSON payload of per-binary results.
|
|
13
|
+
* Split TTL: 60 min for UP_TO_DATE, 720 min for UPGRADE_AVAILABLE.
|
|
14
|
+
*
|
|
15
|
+
* 2. `just-upgraded-from` — one-shot marker written by `mthds-agent upgrade`
|
|
16
|
+
* (and bootstrap) so the next update-check can announce what was upgraded.
|
|
17
|
+
* Consumed within the same skill flow, so a short TTL is enough; older
|
|
18
|
+
* markers are treated as stuck (sandbox blocked cleanup last time) and
|
|
19
|
+
* ignored to stop the announcement from replaying forever.
|
|
13
20
|
*
|
|
14
21
|
* TTL is based on file mtime (like gstack), not an embedded timestamp.
|
|
15
|
-
* Split TTL: 60 min for UP_TO_DATE, 720 min for UPGRADE_AVAILABLE.
|
|
16
22
|
*/
|
|
17
23
|
import { join } from "node:path";
|
|
18
24
|
import { homedir, tmpdir } from "node:os";
|
|
19
25
|
import { mkdirSync, readFileSync, writeFileSync, unlinkSync, statSync, } from "node:fs";
|
|
20
26
|
// ── Constants ──────────────────────────────────────────────────────
|
|
21
|
-
|
|
27
|
+
const STATE_DIR = join(homedir(), ".mthds", "state");
|
|
22
28
|
const PRIMARY_CACHE_PATH = join(STATE_DIR, "last-update-check");
|
|
29
|
+
const PRIMARY_MARKER_PATH = join(STATE_DIR, "just-upgraded-from");
|
|
23
30
|
const FALLBACK_DIR = join(tmpdir(), "mthds-agent");
|
|
24
31
|
const FALLBACK_CACHE_PATH = join(FALLBACK_DIR, "last-update-check");
|
|
32
|
+
const FALLBACK_MARKER_PATH = join(FALLBACK_DIR, "just-upgraded-from");
|
|
25
33
|
const TTL_UP_TO_DATE_MS = 60 * 60 * 1000; // 60 min
|
|
26
34
|
const TTL_UPGRADE_AVAILABLE_MS = 720 * 60 * 1000; // 720 min (12 hours)
|
|
35
|
+
// Real markers are consumed within seconds (skill flow re-runs preamble
|
|
36
|
+
// immediately after upgrade). Anything markedly older is almost certainly
|
|
37
|
+
// stuck because the sandbox blocked cleanup last time — ignore it instead of
|
|
38
|
+
// replaying the announcement on every update-check.
|
|
39
|
+
const MARKER_TTL_MS = 60 * 60 * 1000; // 60 min
|
|
27
40
|
const VALID_AGGREGATES = new Set([
|
|
28
41
|
"UP_TO_DATE",
|
|
29
42
|
"UPGRADE_AVAILABLE",
|
|
30
43
|
]);
|
|
31
|
-
const SANDBOX_WRITE_ERRORS = new Set([
|
|
44
|
+
export const SANDBOX_WRITE_ERRORS = new Set([
|
|
32
45
|
"EPERM",
|
|
33
46
|
"EACCES",
|
|
34
47
|
"EROFS",
|
|
@@ -64,13 +77,11 @@ function isValidPayload(p) {
|
|
|
64
77
|
}
|
|
65
78
|
return true;
|
|
66
79
|
}
|
|
67
|
-
// ── Per-process warning
|
|
80
|
+
// ── Per-process warning latches ────────────────────────────────────
|
|
68
81
|
let warnedAboutCacheWrite = false;
|
|
82
|
+
let warnedAboutMarkerWrite = false;
|
|
83
|
+
let warnedAboutMarkerClear = false;
|
|
69
84
|
// ── Functions ──────────────────────────────────────────────────────
|
|
70
|
-
/** Ensure the state directory exists. */
|
|
71
|
-
export function ensureStateDir() {
|
|
72
|
-
mkdirSync(STATE_DIR, { recursive: true });
|
|
73
|
-
}
|
|
74
85
|
/** Compute aggregate status from a payload. */
|
|
75
86
|
export function computeAggregate(payload) {
|
|
76
87
|
const entries = [payload.mthds_agent, payload.plxt];
|
|
@@ -117,18 +128,38 @@ function readCacheAt(path) {
|
|
|
117
128
|
// Negative age beyond 1 minute means clock skew — treat as expired
|
|
118
129
|
if (age < -60_000 || age > ttl)
|
|
119
130
|
return null;
|
|
120
|
-
return {
|
|
131
|
+
return {
|
|
132
|
+
result: { aggregate: aggregate, payload },
|
|
133
|
+
mtimeMs,
|
|
134
|
+
};
|
|
121
135
|
}
|
|
122
136
|
/**
|
|
123
137
|
* Read the update-check cache.
|
|
124
138
|
*
|
|
125
|
-
*
|
|
126
|
-
* the
|
|
139
|
+
* Both the primary and the fallback path may hold valid contents — primary
|
|
140
|
+
* from a session where the home dir was writable, fallback from a session
|
|
141
|
+
* where writes had to be redirected (sandbox EPERM). When both exist and
|
|
142
|
+
* have unexpired contents, return whichever was written most recently; the
|
|
143
|
+
* older one is a stale snapshot from before the redirect happened.
|
|
127
144
|
*/
|
|
128
145
|
export function readCache() {
|
|
129
|
-
|
|
146
|
+
const primary = readCacheAt(PRIMARY_CACHE_PATH);
|
|
147
|
+
const fallback = readCacheAt(FALLBACK_CACHE_PATH);
|
|
148
|
+
if (!primary)
|
|
149
|
+
return fallback?.result ?? null;
|
|
150
|
+
if (!fallback)
|
|
151
|
+
return primary.result;
|
|
152
|
+
return fallback.mtimeMs > primary.mtimeMs
|
|
153
|
+
? fallback.result
|
|
154
|
+
: primary.result;
|
|
130
155
|
}
|
|
131
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Best-effort `mkdir -p` + `writeFile`. Returns `{ok: true}` on success, or
|
|
158
|
+
* `{ok: false, code}` on any failure (errno code if available, else stringified
|
|
159
|
+
* error). Callers decide whether to retry on a fallback path based on `code`
|
|
160
|
+
* — see `SANDBOX_WRITE_ERRORS` for the sandbox-fallback predicate.
|
|
161
|
+
*/
|
|
162
|
+
export function writeFileAt(dir, file, content) {
|
|
132
163
|
try {
|
|
133
164
|
mkdirSync(dir, { recursive: true });
|
|
134
165
|
writeFileSync(file, content, "utf-8");
|
|
@@ -145,14 +176,14 @@ function writeCacheAt(dir, file, content) {
|
|
|
145
176
|
*/
|
|
146
177
|
export function writeCache(result) {
|
|
147
178
|
const content = result.aggregate + "\n" + JSON.stringify(result.payload) + "\n";
|
|
148
|
-
const primary =
|
|
179
|
+
const primary = writeFileAt(STATE_DIR, PRIMARY_CACHE_PATH, content);
|
|
149
180
|
if (primary.ok)
|
|
150
181
|
return;
|
|
151
182
|
// Only fall back for the sandbox/perm family of errors. Other failures
|
|
152
183
|
// (ENOSPC, IO errors, ...) are not improved by retrying in $TMPDIR, so we
|
|
153
184
|
// surface them via the same one-shot warning path.
|
|
154
185
|
if (primary.code && SANDBOX_WRITE_ERRORS.has(primary.code)) {
|
|
155
|
-
const fallback =
|
|
186
|
+
const fallback = writeFileAt(FALLBACK_DIR, FALLBACK_CACHE_PATH, content);
|
|
156
187
|
if (fallback.ok)
|
|
157
188
|
return;
|
|
158
189
|
emitWriteWarning(primary.code, fallback.code);
|
|
@@ -182,4 +213,127 @@ export function clearCache() {
|
|
|
182
213
|
}
|
|
183
214
|
}
|
|
184
215
|
}
|
|
216
|
+
// ── Upgrade marker ──────────────────────────────────────────────────
|
|
217
|
+
//
|
|
218
|
+
// The marker is a one-shot hand-off from `mthds-agent upgrade` / `bootstrap`
|
|
219
|
+
// to the next `update-check`, so the skill preamble can announce what just
|
|
220
|
+
// changed. It uses the same primary/fallback layout as the cache, for the
|
|
221
|
+
// same reason: ~/.mthds/state/ is not writable under Codex's workspaceWrite
|
|
222
|
+
// sandbox, and the bug we are fixing here is exactly the case where the
|
|
223
|
+
// marker was written successfully in a non-sandboxed context and then could
|
|
224
|
+
// not be cleaned up later from a sandboxed one, replaying the announcement
|
|
225
|
+
// every update-check.
|
|
226
|
+
/**
|
|
227
|
+
* Write the just-upgraded marker. Sandbox-aware: falls back to $TMPDIR when
|
|
228
|
+
* ~/.mthds/state/ is not writable. The marker is best-effort — a write
|
|
229
|
+
* failure is warned (once per process) but never thrown.
|
|
230
|
+
*/
|
|
231
|
+
export function writeUpgradeMarker(data) {
|
|
232
|
+
const content = JSON.stringify(data);
|
|
233
|
+
const primary = writeFileAt(STATE_DIR, PRIMARY_MARKER_PATH, content);
|
|
234
|
+
if (primary.ok)
|
|
235
|
+
return;
|
|
236
|
+
if (primary.code && SANDBOX_WRITE_ERRORS.has(primary.code)) {
|
|
237
|
+
const fallback = writeFileAt(FALLBACK_DIR, FALLBACK_MARKER_PATH, content);
|
|
238
|
+
if (fallback.ok)
|
|
239
|
+
return;
|
|
240
|
+
emitMarkerWriteWarning(primary.code, fallback.code);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
emitMarkerWriteWarning(primary.code);
|
|
244
|
+
}
|
|
245
|
+
function emitMarkerWriteWarning(primaryCode, fallbackCode) {
|
|
246
|
+
if (warnedAboutMarkerWrite)
|
|
247
|
+
return;
|
|
248
|
+
warnedAboutMarkerWrite = true;
|
|
249
|
+
const detail = fallbackCode
|
|
250
|
+
? `primary=${primaryCode ?? "?"}, fallback=${fallbackCode}`
|
|
251
|
+
: (primaryCode ?? "?");
|
|
252
|
+
process.stderr.write(`Warning: could not write upgrade marker (${detail}). The next update-check may not announce the upgrade.\n`);
|
|
253
|
+
}
|
|
254
|
+
function readMarkerAt(path) {
|
|
255
|
+
let mtimeMs;
|
|
256
|
+
let content;
|
|
257
|
+
try {
|
|
258
|
+
mtimeMs = statSync(path).mtimeMs;
|
|
259
|
+
content = readFileSync(path, "utf-8");
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
let parsed;
|
|
265
|
+
try {
|
|
266
|
+
parsed = JSON.parse(content);
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
return { data: parsed, mtimeMs };
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Best-effort invalidation. unlinkSync first (the desired outcome); if that
|
|
278
|
+
* fails — typically EPERM under the sandbox — overwrite with empty content so
|
|
279
|
+
* the next read parses as invalid (empty content fails JSON.parse and is also
|
|
280
|
+
* rejected by the single-line snooze parser). Returns true when the file is
|
|
281
|
+
* either gone or guaranteed unparseable.
|
|
282
|
+
*/
|
|
283
|
+
export function invalidateFileAt(path) {
|
|
284
|
+
try {
|
|
285
|
+
unlinkSync(path);
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
// fall through
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
writeFileSync(path, "", "utf-8");
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Read and consume the just-upgraded marker. Returns null when no marker is
|
|
301
|
+
* present, when the most recent marker is older than MARKER_TTL_MS (stale —
|
|
302
|
+
* likely stuck from a session where the sandbox blocked cleanup), or when
|
|
303
|
+
* the content cannot be parsed.
|
|
304
|
+
*
|
|
305
|
+
* Sandbox-aware: inspects both the primary and the fallback path, prefers the
|
|
306
|
+
* newer one, and best-effort cleans up both regardless of whether the marker
|
|
307
|
+
* was honored or rejected — so a stuck marker stops replaying as soon as we
|
|
308
|
+
* regain write access to its directory.
|
|
309
|
+
*/
|
|
310
|
+
export function readAndClearUpgradeMarker() {
|
|
311
|
+
const primary = readMarkerAt(PRIMARY_MARKER_PATH);
|
|
312
|
+
const fallback = readMarkerAt(FALLBACK_MARKER_PATH);
|
|
313
|
+
let chosen;
|
|
314
|
+
if (!primary)
|
|
315
|
+
chosen = fallback;
|
|
316
|
+
else if (!fallback)
|
|
317
|
+
chosen = primary;
|
|
318
|
+
else
|
|
319
|
+
chosen = fallback.mtimeMs > primary.mtimeMs ? fallback : primary;
|
|
320
|
+
if (!chosen)
|
|
321
|
+
return null;
|
|
322
|
+
// Negative age beyond 1 minute means clock skew — treat as stale so a
|
|
323
|
+
// future-dated marker can't replay the announcement forever.
|
|
324
|
+
const ageMs = Date.now() - chosen.mtimeMs;
|
|
325
|
+
const isStale = ageMs < -60_000 || ageMs > MARKER_TTL_MS;
|
|
326
|
+
// Clean up both paths whether or not we honor the marker. We only attempt
|
|
327
|
+
// invalidation for paths that actually had content; otherwise an existsSync
|
|
328
|
+
// miss-then-create race could leave a zero-byte file we just created.
|
|
329
|
+
const primaryCleared = primary ? invalidateFileAt(PRIMARY_MARKER_PATH) : true;
|
|
330
|
+
const fallbackCleared = fallback ? invalidateFileAt(FALLBACK_MARKER_PATH) : true;
|
|
331
|
+
if ((!primaryCleared || !fallbackCleared) && !warnedAboutMarkerClear) {
|
|
332
|
+
warnedAboutMarkerClear = true;
|
|
333
|
+
process.stderr.write(`Warning: could not clear upgrade marker (primary=${primaryCleared ? "ok" : "blocked"}, fallback=${fallbackCleared ? "ok" : "blocked"}). It will be ignored after ${MARKER_TTL_MS / 60_000}min.\n`);
|
|
334
|
+
}
|
|
335
|
+
if (isStale)
|
|
336
|
+
return null;
|
|
337
|
+
return chosen.data;
|
|
338
|
+
}
|
|
185
339
|
//# sourceMappingURL=update-cache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-cache.js","sourceRoot":"","sources":["../../src/agent/update-cache.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"update-cache.js","sourceRoot":"","sources":["../../src/agent/update-cache.ts"],"names":[],"mappings":"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"}
|
package/dist/agent-cli.js
CHANGED
|
@@ -23,7 +23,6 @@ import { agentDoctor, OutputFormat } from "./agent/commands/doctor.js";
|
|
|
23
23
|
import { agentUpdateCheck } from "./agent/commands/update-check.js";
|
|
24
24
|
import { agentUpgrade } from "./agent/commands/upgrade.js";
|
|
25
25
|
import { agentBootstrap } from "./agent/commands/bootstrap.js";
|
|
26
|
-
import { agentCodexInstallHook } from "./agent/commands/codex.js";
|
|
27
26
|
import { agentCodexHook } from "./agent/commands/codex-hook.js";
|
|
28
27
|
import { agentCodexApplyConfig } from "./agent/commands/codex-config.js";
|
|
29
28
|
import { agentConfigGet, agentConfigList, agentConfigSet } from "./agent/commands/config.js";
|
|
@@ -309,15 +308,8 @@ program
|
|
|
309
308
|
// ── mthds-agent codex ─────────────────────────────────────────────
|
|
310
309
|
const codex = program
|
|
311
310
|
.command("codex")
|
|
312
|
-
.description("Codex plugin helpers (hook runtime +
|
|
311
|
+
.description("Codex plugin helpers (hook runtime + setup)")
|
|
313
312
|
.exitOverride();
|
|
314
|
-
codex
|
|
315
|
-
.command("install-hook")
|
|
316
|
-
.description("Idempotently wire the mthds PostToolUse(apply_patch) hook into ~/.codex/hooks.json")
|
|
317
|
-
.exitOverride()
|
|
318
|
-
.action(async () => {
|
|
319
|
-
await agentCodexInstallHook();
|
|
320
|
-
});
|
|
321
313
|
codex
|
|
322
314
|
.command("hook")
|
|
323
315
|
.description("Codex PostToolUse(apply_patch) hook runtime — invoked by Codex, not directly")
|
|
@@ -327,7 +319,7 @@ codex
|
|
|
327
319
|
});
|
|
328
320
|
codex
|
|
329
321
|
.command("apply-config")
|
|
330
|
-
.description("
|
|
322
|
+
.description("Configure ~/.codex/ for the mthds plugin: enable sandbox network + plugin hooks, drop any obsolete hook entry")
|
|
331
323
|
.option("--check", "Exit non-zero if anything would change (no writes)")
|
|
332
324
|
.option("--dry-run", "Print proposed diff and exit without modifying the file")
|
|
333
325
|
.exitOverride()
|