shadok-ai 0.17.41 → 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.
@@ -99,15 +99,46 @@ export declare function commonsOsUser(input: {
99
99
  * path is unreadable and the guard dies `check-failed` in silence. The migration
100
100
  * relocates the `.claude` tree into the new HOME, so the reference must follow.
101
101
  *
102
- * Only the `<oldHome>/.claude` base is rewritten — the one tree that moved — not
103
- * every `<oldHome>` mention, so an unrelated `/root/...` reference is left intact.
104
- * Identity when the home did not move (mono-tenant, or old === new) or when either
105
- * base is blank (never blank out a path). A `$HOME`-relative check is already
106
- * portable and contains no absolute base to match, so it passes through untouched.
107
- * Pure, so the boot self-heal that walks the cron file stays a thin caller — and
108
- * the exact substitution is locked by test, the twin of `rewriteSkillsBase`.
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`.
109
112
  */
110
- export declare function rewriteCronCheckHome(check: string, oldHome: string, newHome: string): string;
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[];
111
142
  /**
112
143
  * The running agents to respawn, as session ids — deduped, order preserved so
113
144
  * the caller cycles them ONE AT A TIME (the OAuth refresh-token race,
@@ -100,18 +100,93 @@ export function commonsOsUser(input) {
100
100
  * path is unreadable and the guard dies `check-failed` in silence. The migration
101
101
  * relocates the `.claude` tree into the new HOME, so the reference must follow.
102
102
  *
103
- * Only the `<oldHome>/.claude` base is rewritten — the one tree that moved — not
104
- * every `<oldHome>` mention, so an unrelated `/root/...` reference is left intact.
105
- * Identity when the home did not move (mono-tenant, or old === new) or when either
106
- * base is blank (never blank out a path). A `$HOME`-relative check is already
107
- * portable and contains no absolute base to match, so it passes through untouched.
108
- * Pure, so the boot self-heal that walks the cron file stays a thin caller — and
109
- * the exact substitution is locked by test, the twin of `rewriteSkillsBase`.
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`.
110
113
  */
111
- export function rewriteCronCheckHome(check, oldHome, newHome) {
114
+ export function rewriteCronCheckHome(check, oldHome, newHome, extraRelPrefixes = []) {
112
115
  if (!check || !oldHome || !newHome || oldHome === newHome)
113
116
  return check;
114
- return check.split(oldHome + "/.claude").join(newHome + "/.claude");
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];
115
190
  }
116
191
  /**
117
192
  * The running agents to respawn, as session ids — deduped, order preserved so
@@ -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, rewriteCronCheckHome, } 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";
@@ -3013,20 +3013,24 @@ async function ensureGroupsProvisioned() {
3013
3013
  preseedGroupHomes();
3014
3014
  // And heal the commons agent's own helper scripts + cron guards, which the HOME
3015
3015
  // move off /root left stranded (see below).
3016
- await healCommonsClaudeScripts();
3016
+ await healCommonsStrandedScripts();
3017
3017
  }
3018
3018
  /**
3019
- * Boot self-heal for the commons agent's OWN `.claude` content and cron guards
3020
- * after its HOME moved off `/root` to `/home/main`.
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.
3021
3026
  *
3022
- * The one-shot migration (`migChownTreeToCommons`) relocates the transcript tree
3023
- * but NOT `~/.claude/skills`, where an agent keeps the custom monitoring scripts
3024
- * it authored. Those scripts (and any cron `check` that hard-codes their old
3025
- * `/root/.claude/...` path) are then unreachable: a cron guard runs DROPPED as the
3026
- * commons `main` user, which cannot traverse `/root` (0700) — so the guard dies
3027
- * `check-failed` in silence (measured on a live instance: three monitoring crons
3028
- * stuck, "son script est sous /root"). New agents are fine (their HOME is already
3029
- * `/home/main`); this is the one-way carry for what predates the move.
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`.
3030
3034
  *
3031
3035
  * Runs on EVERY capable boot, independent of the migration marker (the twin of
3032
3036
  * the reprovision reconciler above), so an ALREADY-migrated instance self-heals on
@@ -3035,38 +3039,58 @@ async function ensureGroupsProvisioned() {
3035
3039
  * (`cp -rn`, non-clobber) and the checks already rewritten (identity). No-op unless
3036
3040
  * the HOME actually moved (mono-tenant / pre-migration: old === new).
3037
3041
  */
3038
- async function healCommonsClaudeScripts() {
3042
+ async function healCommonsStrandedScripts() {
3039
3043
  if (DEPLOYMENT_MODE !== "multi-tenant")
3040
3044
  return;
3041
3045
  const oldHome = os.homedir();
3042
3046
  const newHome = homeForUser(COMMONS_USER, GROUP_HOME_BASE);
3043
3047
  if (!newHome || newHome === oldHome)
3044
3048
  return; // not migrated off /root → nothing moved
3045
- // 1) Carry the agent-authored scripts across: <oldHome>/.claude/skills →
3046
- // <newHome>/.claude/skills, non-clobber, owned by `main`. This is the one
3047
- // `.claude` subtree the migration skipped (skills are seeded machine-wide in
3048
- // MT, but an agent's CUSTOM files live only in this per-HOME copy).
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 = [];
3049
3065
  try {
3050
- const srcSkills = path.join(oldHome, ".claude", "skills");
3051
- if (fs.existsSync(srcSkills)) {
3052
- const owner = `${COMMONS_USER}:${COMMONS_USER}`;
3053
- const dstSkills = path.join(newHome, ".claude", "skills");
3054
- await runPrivileged("install", ["-d", "-o", COMMONS_USER, "-g", COMMONS_USER, dstSkills]);
3055
- await runPrivileged("cp", ["-rn", `${srcSkills}/.`, `${dstSkills}/`], { timeoutMs: TREE_OP_TIMEOUT_MS });
3056
- await runPrivileged("chown", ["-R", owner, dstSkills], { timeoutMs: TREE_OP_TIMEOUT_MS });
3057
- }
3066
+ crons = loadCrons();
3058
3067
  }
3059
3068
  catch (e) {
3060
- console.error(`heal: relocating commons ~/.claude/skills failed (best-effort): ${e?.message ?? 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
+ }
3061
3085
  }
3062
- // 2) Repoint this instance's cron guards that still name the old /root HOME.
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.
3063
3088
  try {
3064
- const crons = loadCrons();
3065
3089
  let changed = false;
3066
3090
  for (const c of crons) {
3067
3091
  if (!c.check)
3068
3092
  continue;
3069
- const next = rewriteCronCheckHome(c.check, oldHome, newHome);
3093
+ const next = rewriteCronCheckHome(c.check, oldHome, newHome, scriptDirs);
3070
3094
  if (next !== c.check) {
3071
3095
  c.check = next;
3072
3096
  changed = true;
@@ -3074,7 +3098,8 @@ async function healCommonsClaudeScripts() {
3074
3098
  }
3075
3099
  if (changed) {
3076
3100
  saveCrons(crons);
3077
- console.log(`heal: repointed cron guard path(s) from ${oldHome}/.claude → ${newHome}/.claude`);
3101
+ console.log(`heal: repointed cron guard path(s) from ${oldHome} → ${newHome} ` +
3102
+ `(.claude${scriptDirs.length ? ", " + scriptDirs.join(", ") : ""})`);
3078
3103
  }
3079
3104
  }
3080
3105
  catch (e) {