shadok-ai 0.17.40 → 0.17.42

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.
@@ -88,6 +88,57 @@ export declare function commonsOsUser(input: {
88
88
  migrated: boolean;
89
89
  mode: DeploymentMode;
90
90
  }): string | null;
91
+ /**
92
+ * Repoint a cron `check` command from the OLD commons HOME's `.claude` tree to the
93
+ * NEW one, after migration moved the commons agent off `/root` to `/home/main`.
94
+ *
95
+ * Why this is needed at all: an agent that authored a monitoring script stored it
96
+ * (and hard-coded the guard path) under `$HOME/.claude/skills/.../scripts/` when
97
+ * its HOME was still `/root`. Since cron guards now run DROPPED as the commons
98
+ * `main` user (which cannot traverse `/root`, 0700), that absolute `/root/.claude`
99
+ * path is unreadable and the guard dies `check-failed` in silence. The migration
100
+ * relocates the `.claude` tree into the new HOME, so the reference must follow.
101
+ *
102
+ * The `<oldHome>/.claude` base is ALWAYS rewritten — the tree the migration moved —
103
+ * plus any extra RELATIVE prefix the caller passes (the `~/.shadok-ai/<dir>` script
104
+ * dirs a guard also names; see `shadokScriptDirs`). Every OTHER `/root/...` mention
105
+ * is left intact, so a reference to a dir that was NOT relocated keeps pointing at
106
+ * the original. Identity when the home did not move (mono-tenant, or old === new) or
107
+ * when either base is blank (never blank out a path). A `$HOME`-relative check is
108
+ * already portable and contains no absolute base to match, so it passes through
109
+ * untouched. Pure, so the boot self-heal that walks the cron file stays a thin
110
+ * caller — and the exact substitution is locked by test, the twin of
111
+ * `rewriteSkillsBase`.
112
+ */
113
+ export declare function rewriteCronCheckHome(check: string, oldHome: string, newHome: string, extraRelPrefixes?: readonly string[]): string;
114
+ /**
115
+ * Shadok's OWN directories under `~/.shadok-ai` — NEVER carried into the commons
116
+ * HOME by the stranded-script heal, even if a cron check names one. The credential
117
+ * stores (`ssh`, `users`, `secrets`) are the load-bearing entries: copying them
118
+ * into `/home/main` would hand every commons agent the SSH private key, the
119
+ * per-session signing keys and the account password hashes. The rest are internal
120
+ * per-instance state a guard has no business reading. A denylist (not an allowlist)
121
+ * on purpose: an operator/agent names its script dir whatever it likes (`scripts`,
122
+ * `checks`, `marketing`, …), and an allowlist would silently fail to heal a
123
+ * custom-named one — reintroducing the exact silent breakage this closes.
124
+ */
125
+ export declare const SHADOK_INTERNAL_DIRS: readonly string[];
126
+ /**
127
+ * The `~/.shadok-ai/<dir>` script directories a cron `check` references under the
128
+ * OLD commons HOME (`oldHome`, i.e. `/root`). These are operator/agent-authored
129
+ * monitoring scripts dropped straight under the data dir — a DIFFERENT location
130
+ * from `~/.claude/skills` (#419) that the HOME move also stranded: a dropped `main`
131
+ * guard cannot traverse `/root` (0700), so `/root/.shadok-ai/checks/x.sh` is
132
+ * unreadable exactly like a `/root/.claude` one, and the guard dies `check-failed`
133
+ * in silence.
134
+ *
135
+ * Returns the distinct RELATIVE prefixes (`".shadok-ai/checks"`, …), deduped and
136
+ * ready to feed `rewriteCronCheckHome`'s extra prefixes and `path.join`. Only the
137
+ * `<dir>/<something>` shape is matched (a segment that is a DIRECTORY, with a path
138
+ * component after it), so a top-level FILE (`/root/.shadok-ai/secrets.json`) is
139
+ * never caught; a dir on `SHADOK_INTERNAL_DIRS` is refused outright. Pure.
140
+ */
141
+ export declare function shadokScriptDirs(check: string, oldHome: string): string[];
91
142
  /**
92
143
  * The running agents to respawn, as session ids — deduped, order preserved so
93
144
  * the caller cycles them ONE AT A TIME (the OAuth refresh-token race,
@@ -89,6 +89,105 @@ export function migrationPlan(input) {
89
89
  export function commonsOsUser(input) {
90
90
  return input.migrated && input.mode === "multi-tenant" ? COMMONS_USER : null;
91
91
  }
92
+ /**
93
+ * Repoint a cron `check` command from the OLD commons HOME's `.claude` tree to the
94
+ * NEW one, after migration moved the commons agent off `/root` to `/home/main`.
95
+ *
96
+ * Why this is needed at all: an agent that authored a monitoring script stored it
97
+ * (and hard-coded the guard path) under `$HOME/.claude/skills/.../scripts/` when
98
+ * its HOME was still `/root`. Since cron guards now run DROPPED as the commons
99
+ * `main` user (which cannot traverse `/root`, 0700), that absolute `/root/.claude`
100
+ * path is unreadable and the guard dies `check-failed` in silence. The migration
101
+ * relocates the `.claude` tree into the new HOME, so the reference must follow.
102
+ *
103
+ * The `<oldHome>/.claude` base is ALWAYS rewritten — the tree the migration moved —
104
+ * plus any extra RELATIVE prefix the caller passes (the `~/.shadok-ai/<dir>` script
105
+ * dirs a guard also names; see `shadokScriptDirs`). Every OTHER `/root/...` mention
106
+ * is left intact, so a reference to a dir that was NOT relocated keeps pointing at
107
+ * the original. Identity when the home did not move (mono-tenant, or old === new) or
108
+ * when either base is blank (never blank out a path). A `$HOME`-relative check is
109
+ * already portable and contains no absolute base to match, so it passes through
110
+ * untouched. Pure, so the boot self-heal that walks the cron file stays a thin
111
+ * caller — and the exact substitution is locked by test, the twin of
112
+ * `rewriteSkillsBase`.
113
+ */
114
+ export function rewriteCronCheckHome(check, oldHome, newHome, extraRelPrefixes = []) {
115
+ if (!check || !oldHome || !newHome || oldHome === newHome)
116
+ return check;
117
+ let out = check;
118
+ for (const rel of [".claude", ...extraRelPrefixes]) {
119
+ out = out.split(oldHome + "/" + rel).join(newHome + "/" + rel);
120
+ }
121
+ return out;
122
+ }
123
+ /** Escape a string for literal use inside a `RegExp`. */
124
+ function escapeRegExp(s) {
125
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
126
+ }
127
+ /**
128
+ * Shadok's OWN directories under `~/.shadok-ai` — NEVER carried into the commons
129
+ * HOME by the stranded-script heal, even if a cron check names one. The credential
130
+ * stores (`ssh`, `users`, `secrets`) are the load-bearing entries: copying them
131
+ * into `/home/main` would hand every commons agent the SSH private key, the
132
+ * per-session signing keys and the account password hashes. The rest are internal
133
+ * per-instance state a guard has no business reading. A denylist (not an allowlist)
134
+ * on purpose: an operator/agent names its script dir whatever it likes (`scripts`,
135
+ * `checks`, `marketing`, …), and an allowlist would silently fail to heal a
136
+ * custom-named one — reintroducing the exact silent breakage this closes.
137
+ */
138
+ export const SHADOK_INTERNAL_DIRS = [
139
+ "app",
140
+ "browsers",
141
+ "channels",
142
+ "config",
143
+ "crons",
144
+ "files",
145
+ "keys",
146
+ "ledger",
147
+ "locks",
148
+ "media",
149
+ "peers",
150
+ "pilotctl",
151
+ "profiles",
152
+ "run",
153
+ "secrets",
154
+ "self",
155
+ "ssh",
156
+ "tail",
157
+ "tokens",
158
+ "users",
159
+ "whisper",
160
+ "worktrees",
161
+ "wt",
162
+ ];
163
+ /**
164
+ * The `~/.shadok-ai/<dir>` script directories a cron `check` references under the
165
+ * OLD commons HOME (`oldHome`, i.e. `/root`). These are operator/agent-authored
166
+ * monitoring scripts dropped straight under the data dir — a DIFFERENT location
167
+ * from `~/.claude/skills` (#419) that the HOME move also stranded: a dropped `main`
168
+ * guard cannot traverse `/root` (0700), so `/root/.shadok-ai/checks/x.sh` is
169
+ * unreadable exactly like a `/root/.claude` one, and the guard dies `check-failed`
170
+ * in silence.
171
+ *
172
+ * Returns the distinct RELATIVE prefixes (`".shadok-ai/checks"`, …), deduped and
173
+ * ready to feed `rewriteCronCheckHome`'s extra prefixes and `path.join`. Only the
174
+ * `<dir>/<something>` shape is matched (a segment that is a DIRECTORY, with a path
175
+ * component after it), so a top-level FILE (`/root/.shadok-ai/secrets.json`) is
176
+ * never caught; a dir on `SHADOK_INTERNAL_DIRS` is refused outright. Pure.
177
+ */
178
+ export function shadokScriptDirs(check, oldHome) {
179
+ if (!check || !oldHome)
180
+ return [];
181
+ const re = new RegExp(escapeRegExp(oldHome + "/.shadok-ai/") + "([^/\\s'\"]+)/", "g");
182
+ const out = new Set();
183
+ for (let m = re.exec(check); m; m = re.exec(check)) {
184
+ const seg = m[1];
185
+ if (SHADOK_INTERNAL_DIRS.includes(seg))
186
+ continue;
187
+ out.add(".shadok-ai/" + seg);
188
+ }
189
+ return [...out];
190
+ }
92
191
  /**
93
192
  * The running agents to respawn, as session ids — deduped, order preserved so
94
193
  * the caller cycles them ONE AT A TIME (the OAuth refresh-token race,
@@ -1 +1 @@
1
- {"version":3,"file":"migrate-groups.js","sourceRoot":"","sources":["../src/migrate-groups.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migrate-groups.js","sourceRoot":"","sources":["../src/migrate-groups.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -34,7 +34,7 @@ import { readGroundAt } from "./ground.js";
34
34
  import { homeGreetingBrief } from "./greeting.js";
35
35
  import { ensureSshIdentity } from "./ssh.js";
36
36
  import { accountsEnabled, deploymentMode, probeCanProvision } from "./capability.js";
37
- import { migrationPlan, runMigration, respawnPlan, commonsOsUser, COMMONS_USER, MIGRATION_MARKER_FILE, } from "./migrate-groups.js";
37
+ import { migrationPlan, runMigration, respawnPlan, commonsOsUser, COMMONS_USER, MIGRATION_MARKER_FILE, rewriteCronCheckHome, shadokScriptDirs, } from "./migrate-groups.js";
38
38
  import { relayOAuthCallback } from "./oauth-relay.js";
39
39
  import { openBrowser } from "./open-browser.js";
40
40
  import { parseSkillMeta, prepromptParts, prepromptFingerprint, stalenessReasons, LEGACY_FINGERPRINT, } from "./preprompt.js";
@@ -3011,6 +3011,100 @@ async function ensureGroupsProvisioned() {
3011
3011
  // of trusted directories in one write each, so none strands on the trust
3012
3012
  // dialog when the resume storm rebuilds a wiped (ephemeral) group HOME.
3013
3013
  preseedGroupHomes();
3014
+ // And heal the commons agent's own helper scripts + cron guards, which the HOME
3015
+ // move off /root left stranded (see below).
3016
+ await healCommonsStrandedScripts();
3017
+ }
3018
+ /**
3019
+ * Boot self-heal for the commons agent's OWN helper scripts and cron guards after
3020
+ * its HOME moved off `/root` to `/home/main`. A cron guard runs DROPPED as the
3021
+ * commons `main` user, which cannot traverse `/root` (0700) — so ANY absolute
3022
+ * `/root/...` path it names (script or sibling state file) is unreadable and the
3023
+ * guard dies `check-failed` in silence (measured on a live instance: monitoring
3024
+ * crons stuck, "son script est sous /root"). New agents are fine (their HOME is
3025
+ * already `/home/main`); this is the one-way carry for what predates the move.
3026
+ *
3027
+ * Two kinds of stranded location, both relocated here and then repointed:
3028
+ * 1. `~/.claude/skills` — the subtree `migChownTreeToCommons` skipped, where an
3029
+ * agent keeps the custom monitoring scripts it authored (#419).
3030
+ * 2. `~/.shadok-ai/<dir>` — operator/agent script dirs dropped straight under the
3031
+ * data dir (`checks`, `scripts`, `marketing`, …), discovered from the cron
3032
+ * checks that name them. `shadokScriptDirs` denylists shadok's own state and
3033
+ * credential stores, so a key/secret dir is NEVER copied into `/home/main`.
3034
+ *
3035
+ * Runs on EVERY capable boot, independent of the migration marker (the twin of
3036
+ * the reprovision reconciler above), so an ALREADY-migrated instance self-heals on
3037
+ * the next update rather than needing a hand fix. Idempotent and best-effort: a
3038
+ * failure here must never take down boot, and a re-run finds the copy already done
3039
+ * (`cp -rn`, non-clobber) and the checks already rewritten (identity). No-op unless
3040
+ * the HOME actually moved (mono-tenant / pre-migration: old === new).
3041
+ */
3042
+ async function healCommonsStrandedScripts() {
3043
+ if (DEPLOYMENT_MODE !== "multi-tenant")
3044
+ return;
3045
+ const oldHome = os.homedir();
3046
+ const newHome = homeForUser(COMMONS_USER, GROUP_HOME_BASE);
3047
+ if (!newHome || newHome === oldHome)
3048
+ return; // not migrated off /root → nothing moved
3049
+ const owner = `${COMMONS_USER}:${COMMONS_USER}`;
3050
+ // Carry one relative tree <oldHome>/<rel> → <newHome>/<rel>, non-clobber, owned
3051
+ // by `main`. The parent is `install -d`'d too so `~/.shadok-ai` exists in the new
3052
+ // HOME. No-op when the source is absent.
3053
+ const copyTree = async (rel) => {
3054
+ const src = path.join(oldHome, rel);
3055
+ if (!fs.existsSync(src))
3056
+ return;
3057
+ const dst = path.join(newHome, rel);
3058
+ await runPrivileged("install", ["-d", "-o", COMMONS_USER, "-g", COMMONS_USER, path.dirname(dst)]);
3059
+ await runPrivileged("install", ["-d", "-o", COMMONS_USER, "-g", COMMONS_USER, dst]);
3060
+ await runPrivileged("cp", ["-rn", `${src}/.`, `${dst}/`], { timeoutMs: TREE_OP_TIMEOUT_MS });
3061
+ await runPrivileged("chown", ["-R", owner, dst], { timeoutMs: TREE_OP_TIMEOUT_MS });
3062
+ };
3063
+ // Load once; the same list feeds the dir discovery AND the rewrite below.
3064
+ let crons = [];
3065
+ try {
3066
+ crons = loadCrons();
3067
+ }
3068
+ catch (e) {
3069
+ console.error(`heal: reading crons failed (best-effort): ${e?.message ?? e}`);
3070
+ }
3071
+ // The ~/.shadok-ai/<dir> script dirs the guards name, deduped (never a
3072
+ // credential/state dir — shadokScriptDirs denylists those).
3073
+ const scriptDirs = [
3074
+ ...new Set(crons.flatMap((c) => (c.check ? shadokScriptDirs(c.check, oldHome) : []))),
3075
+ ];
3076
+ // 1) Relocate the skills subtree the migration skipped, plus every discovered
3077
+ // ~/.shadok-ai script dir. Each copy is independent and best-effort.
3078
+ for (const rel of [path.join(".claude", "skills"), ...scriptDirs]) {
3079
+ try {
3080
+ await copyTree(rel);
3081
+ }
3082
+ catch (e) {
3083
+ console.error(`heal: relocating commons ~/${rel} failed (best-effort): ${e?.message ?? e}`);
3084
+ }
3085
+ }
3086
+ // 2) Repoint this instance's cron guards: the .claude base AND the relocated
3087
+ // ~/.shadok-ai script dirs. A /root path that was NOT relocated stays intact.
3088
+ try {
3089
+ let changed = false;
3090
+ for (const c of crons) {
3091
+ if (!c.check)
3092
+ continue;
3093
+ const next = rewriteCronCheckHome(c.check, oldHome, newHome, scriptDirs);
3094
+ if (next !== c.check) {
3095
+ c.check = next;
3096
+ changed = true;
3097
+ }
3098
+ }
3099
+ if (changed) {
3100
+ saveCrons(crons);
3101
+ console.log(`heal: repointed cron guard path(s) from ${oldHome} → ${newHome} ` +
3102
+ `(.claude${scriptDirs.length ? ", " + scriptDirs.join(", ") : ""})`);
3103
+ }
3104
+ }
3105
+ catch (e) {
3106
+ console.error(`heal: rewriting cron guard paths failed (best-effort): ${e?.message ?? e}`);
3107
+ }
3014
3108
  }
3015
3109
  /** Step 1 — create the non-root commons user `main` (+ HOME). Idempotent. */
3016
3110
  async function migCreateCommonsUser() {