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.
- package/dist/migrate-groups.d.ts +51 -0
- package/dist/migrate-groups.js +99 -0
- package/dist/migrate-groups.js.map +1 -1
- package/dist/server.js +95 -1
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/migrate-groups.d.ts
CHANGED
|
@@ -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,
|
package/dist/migrate-groups.js
CHANGED
|
@@ -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() {
|