squad-openclaw 2026.2.2208 → 2026.2.2209
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/README.md +15 -0
- package/dist/index.js +135 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -118,6 +118,21 @@ For agent editing UX, this plugin also exposes **whitelisted gateway RPC mutator
|
|
|
118
118
|
|
|
119
119
|
These methods do **not** permit arbitrary file writes and do not expose credentials. They are intentionally narrow so the UI can update agent metadata safely without direct `openclaw.json` filesystem writes.
|
|
120
120
|
|
|
121
|
+
### Startup Config Migration (one-time, localized)
|
|
122
|
+
|
|
123
|
+
On plugin startup, Squad runs an internal migration harness. Current migration behavior:
|
|
124
|
+
|
|
125
|
+
- Checks `~/.openclaw/squad-ceo-data/migrations.json` for completed migration IDs.
|
|
126
|
+
- If `001-enable-main-subagent-access` is not recorded, applies a **localized** `config.patch` that sets only:
|
|
127
|
+
- `agents.defaults.maxConcurrent = 4`
|
|
128
|
+
- `agents.defaults.subagents.maxConcurrent = 8`
|
|
129
|
+
- `agents.list[id=main].identity.name = "Pepper"`
|
|
130
|
+
- `agents.list[id=main].tools.allow = ["*"]`
|
|
131
|
+
- `agents.list[id=main].subagents.allowAgents = ["*"]`
|
|
132
|
+
- Records completion in `~/.openclaw/squad-ceo-data/migrations.json`.
|
|
133
|
+
|
|
134
|
+
This migration is designed to run once. If an operator later changes these values manually, the plugin does not overwrite them again because the migration is already marked complete.
|
|
135
|
+
|
|
121
136
|
## Relay Security
|
|
122
137
|
|
|
123
138
|
The cloud relay enables remote browser access to the gateway through `relay.squad.ceo`. This section explains the full architecture for security reviewers.
|
package/dist/index.js
CHANGED
|
@@ -2979,11 +2979,146 @@ function registerSquadSharedApi(api, onFsChange) {
|
|
|
2979
2979
|
};
|
|
2980
2980
|
}
|
|
2981
2981
|
|
|
2982
|
+
// src/migrations/runner.ts
|
|
2983
|
+
import fs11 from "fs";
|
|
2984
|
+
import path12 from "path";
|
|
2985
|
+
|
|
2986
|
+
// src/migrations/001-enable-main-subagent-access.ts
|
|
2987
|
+
var migration = {
|
|
2988
|
+
id: "001-enable-main-subagent-access",
|
|
2989
|
+
description: "Enable full main-agent tool and subagent spawning defaults",
|
|
2990
|
+
run: async ({ gatewayCall }) => {
|
|
2991
|
+
const doPatch = async (baseHash) => {
|
|
2992
|
+
await gatewayCall("config.patch", {
|
|
2993
|
+
...baseHash ? { baseHash } : {},
|
|
2994
|
+
raw: JSON.stringify({
|
|
2995
|
+
agents: {
|
|
2996
|
+
defaults: {
|
|
2997
|
+
maxConcurrent: 4,
|
|
2998
|
+
subagents: {
|
|
2999
|
+
maxConcurrent: 8
|
|
3000
|
+
}
|
|
3001
|
+
},
|
|
3002
|
+
list: [
|
|
3003
|
+
{
|
|
3004
|
+
id: "main",
|
|
3005
|
+
identity: {
|
|
3006
|
+
name: "Pepper"
|
|
3007
|
+
},
|
|
3008
|
+
tools: {
|
|
3009
|
+
allow: ["*"]
|
|
3010
|
+
},
|
|
3011
|
+
subagents: {
|
|
3012
|
+
allowAgents: ["*"]
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
]
|
|
3016
|
+
}
|
|
3017
|
+
})
|
|
3018
|
+
});
|
|
3019
|
+
};
|
|
3020
|
+
let snapshot = await gatewayCall("config.get", {});
|
|
3021
|
+
try {
|
|
3022
|
+
await doPatch(snapshot?.hash);
|
|
3023
|
+
} catch (firstErr) {
|
|
3024
|
+
const msg = firstErr instanceof Error ? firstErr.message : String(firstErr);
|
|
3025
|
+
if (!/config changed since last load/i.test(msg)) throw firstErr;
|
|
3026
|
+
snapshot = await gatewayCall("config.get", {});
|
|
3027
|
+
await doPatch(snapshot?.hash);
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
};
|
|
3031
|
+
var enable_main_subagent_access_default = migration;
|
|
3032
|
+
|
|
3033
|
+
// src/migrations/index.ts
|
|
3034
|
+
var STARTUP_MIGRATIONS = [
|
|
3035
|
+
enable_main_subagent_access_default
|
|
3036
|
+
// Append new startup migrations here.
|
|
3037
|
+
];
|
|
3038
|
+
|
|
3039
|
+
// src/migrations/runner.ts
|
|
3040
|
+
var MIGRATIONS_DIR = path12.join(getOpenclawStateDir(), "squad-ceo-data");
|
|
3041
|
+
var MIGRATIONS_PATH = path12.join(MIGRATIONS_DIR, "migrations.json");
|
|
3042
|
+
function defaultState() {
|
|
3043
|
+
return {
|
|
3044
|
+
version: 1,
|
|
3045
|
+
completed: []
|
|
3046
|
+
};
|
|
3047
|
+
}
|
|
3048
|
+
function readState() {
|
|
3049
|
+
try {
|
|
3050
|
+
const raw = fs11.readFileSync(MIGRATIONS_PATH, "utf-8");
|
|
3051
|
+
const parsed = JSON.parse(raw);
|
|
3052
|
+
if (!Array.isArray(parsed.completed)) return defaultState();
|
|
3053
|
+
return {
|
|
3054
|
+
version: 1,
|
|
3055
|
+
completed: parsed.completed.filter((row) => row && typeof row.id === "string" && typeof row.completedAt === "string").map((row) => ({ id: row.id, completedAt: row.completedAt }))
|
|
3056
|
+
};
|
|
3057
|
+
} catch {
|
|
3058
|
+
return defaultState();
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
function writeState(state) {
|
|
3062
|
+
fs11.mkdirSync(MIGRATIONS_DIR, { recursive: true });
|
|
3063
|
+
fs11.writeFileSync(MIGRATIONS_PATH, JSON.stringify(state, null, 2), "utf-8");
|
|
3064
|
+
}
|
|
3065
|
+
function makeGatewayCaller(api) {
|
|
3066
|
+
return async (method, params = {}) => {
|
|
3067
|
+
const apiRequest = api?.request;
|
|
3068
|
+
if (typeof apiRequest === "function") {
|
|
3069
|
+
return apiRequest(method, params);
|
|
3070
|
+
}
|
|
3071
|
+
const apiCallGatewayMethod = api?.callGatewayMethod;
|
|
3072
|
+
if (typeof apiCallGatewayMethod === "function") {
|
|
3073
|
+
return apiCallGatewayMethod(method, params);
|
|
3074
|
+
}
|
|
3075
|
+
throw new Error("Gateway method invocation API unavailable in plugin context");
|
|
3076
|
+
};
|
|
3077
|
+
}
|
|
3078
|
+
async function runMigration(state, migration2, gatewayCall) {
|
|
3079
|
+
if (state.completed.some((row) => row.id === migration2.id)) {
|
|
3080
|
+
return { state, applied: false };
|
|
3081
|
+
}
|
|
3082
|
+
await migration2.run({ gatewayCall });
|
|
3083
|
+
return {
|
|
3084
|
+
applied: true,
|
|
3085
|
+
state: {
|
|
3086
|
+
...state,
|
|
3087
|
+
completed: [
|
|
3088
|
+
...state.completed,
|
|
3089
|
+
{
|
|
3090
|
+
id: migration2.id,
|
|
3091
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3092
|
+
}
|
|
3093
|
+
]
|
|
3094
|
+
}
|
|
3095
|
+
};
|
|
3096
|
+
}
|
|
3097
|
+
async function runStartupMigrations(api) {
|
|
3098
|
+
const gatewayCall = makeGatewayCaller(api);
|
|
3099
|
+
let state = readState();
|
|
3100
|
+
for (const migration2 of STARTUP_MIGRATIONS) {
|
|
3101
|
+
try {
|
|
3102
|
+
const result = await runMigration(state, migration2, gatewayCall);
|
|
3103
|
+
state = result.state;
|
|
3104
|
+
if (result.applied) {
|
|
3105
|
+
writeState(state);
|
|
3106
|
+
console.log(`[startup-migrations] applied: ${migration2.id}`);
|
|
3107
|
+
}
|
|
3108
|
+
} catch (err2) {
|
|
3109
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
3110
|
+
console.warn(`[startup-migrations] failed: ${migration2.id}: ${msg}`);
|
|
3111
|
+
break;
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
|
|
2982
3116
|
// src/index.ts
|
|
2983
3117
|
function squadAppPlugin(api) {
|
|
2984
3118
|
const onFsChange = (evt) => broadcastToUsers("fs.change", evt);
|
|
2985
3119
|
const sharedApi = registerSquadSharedApi(api, onFsChange);
|
|
2986
3120
|
sharedApi.registerCoreGatewayMethods();
|
|
3121
|
+
void runStartupMigrations(api);
|
|
2987
3122
|
const relayState = readRelayState();
|
|
2988
3123
|
const relayEnabled = !!(relayState.claimToken || relayState.roomId);
|
|
2989
3124
|
if (relayEnabled) {
|
package/package.json
CHANGED