@rubytech/create-maxy-code 0.1.165 → 0.1.166
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/index.js +17 -9
- package/package.json +1 -1
- package/payload/platform/neo4j/schema.cypher +3 -5
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts +0 -29
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.js +7 -115
- package/payload/platform/plugins/email/mcp/dist/lib/credentials.js.map +1 -1
- package/payload/platform/plugins/email/skills/email-composition/SKILL.md +1 -1
- package/payload/platform/scripts/lib/read-brand-json.sh +1 -1
- package/payload/platform/scripts/lib/resolve-account-dir.sh +1 -1
- package/payload/platform/scripts/seed-neo4j.sh +29 -421
- package/payload/platform/scripts/setup-account.sh +370 -0
- package/payload/platform/services/claude-session-manager/dist/config.js +2 -2
- package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
package/dist/index.js
CHANGED
|
@@ -2333,11 +2333,19 @@ function setupVncViewer() {
|
|
|
2333
2333
|
}
|
|
2334
2334
|
function setupAccount() {
|
|
2335
2335
|
log("10", TOTAL, "Setting up...");
|
|
2336
|
-
//
|
|
2337
|
-
//
|
|
2338
|
-
//
|
|
2339
|
-
//
|
|
2340
|
-
//
|
|
2336
|
+
// Account-side setup runs first: creates the account dir, writes the
|
|
2337
|
+
// Claude Code project settings (hooks only — no permissions.allow),
|
|
2338
|
+
// installs specialist templates, seeds account.json. Then seed-neo4j.sh
|
|
2339
|
+
// applies the schema and MERGEs the root :LocalBusiness / owner
|
|
2340
|
+
// :AdminUser nodes. setup-account.sh has no Neo4j env dependency;
|
|
2341
|
+
// seed-neo4j.sh hard-exits without NEO4J_URI, so we derive the URI +
|
|
2342
|
+
// password (a missing password file is a hard error here — the
|
|
2343
|
+
// upstream ensureNeo4jPassword() would have thrown if it couldn't
|
|
2344
|
+
// reach the brand's Neo4j).
|
|
2345
|
+
const setupScript = join(INSTALL_DIR, "platform/scripts/setup-account.sh");
|
|
2346
|
+
if (existsSync(setupScript)) {
|
|
2347
|
+
shell("bash", [setupScript], { cwd: INSTALL_DIR });
|
|
2348
|
+
}
|
|
2341
2349
|
const passwordFile = join(INSTALL_DIR, "platform/config/.neo4j-password");
|
|
2342
2350
|
if (!existsSync(passwordFile)) {
|
|
2343
2351
|
throw new Error(`Neo4j password file missing at ${passwordFile} — required by setup step.`);
|
|
@@ -2489,7 +2497,7 @@ function registerSpecialistAgents() {
|
|
|
2489
2497
|
// `installService` stamps `Environment=ACCOUNT_ID=` into the brand
|
|
2490
2498
|
// systemd unit so the writeNodeWithEdges gate has a non-undefined identity to
|
|
2491
2499
|
// compare against. Pulled from `INSTALL_DIR/data/accounts/<uuid>/account.json`
|
|
2492
|
-
// written by
|
|
2500
|
+
// written by setup-account.sh during setupAccount(). One reader, one shape, one
|
|
2493
2501
|
// source of truth.
|
|
2494
2502
|
//
|
|
2495
2503
|
// retired the installer's cron registration — `resolveInstallAccountId`
|
|
@@ -2573,7 +2581,7 @@ function installServiceDarwin() {
|
|
|
2573
2581
|
const installAccountId = resolveInstallAccountId();
|
|
2574
2582
|
if (!installAccountId) {
|
|
2575
2583
|
throw new Error(`installServiceDarwin: no account discovered at ${INSTALL_DIR}/data/accounts/<uuid>/account.json — ` +
|
|
2576
|
-
`setupAccount() (
|
|
2584
|
+
`setupAccount() (setup-account.sh) should have created one. Refusing to write .env ` +
|
|
2577
2585
|
`without ACCOUNT_ID; the boot validator would FATAL on every kickstart.`);
|
|
2578
2586
|
}
|
|
2579
2587
|
const envPath = join(persistDir, ".env");
|
|
@@ -3002,13 +3010,13 @@ function installService() {
|
|
|
3002
3010
|
// ACCOUNT_ID stamped into the brand unit so the writeNodeWithEdges
|
|
3003
3011
|
// gate at platform/lib/graph-write/src/index.ts:170 has a real identity to
|
|
3004
3012
|
// compare against (instead of process.env.ACCOUNT_ID === undefined). Resolved
|
|
3005
|
-
// here AFTER setupAccount() ran upstream —
|
|
3013
|
+
// here AFTER setupAccount() ran upstream — setup-account.sh wrote account.json,
|
|
3006
3014
|
// so an empty resolution at this point is a corrupted install (e.g. the seed
|
|
3007
3015
|
// failed silently, or accounts/ was wiped between setup and unit-write).
|
|
3008
3016
|
const installAccountId = resolveInstallAccountId();
|
|
3009
3017
|
if (!installAccountId) {
|
|
3010
3018
|
throw new Error(`installService: no account discovered at ${INSTALL_DIR}/data/accounts/<uuid>/account.json — ` +
|
|
3011
|
-
`setupAccount() (
|
|
3019
|
+
`setupAccount() (setup-account.sh) should have created one. Refusing to write a systemd unit ` +
|
|
3012
3020
|
`without ACCOUNT_ID; the boot validator would FATAL on every restart.`);
|
|
3013
3021
|
}
|
|
3014
3022
|
const serviceFile = buildMaxyUnitFile({
|
package/package.json
CHANGED
|
@@ -827,11 +827,9 @@ OPTIONS {
|
|
|
827
827
|
// accountId, email, agentAddress, imapHost, imapPort,
|
|
828
828
|
// imapSecurity, smtpHost, smtpPort, smtpSecurity, updatedAt
|
|
829
829
|
//
|
|
830
|
-
//
|
|
831
|
-
//
|
|
832
|
-
//
|
|
833
|
-
// lastRespondedUid (integer — IMAP UID high-water mark),
|
|
834
|
-
// lastPollAt (ISO 8601), consecutiveFailures (integer)
|
|
830
|
+
// Poll state (written by email-ingest after each successful fetch):
|
|
831
|
+
// agentSlug, pollIntervalMinutes, lastFetchedUid, lastPollAt,
|
|
832
|
+
// uidValidity
|
|
835
833
|
// ----------------------------------------------------------
|
|
836
834
|
|
|
837
835
|
// ----------------------------------------------------------
|
|
@@ -15,16 +15,6 @@ export interface PollState {
|
|
|
15
15
|
lastPollAt: string | null;
|
|
16
16
|
uidValidity: number | null;
|
|
17
17
|
}
|
|
18
|
-
export interface AutoRespondConfig {
|
|
19
|
-
autoRespond: boolean;
|
|
20
|
-
respondingAgentSlug: string | null;
|
|
21
|
-
pollIntervalMinutes: number;
|
|
22
|
-
lastRespondedUid: number;
|
|
23
|
-
lastPollAt: string | null;
|
|
24
|
-
consecutiveFailures: number;
|
|
25
|
-
autoRespondHourlyLimit: number;
|
|
26
|
-
autoRespondDailyLimit: number;
|
|
27
|
-
}
|
|
28
18
|
export interface FullCredentials {
|
|
29
19
|
config: EmailConfig;
|
|
30
20
|
password: string;
|
|
@@ -87,25 +77,6 @@ export declare function writeBindingConfig(accountId: string, agentSlug: string,
|
|
|
87
77
|
* Returns the conflicting agentSlug if claimed, or null if available.
|
|
88
78
|
*/
|
|
89
79
|
export declare function checkAddressBinding(agentAddress: string, currentSlug: string): Promise<string | null>;
|
|
90
|
-
/**
|
|
91
|
-
* Read auto-respond config from the EmailAccount node.
|
|
92
|
-
* Returns defaults if fields are not yet set.
|
|
93
|
-
*/
|
|
94
|
-
export declare function readAutoRespondConfig(accountId: string): Promise<AutoRespondConfig | null>;
|
|
95
|
-
/**
|
|
96
|
-
* Write auto-respond config fields on the EmailAccount node.
|
|
97
|
-
* Only updates the specified fields — does not touch email/IMAP/SMTP config.
|
|
98
|
-
*/
|
|
99
|
-
export declare function writeAutoRespondConfig(accountId: string, config: Partial<AutoRespondConfig>): Promise<void>;
|
|
100
|
-
/**
|
|
101
|
-
* Read all EmailAccounts that have auto-respond enabled.
|
|
102
|
-
* Returns config + auto-respond settings for each.
|
|
103
|
-
*/
|
|
104
|
-
export declare function readAutoRespondAccounts(): Promise<Array<{
|
|
105
|
-
accountId: string;
|
|
106
|
-
config: EmailConfig;
|
|
107
|
-
autoRespond: AutoRespondConfig;
|
|
108
|
-
}>>;
|
|
109
80
|
/**
|
|
110
81
|
* Load full credentials (config + password).
|
|
111
82
|
* Returns null with a reason if either piece is missing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,KAAK,GAAG,UAAU,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,KAAK,GAAG,UAAU,CAAC;CAClC;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,KAAK,GAAG,UAAU,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,KAAK,GAAG,UAAU,CAAC;CAClC;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAarC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAIpD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAwB/E;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA2CvF;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUnE;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA2BhF;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,WAAW,EAAE,eAAe,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAc/D"}
|
|
@@ -89,7 +89,13 @@ export async function writeConfig(accountId, config) {
|
|
|
89
89
|
e.smtpHost = $smtpHost,
|
|
90
90
|
e.smtpPort = $smtpPort,
|
|
91
91
|
e.smtpSecurity = $smtpSecurity,
|
|
92
|
-
e.updatedAt = $updatedAt
|
|
92
|
+
e.updatedAt = $updatedAt
|
|
93
|
+
REMOVE e.autoRespond,
|
|
94
|
+
e.autoRespondHourlyLimit,
|
|
95
|
+
e.autoRespondDailyLimit,
|
|
96
|
+
e.respondingAgentSlug,
|
|
97
|
+
e.lastRespondedUid,
|
|
98
|
+
e.consecutiveFailures`, {
|
|
93
99
|
accountId,
|
|
94
100
|
email: config.email,
|
|
95
101
|
agentAddress: config.agentAddress,
|
|
@@ -217,120 +223,6 @@ export async function checkAddressBinding(agentAddress, currentSlug) {
|
|
|
217
223
|
await session.close();
|
|
218
224
|
}
|
|
219
225
|
}
|
|
220
|
-
/**
|
|
221
|
-
* Read auto-respond config from the EmailAccount node.
|
|
222
|
-
* Returns defaults if fields are not yet set.
|
|
223
|
-
*/
|
|
224
|
-
export async function readAutoRespondConfig(accountId) {
|
|
225
|
-
const session = getSession();
|
|
226
|
-
try {
|
|
227
|
-
const result = await session.run(`MATCH (e:EmailAccount {accountId: $accountId}) RETURN e LIMIT 1`, { accountId });
|
|
228
|
-
if (result.records.length === 0)
|
|
229
|
-
return null;
|
|
230
|
-
const props = result.records[0].get("e").properties;
|
|
231
|
-
return {
|
|
232
|
-
autoRespond: props.autoRespond === true,
|
|
233
|
-
respondingAgentSlug: props.respondingAgentSlug ?? null,
|
|
234
|
-
pollIntervalMinutes: props.pollIntervalMinutes ? neo4j.integer.toNumber(props.pollIntervalMinutes) : 5,
|
|
235
|
-
lastRespondedUid: props.lastRespondedUid ? neo4j.integer.toNumber(props.lastRespondedUid) : 0,
|
|
236
|
-
lastPollAt: props.lastPollAt ?? null,
|
|
237
|
-
consecutiveFailures: props.consecutiveFailures ? neo4j.integer.toNumber(props.consecutiveFailures) : 0,
|
|
238
|
-
autoRespondHourlyLimit: props.autoRespondHourlyLimit ? neo4j.integer.toNumber(props.autoRespondHourlyLimit) : 20,
|
|
239
|
-
autoRespondDailyLimit: props.autoRespondDailyLimit ? neo4j.integer.toNumber(props.autoRespondDailyLimit) : 100,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
finally {
|
|
243
|
-
await session.close();
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Write auto-respond config fields on the EmailAccount node.
|
|
248
|
-
* Only updates the specified fields — does not touch email/IMAP/SMTP config.
|
|
249
|
-
*/
|
|
250
|
-
export async function writeAutoRespondConfig(accountId, config) {
|
|
251
|
-
const session = getSession();
|
|
252
|
-
try {
|
|
253
|
-
const setClauses = [];
|
|
254
|
-
const params = { accountId };
|
|
255
|
-
if (config.autoRespond !== undefined) {
|
|
256
|
-
setClauses.push("e.autoRespond = $autoRespond");
|
|
257
|
-
params.autoRespond = config.autoRespond;
|
|
258
|
-
}
|
|
259
|
-
if (config.respondingAgentSlug !== undefined) {
|
|
260
|
-
setClauses.push("e.respondingAgentSlug = $respondingAgentSlug");
|
|
261
|
-
params.respondingAgentSlug = config.respondingAgentSlug;
|
|
262
|
-
}
|
|
263
|
-
if (config.pollIntervalMinutes !== undefined) {
|
|
264
|
-
setClauses.push("e.pollIntervalMinutes = $pollIntervalMinutes");
|
|
265
|
-
params.pollIntervalMinutes = neo4j.int(config.pollIntervalMinutes);
|
|
266
|
-
}
|
|
267
|
-
if (config.lastRespondedUid !== undefined) {
|
|
268
|
-
setClauses.push("e.lastRespondedUid = $lastRespondedUid");
|
|
269
|
-
params.lastRespondedUid = neo4j.int(config.lastRespondedUid);
|
|
270
|
-
}
|
|
271
|
-
if (config.lastPollAt !== undefined) {
|
|
272
|
-
setClauses.push("e.lastPollAt = $lastPollAt");
|
|
273
|
-
params.lastPollAt = config.lastPollAt;
|
|
274
|
-
}
|
|
275
|
-
if (config.consecutiveFailures !== undefined) {
|
|
276
|
-
setClauses.push("e.consecutiveFailures = $consecutiveFailures");
|
|
277
|
-
params.consecutiveFailures = neo4j.int(config.consecutiveFailures);
|
|
278
|
-
}
|
|
279
|
-
if (config.autoRespondHourlyLimit !== undefined) {
|
|
280
|
-
setClauses.push("e.autoRespondHourlyLimit = $autoRespondHourlyLimit");
|
|
281
|
-
params.autoRespondHourlyLimit = neo4j.int(config.autoRespondHourlyLimit);
|
|
282
|
-
}
|
|
283
|
-
if (config.autoRespondDailyLimit !== undefined) {
|
|
284
|
-
setClauses.push("e.autoRespondDailyLimit = $autoRespondDailyLimit");
|
|
285
|
-
params.autoRespondDailyLimit = neo4j.int(config.autoRespondDailyLimit);
|
|
286
|
-
}
|
|
287
|
-
if (setClauses.length === 0)
|
|
288
|
-
return;
|
|
289
|
-
await session.run(`MATCH (e:EmailAccount {accountId: $accountId}) SET ${setClauses.join(", ")}`, params);
|
|
290
|
-
}
|
|
291
|
-
finally {
|
|
292
|
-
await session.close();
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Read all EmailAccounts that have auto-respond enabled.
|
|
297
|
-
* Returns config + auto-respond settings for each.
|
|
298
|
-
*/
|
|
299
|
-
export async function readAutoRespondAccounts() {
|
|
300
|
-
const session = getSession();
|
|
301
|
-
try {
|
|
302
|
-
const result = await session.run(`MATCH (e:EmailAccount {autoRespond: true}) RETURN e`);
|
|
303
|
-
return result.records.map((record) => {
|
|
304
|
-
const props = record.get("e").properties;
|
|
305
|
-
return {
|
|
306
|
-
accountId: props.accountId,
|
|
307
|
-
config: {
|
|
308
|
-
email: props.email,
|
|
309
|
-
agentAddress: props.agentAddress ?? props.email,
|
|
310
|
-
imapHost: props.imapHost,
|
|
311
|
-
imapPort: neo4j.integer.toNumber(props.imapPort),
|
|
312
|
-
imapSecurity: props.imapSecurity,
|
|
313
|
-
smtpHost: props.smtpHost,
|
|
314
|
-
smtpPort: neo4j.integer.toNumber(props.smtpPort),
|
|
315
|
-
smtpSecurity: props.smtpSecurity,
|
|
316
|
-
},
|
|
317
|
-
autoRespond: {
|
|
318
|
-
autoRespond: true,
|
|
319
|
-
respondingAgentSlug: props.respondingAgentSlug ?? null,
|
|
320
|
-
pollIntervalMinutes: props.pollIntervalMinutes ? neo4j.integer.toNumber(props.pollIntervalMinutes) : 5,
|
|
321
|
-
lastRespondedUid: props.lastRespondedUid ? neo4j.integer.toNumber(props.lastRespondedUid) : 0,
|
|
322
|
-
lastPollAt: props.lastPollAt ?? null,
|
|
323
|
-
consecutiveFailures: props.consecutiveFailures ? neo4j.integer.toNumber(props.consecutiveFailures) : 0,
|
|
324
|
-
autoRespondHourlyLimit: props.autoRespondHourlyLimit ? neo4j.integer.toNumber(props.autoRespondHourlyLimit) : 20,
|
|
325
|
-
autoRespondDailyLimit: props.autoRespondDailyLimit ? neo4j.integer.toNumber(props.autoRespondDailyLimit) : 100,
|
|
326
|
-
},
|
|
327
|
-
};
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
finally {
|
|
331
|
-
await session.close();
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
226
|
/**
|
|
335
227
|
* Load full credentials (config + password).
|
|
336
228
|
* Returns null with a reason if either piece is missing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,MAAM,cAAc,CAAC;AAEjC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ Activate when the operator asks for any of:
|
|
|
19
19
|
Do **not** activate for:
|
|
20
20
|
|
|
21
21
|
- Listing or searching emails as the end-goal (no draft intent) — let `email-search` / `email-graph-query` answer directly.
|
|
22
|
-
- Setup, status checks, OTP extraction
|
|
22
|
+
- Setup, status checks, OTP extraction — those are direct tool calls.
|
|
23
23
|
- Any automated send loop. If the operator asks for drip / scheduled / broadcast sends, decline and explain that this skill is human-in-the-loop only.
|
|
24
24
|
|
|
25
25
|
## Flow — reply to an existing thread
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# read-brand-json.sh — brand.json reader + LocalBusiness bootstrap helpers.
|
|
3
3
|
#
|
|
4
|
-
# Sourced by seed-neo4j.sh. Three functions:
|
|
4
|
+
# Sourced by setup-account.sh and seed-neo4j.sh. Three functions:
|
|
5
5
|
#
|
|
6
6
|
# read_brand_json_key <brand.json path> <key>
|
|
7
7
|
# Sets the global BRAND_JSON_VALUE to the value at <key>, or empty when
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# resolve-account-dir.sh — identity-aware account resolver + orphan sweeper
|
|
2
|
-
# Sourced by seed-neo4j.sh. Defines `resolve_and_sweep_account_dir`.
|
|
2
|
+
# Sourced by setup-account.sh and seed-neo4j.sh. Defines `resolve_and_sweep_account_dir`.
|
|
3
3
|
#
|
|
4
4
|
# Invariant: the TypeScript `resolveAccount()` at platform/ui/app/lib/claude-agent.ts
|
|
5
5
|
# is READ-ONLY. This bash helper is the SOLE sweep surface, because seed-time is
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ============================================================
|
|
3
|
-
# seed-neo4j.sh —
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
3
|
+
# seed-neo4j.sh — Neo4j schema + root-node seeding
|
|
4
|
+
# Applies the schema (constraints, indexes, vector indexes) and
|
|
5
|
+
# MERGEs the per-account root :LocalBusiness and owner :AdminUser
|
|
6
|
+
# nodes. Account directory creation, Claude Code settings, hooks
|
|
7
|
+
# wiring, and specialist templates live in `setup-account.sh`.
|
|
8
|
+
# This script does no filesystem setup beyond reading what
|
|
9
|
+
# setup-account.sh wrote.
|
|
7
10
|
# ============================================================
|
|
8
11
|
|
|
9
12
|
set -euo pipefail
|
|
10
13
|
|
|
11
14
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
15
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
13
|
-
TEMPLATES_DIR="$PROJECT_DIR/templates"
|
|
14
|
-
# Accounts live at {installDir}/data/accounts/ — outside the platform/ wipe zone.
|
|
15
|
-
INSTALL_DIR="$(dirname "$PROJECT_DIR")"
|
|
16
|
-
ACCOUNTS_DIR="$INSTALL_DIR/data/accounts"
|
|
17
16
|
NEO4J_DIR="$PROJECT_DIR/neo4j"
|
|
18
17
|
|
|
19
18
|
# NEO4J_URI is hard-required. The previous default
|
|
@@ -41,426 +40,20 @@ fi
|
|
|
41
40
|
CYPHER_SHELL="cypher-shell"
|
|
42
41
|
|
|
43
42
|
# ------------------------------------------------------------------
|
|
44
|
-
# 1.
|
|
43
|
+
# 1. Resolve the account dir (must already exist; setup-account.sh
|
|
44
|
+
# is the creator). The resolver is idempotent — calling it here
|
|
45
|
+
# re-finds the same ACCOUNT_DIR / ACCOUNT_ID setup-account.sh
|
|
46
|
+
# minted.
|
|
45
47
|
# ------------------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
# Resolve existing account by identity (users.json[0].userId) or mint a new one on fresh install.
|
|
48
|
-
# Orphan siblings under data/accounts/ — non-matching dirs left behind by the userId
|
|
49
|
-
# regeneration — are swept to data/accounts/.trash/<uuid>-<ISO8601-ts>/. Multi-candidate with
|
|
50
|
-
# no identity match aborts loud; .trash/ is operator-emptied, never auto-cleaned.
|
|
51
48
|
# shellcheck source=lib/resolve-account-dir.sh
|
|
52
49
|
. "$SCRIPT_DIR/lib/resolve-account-dir.sh"
|
|
53
50
|
# shellcheck source=lib/read-brand-json.sh
|
|
54
51
|
. "$SCRIPT_DIR/lib/read-brand-json.sh"
|
|
55
|
-
# Resolve brand-aware persistent users.json path before the resolver runs.
|
|
56
|
-
# Mirrors the resolution lower in this file (around the post-Task-904 USERS_FILE
|
|
57
|
-
# block); duplicated here because resolve_and_sweep_account_dir runs first.
|
|
58
52
|
_RESOLVER_CONFIG_DIR_NAME=".maxy"
|
|
59
53
|
read_brand_json_key "$PROJECT_DIR/config/brand.json" "configDir"
|
|
60
54
|
[ -n "$BRAND_JSON_VALUE" ] && _RESOLVER_CONFIG_DIR_NAME="$BRAND_JSON_VALUE"
|
|
61
55
|
USERS_FILE="$HOME/$_RESOLVER_CONFIG_DIR_NAME/users.json" resolve_and_sweep_account_dir
|
|
62
56
|
|
|
63
|
-
mkdir -p "$ACCOUNT_DIR/agents/admin" "$ACCOUNT_DIR/agents/public" "$ACCOUNT_DIR/.claude" "$ACCOUNT_DIR/specialists/.claude-plugin" "$ACCOUNT_DIR/specialists/agents"
|
|
64
|
-
|
|
65
|
-
# Claude Code discovers project-level .claude/ (agents, settings) relative to the
|
|
66
|
-
# nearest .git root. Without a .git in the account directory, Claude Code traverses
|
|
67
|
-
# up to ~/maxy/.git and misses everything in accountDir/.claude/. Initialise a git
|
|
68
|
-
# repo so the account directory IS the project root for Claude Code.
|
|
69
|
-
[ -d "$ACCOUNT_DIR/.git" ] || git init -q "$ACCOUNT_DIR"
|
|
70
|
-
|
|
71
|
-
# Claude Code permissions — project-level settings now work since the account dir
|
|
72
|
-
# has .git. Write permissions to the account's own .claude/settings.json.
|
|
73
|
-
ACCOUNT_SETTINGS="$ACCOUNT_DIR/.claude/settings.json"
|
|
74
|
-
|
|
75
|
-
# Wildcard permissions for all plugin MCP servers (core + optional).
|
|
76
|
-
# Including optional plugins here is safe — permissions without a running
|
|
77
|
-
# MCP server are inert. This ensures tools are allowed when the user
|
|
78
|
-
# enables an optional plugin, without requiring a re-seed.
|
|
79
|
-
MAXY_PERMISSIONS='["Read","Edit","Write","Bash","Glob","Grep","Agent","mcp__memory__*","mcp__contacts__*","mcp__telegram__*","mcp__admin__*","mcp__cloudflare__*","mcp__work__*","mcp__scheduling__*","mcp__email__*","mcp__workflows__*","mcp__web__*","mcp__plugin_playwright_playwright__*"]'
|
|
80
|
-
|
|
81
|
-
# Append wildcard permissions for any optional plugins not already covered
|
|
82
|
-
PLUGINS_DIR="$(dirname "$0")/../plugins"
|
|
83
|
-
if [ -d "$PLUGINS_DIR" ]; then
|
|
84
|
-
for PLUGIN_DIR in "$PLUGINS_DIR"/*/; do
|
|
85
|
-
PLUGIN_NAME="$(basename "$PLUGIN_DIR")"
|
|
86
|
-
# Skip plugins already in the static list
|
|
87
|
-
case "$MAXY_PERMISSIONS" in
|
|
88
|
-
*"mcp__${PLUGIN_NAME}__"*) continue ;;
|
|
89
|
-
esac
|
|
90
|
-
# Only add if plugin has an MCP server
|
|
91
|
-
if [ -d "$PLUGIN_DIR/mcp" ]; then
|
|
92
|
-
MAXY_PERMISSIONS="${MAXY_PERMISSIONS%]},\"mcp__${PLUGIN_NAME}__*\"]"
|
|
93
|
-
fi
|
|
94
|
-
done
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
# Always overwrite — Rubytech-controlled. Project-level settings take
|
|
98
|
-
# precedence over global, so each account is properly isolated.
|
|
99
|
-
#
|
|
100
|
-
# Hook commands use $PLATFORM_ROOT (set by claude-agent.ts at spawn time)
|
|
101
|
-
# to locate scripts relative to the platform installation, not the account dir.
|
|
102
|
-
#
|
|
103
|
-
# Hooks wired:
|
|
104
|
-
# PreToolUse — pre-tool-use.sh: admin write boundaries
|
|
105
|
-
# playwright-file-guard.sh: intercepts browser_navigate with file:// URLs
|
|
106
|
-
# webfetch-preflight.mjs: detects JS-SPA shells before WebFetch's
|
|
107
|
-
# 60s extraction timeout. Fail-open on any error;
|
|
108
|
-
# on positive SPA detection exits 2 with WEBFETCH_CANNOT_READ_JS_SPA.
|
|
109
|
-
# archive-ingest-surface-gate.sh:
|
|
110
|
-
# narrows the database-operator subagent's effective surface
|
|
111
|
-
# during conversation-archive ingestion to exactly one Bash
|
|
112
|
-
# entry (memory/bin/conversation-archive-ingest.sh --source
|
|
113
|
-
# <enum>) plus read-only neighbours. Defensive blocks on
|
|
114
|
-
# withdrawn MCP tool names (mcp__memory__whatsapp-export-
|
|
115
|
-
# {parse,preview,insight-write,insight-pass},
|
|
116
|
-
# mcp__memory__memory-archive-write when
|
|
117
|
-
# archiveType=whatsapp-export) remain so any future
|
|
118
|
-
# reintroduction loud-fails. Preserves the plugin-source
|
|
119
|
-
# edit, JS test-runner, and post-parse-error blocks.
|
|
120
|
-
# Wired at three points: explicit Edit/Write/NotebookEdit/Bash
|
|
121
|
-
# matchers, a no-matcher PreToolUse entry (the
|
|
122
|
-
# post-parse-error gate fires on every tool),
|
|
123
|
-
# and a PostToolUse regex matcher for parse tools.
|
|
124
|
-
# UserPromptSubmit — archive-ingest-surface-gate.sh clears the
|
|
125
|
-
# parse-error flag when the operator's next prompt arrives.
|
|
126
|
-
# askuserquestion-investigate-gate.sh (Task 241): PreToolUse
|
|
127
|
-
# matcher=AskUserQuestion. Blocks the question when no
|
|
128
|
-
# read-only investigation tool has fired since the latest
|
|
129
|
-
# real user turn in the session JSONL. Fail-open on
|
|
130
|
-
# missing transcript or parse error. One [ask-gate]
|
|
131
|
-
# decision line per call.
|
|
132
|
-
#
|
|
133
|
-
# Task 214 — the per-turn Stop-hook registration that fired
|
|
134
|
-
# turn-completed-graph-write.sh once per admin turn is no longer written.
|
|
135
|
-
# The script, envelope walker, loopback /api/admin/claude-sessions 127.0.0.1
|
|
136
|
-
# bypass, [turn-recorder] emitters, recorder-auto-archive subscriber, and
|
|
137
|
-
# initialMessage envelope spec are preserved as dormant infrastructure for
|
|
138
|
-
# any future autonomous post-turn flow. Admin now delegates graph writes
|
|
139
|
-
# to database-operator via the Task tool inside its own session.
|
|
140
|
-
#
|
|
141
|
-
# Task 282 — Stop hook session-end-retrospective.sh wired below. Fires on
|
|
142
|
-
# every assistant end_turn but exits 0 with `trigger-skipped reason=…`
|
|
143
|
-
# on every path EXCEPT when the operator's latest real-user message
|
|
144
|
-
# carries an end-intent token (/end, /archive, end session,
|
|
145
|
-
# archive this session). On that path it blocks (exit 2 + stderr
|
|
146
|
-
# instruction block) until the admin agent calls the
|
|
147
|
-
# session-retrospective-mark-complete MCP sentinel tool, whose tool_use
|
|
148
|
-
# in the JSONL is the release signal. Recursion guard: any session
|
|
149
|
-
# carrying MAXY_SPECIALIST=<name> (specialist subagent) skips the gate.
|
|
150
|
-
HOOKS_PATH="\$PLATFORM_ROOT/plugins/admin/hooks"
|
|
151
|
-
cat > "$ACCOUNT_SETTINGS" << SETTINGS_EOF
|
|
152
|
-
{
|
|
153
|
-
"permissions": {
|
|
154
|
-
"allow": $MAXY_PERMISSIONS
|
|
155
|
-
},
|
|
156
|
-
"hooks": {
|
|
157
|
-
"PreToolUse": [
|
|
158
|
-
{
|
|
159
|
-
"matcher": "Write",
|
|
160
|
-
"hooks": [
|
|
161
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" },
|
|
162
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
163
|
-
]
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
"matcher": "Edit",
|
|
167
|
-
"hooks": [
|
|
168
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" },
|
|
169
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
170
|
-
]
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
"matcher": "NotebookEdit",
|
|
174
|
-
"hooks": [
|
|
175
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
176
|
-
]
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
"matcher": "Bash",
|
|
180
|
-
"hooks": [
|
|
181
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" },
|
|
182
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
183
|
-
]
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
"matcher": "mcp__plugin_memory_memory__memory-write",
|
|
187
|
-
"hooks": [
|
|
188
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" }
|
|
189
|
-
]
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
"matcher": "mcp__plugin_memory_memory__memory-update",
|
|
193
|
-
"hooks": [
|
|
194
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" }
|
|
195
|
-
]
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
"hooks": [
|
|
199
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
200
|
-
]
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
"matcher": "mcp__plugin_playwright_playwright__browser_navigate",
|
|
204
|
-
"hooks": [
|
|
205
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/playwright-file-guard.sh" }
|
|
206
|
-
]
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
"matcher": "WebFetch",
|
|
210
|
-
"hooks": [
|
|
211
|
-
{ "type": "command", "command": "node $HOOKS_PATH/webfetch-preflight.mjs" }
|
|
212
|
-
]
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
"matcher": "AskUserQuestion",
|
|
216
|
-
"hooks": [
|
|
217
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/askuserquestion-investigate-gate.sh" }
|
|
218
|
-
]
|
|
219
|
-
}
|
|
220
|
-
],
|
|
221
|
-
"PostToolUse": [
|
|
222
|
-
{
|
|
223
|
-
"matcher": "mcp__.*__.*-(export|import)-parse$",
|
|
224
|
-
"hooks": [
|
|
225
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
226
|
-
]
|
|
227
|
-
}
|
|
228
|
-
],
|
|
229
|
-
"UserPromptSubmit": [
|
|
230
|
-
{
|
|
231
|
-
"hooks": [
|
|
232
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
233
|
-
]
|
|
234
|
-
}
|
|
235
|
-
],
|
|
236
|
-
"Stop": [
|
|
237
|
-
{
|
|
238
|
-
"hooks": [
|
|
239
|
-
{ "type": "command", "command": "bash $HOOKS_PATH/session-end-retrospective.sh" }
|
|
240
|
-
]
|
|
241
|
-
}
|
|
242
|
-
]
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
SETTINGS_EOF
|
|
246
|
-
|
|
247
|
-
# Always overwrite IDENTITY.md — Rubytech-controlled, pure behaviour.
|
|
248
|
-
cp "$TEMPLATES_DIR/agents/admin/IDENTITY.md" "$ACCOUNT_DIR/agents/admin/IDENTITY.md"
|
|
249
|
-
cp "$TEMPLATES_DIR/agents/public/IDENTITY.md" "$ACCOUNT_DIR/agents/public/IDENTITY.md"
|
|
250
|
-
echo " agents/public/IDENTITY.md installed"
|
|
251
|
-
|
|
252
|
-
# Always overwrite specialist plugin — Rubytech-controlled, not user-editable.
|
|
253
|
-
# Specialists are a Claude Code plugin loaded via --plugin-dir. The plugin lives at
|
|
254
|
-
# accountDir/specialists/ with .claude-plugin/plugin.json and agents/*.md.
|
|
255
|
-
# The admin agent dispatches them as specialists:{name} via the Agent tool.
|
|
256
|
-
cp "$TEMPLATES_DIR/specialists/.claude-plugin/plugin.json" "$ACCOUNT_DIR/specialists/.claude-plugin/plugin.json"
|
|
257
|
-
|
|
258
|
-
# Remove orphaned core specialist files before copying fresh templates.
|
|
259
|
-
# Core specialists (no '--' in filename) are Rubytech-controlled and fully replaced
|
|
260
|
-
# on every seed. Premium plugin agents (filename contains '--') are preserved —
|
|
261
|
-
# they are managed by the admin agent when plugins are activated/deactivated.
|
|
262
|
-
for _existing in "$ACCOUNT_DIR/specialists/agents/"*.md; do
|
|
263
|
-
[ -f "$_existing" ] || continue
|
|
264
|
-
case "$(basename "$_existing")" in
|
|
265
|
-
*--*) continue ;; # Premium plugin agent — preserve
|
|
266
|
-
esac
|
|
267
|
-
rm -f "$_existing"
|
|
268
|
-
done
|
|
269
|
-
|
|
270
|
-
for specialist in "$TEMPLATES_DIR/specialists/agents/"*.md; do
|
|
271
|
-
[ -f "$specialist" ] && cp "$specialist" "$ACCOUNT_DIR/specialists/agents/$(basename "$specialist")"
|
|
272
|
-
done
|
|
273
|
-
|
|
274
|
-
# Clean up stale .claude/agents/*.md from previous seed format.
|
|
275
|
-
# The old format placed specialists here as slash-command agents — that never worked
|
|
276
|
-
# for programmatic dispatch. Safe to remove; .claude/ dir stays for settings.json.
|
|
277
|
-
rm -f "$ACCOUNT_DIR/.claude/agents/"*.md 2>/dev/null || true
|
|
278
|
-
|
|
279
|
-
# SOUL.md — user-controlled personalisation. Only create if missing. Never overwrite.
|
|
280
|
-
[ -f "$ACCOUNT_DIR/agents/admin/SOUL.md" ] || cp "$TEMPLATES_DIR/agents/admin/SOUL.md" "$ACCOUNT_DIR/agents/admin/SOUL.md"
|
|
281
|
-
|
|
282
|
-
# Public agent SOUL.md + config.json — create if missing, never overwrite.
|
|
283
|
-
# IDENTITY.md is handled in the Rubytech-controlled block above.
|
|
284
|
-
[ -f "$ACCOUNT_DIR/agents/public/SOUL.md" ] || cp "$TEMPLATES_DIR/agents/public/SOUL.md" "$ACCOUNT_DIR/agents/public/SOUL.md"
|
|
285
|
-
[ -f "$ACCOUNT_DIR/agents/public/config.json" ] || cp "$TEMPLATES_DIR/agents/public/config.json" "$ACCOUNT_DIR/agents/public/config.json"
|
|
286
|
-
|
|
287
|
-
# AGENTS.md — specialist registry. Pre-populated from templates, maintained by admin agent at runtime.
|
|
288
|
-
# Always overwrite on re-seed (Rubytech-controlled initial state, like IDENTITY.md).
|
|
289
|
-
# Dispatch format: specialists:{name} via the Agent tool.
|
|
290
|
-
printf '# Installed Roles\n\nDispatch via the Agent tool with `subagent_type: "specialists:{name}"`.\n\n' > "$ACCOUNT_DIR/agents/admin/AGENTS.md"
|
|
291
|
-
for specialist in "$ACCOUNT_DIR/specialists/agents/"*.md; do
|
|
292
|
-
[ -f "$specialist" ] || continue
|
|
293
|
-
# Extract name and description from YAML frontmatter
|
|
294
|
-
_name=$(sed -n 's/^name: *//p' "$specialist" | head -1)
|
|
295
|
-
_desc=$(sed -n 's/^description: *"*//p' "$specialist" | sed 's/"$//' | head -1)
|
|
296
|
-
[ -z "$_name" ] && continue
|
|
297
|
-
# Skip Phase 1 stubs — not yet functional
|
|
298
|
-
echo "$_desc" | grep -qi "Phase 1" && continue
|
|
299
|
-
printf -- '- **specialists:%s**: %s\n' "$_name" "$_desc" >> "$ACCOUNT_DIR/agents/admin/AGENTS.md"
|
|
300
|
-
done
|
|
301
|
-
|
|
302
|
-
# Create account.json only if it doesn't exist (business config is in the graph).
|
|
303
|
-
# Reads defaults from the template so there is a single source of truth.
|
|
304
|
-
if [ ! -f "$ACCOUNT_DIR/account.json" ]; then
|
|
305
|
-
TEMPLATE="$TEMPLATES_DIR/account.json"
|
|
306
|
-
if [ -f "$TEMPLATE" ]; then
|
|
307
|
-
sed "s/\"accountId\": *\"[^\"]*\"/\"accountId\":\"$ACCOUNT_ID\"/" "$TEMPLATE" \
|
|
308
|
-
| sed "s/\"tier\": *\"[^\"]*\"/\"tier\":\"solo\"/" \
|
|
309
|
-
> "$ACCOUNT_DIR/account.json"
|
|
310
|
-
else
|
|
311
|
-
echo "ERROR: account.json template not found at $TEMPLATE" >&2
|
|
312
|
-
exit 1
|
|
313
|
-
fi
|
|
314
|
-
fi
|
|
315
|
-
|
|
316
|
-
# Backfill defaultAgent in account.json if missing (existing accounts earlier).
|
|
317
|
-
# Uses the first non-admin agent directory that has a config.json.
|
|
318
|
-
if [ -f "$ACCOUNT_DIR/account.json" ] && ! grep -q '"defaultAgent"' "$ACCOUNT_DIR/account.json"; then
|
|
319
|
-
_DEFAULT_SLUG=""
|
|
320
|
-
for _AGENT_DIR in "$ACCOUNT_DIR/agents"/*/; do
|
|
321
|
-
_AGENT_NAME="$(basename "$_AGENT_DIR")"
|
|
322
|
-
[ "$_AGENT_NAME" = "admin" ] && continue
|
|
323
|
-
[ -f "$_AGENT_DIR/config.json" ] && { _DEFAULT_SLUG="$_AGENT_NAME"; break; }
|
|
324
|
-
done
|
|
325
|
-
if [ -n "$_DEFAULT_SLUG" ]; then
|
|
326
|
-
# Insert defaultAgent before the closing brace
|
|
327
|
-
sed -i'' "s/}$/,\"defaultAgent\":\"$_DEFAULT_SLUG\"}/" "$ACCOUNT_DIR/account.json"
|
|
328
|
-
echo " Backfilled defaultAgent=$_DEFAULT_SLUG in account.json"
|
|
329
|
-
fi
|
|
330
|
-
fi
|
|
331
|
-
|
|
332
|
-
# ------------------------------------------------------------------
|
|
333
|
-
# Seed enabledPlugins from brand.json plugins.defaultEnabled
|
|
334
|
-
# ------------------------------------------------------------------
|
|
335
|
-
# Fresh accounts: replaces the template's empty [] with defaultEnabled.
|
|
336
|
-
# Existing accounts: additive merge — adds missing defaultEnabled entries,
|
|
337
|
-
# never removes plugins the user enabled manually.
|
|
338
|
-
# Dependency validation: skips any defaultEnabled plugin whose PLUGIN.md
|
|
339
|
-
# `requires:` dependencies are not satisfied by core or defaultEnabled.
|
|
340
|
-
BRAND_JSON="$PROJECT_DIR/config/brand.json"
|
|
341
|
-
if [ -f "$BRAND_JSON" ] && [ -f "$ACCOUNT_DIR/account.json" ]; then
|
|
342
|
-
python3 -c "
|
|
343
|
-
import json, os, sys
|
|
344
|
-
|
|
345
|
-
brand_path = '$BRAND_JSON'
|
|
346
|
-
account_path = '$ACCOUNT_DIR/account.json'
|
|
347
|
-
plugins_dir = '$PROJECT_DIR/plugins'
|
|
348
|
-
|
|
349
|
-
with open(brand_path) as f:
|
|
350
|
-
brand = json.load(f)
|
|
351
|
-
|
|
352
|
-
plugins_cfg = brand.get('plugins', {})
|
|
353
|
-
default_enabled = plugins_cfg.get('defaultEnabled', [])
|
|
354
|
-
core = set(plugins_cfg.get('core', []))
|
|
355
|
-
|
|
356
|
-
if not default_enabled:
|
|
357
|
-
print(' [seed] no defaultEnabled plugins in brand.json — skipping')
|
|
358
|
-
sys.exit(0)
|
|
359
|
-
|
|
360
|
-
# Dependency validation: check each plugin's PLUGIN.md requires field.
|
|
361
|
-
# A dependency is satisfied if it appears in core or in defaultEnabled.
|
|
362
|
-
satisfied = core | set(default_enabled)
|
|
363
|
-
validated = []
|
|
364
|
-
for plugin in default_enabled:
|
|
365
|
-
plugin_md = os.path.join(plugins_dir, plugin, 'PLUGIN.md')
|
|
366
|
-
requires = []
|
|
367
|
-
if os.path.isfile(plugin_md):
|
|
368
|
-
in_frontmatter = False
|
|
369
|
-
in_requires = False
|
|
370
|
-
with open(plugin_md) as f:
|
|
371
|
-
for line in f:
|
|
372
|
-
stripped = line.rstrip()
|
|
373
|
-
if stripped == '---':
|
|
374
|
-
if in_frontmatter:
|
|
375
|
-
break
|
|
376
|
-
in_frontmatter = True
|
|
377
|
-
continue
|
|
378
|
-
if not in_frontmatter:
|
|
379
|
-
continue
|
|
380
|
-
if stripped.startswith('requires:'):
|
|
381
|
-
# Handle inline list: requires: [a, b]
|
|
382
|
-
inline = stripped.split(':', 1)[1].strip()
|
|
383
|
-
if inline.startswith('['):
|
|
384
|
-
requires = [x.strip().strip('\"').strip(\"'\") for x in inline.strip('[]').split(',') if x.strip()]
|
|
385
|
-
in_requires = False
|
|
386
|
-
else:
|
|
387
|
-
in_requires = True
|
|
388
|
-
continue
|
|
389
|
-
if in_requires:
|
|
390
|
-
if stripped.startswith(' - '):
|
|
391
|
-
requires.append(stripped.lstrip(' -').strip())
|
|
392
|
-
else:
|
|
393
|
-
in_requires = False
|
|
394
|
-
unmet = [r for r in requires if r not in satisfied]
|
|
395
|
-
if unmet:
|
|
396
|
-
print(f' [seed] WARNING: skipping defaultEnabled plugin \"{plugin}\" — unmet requires: {unmet}')
|
|
397
|
-
else:
|
|
398
|
-
validated.append(plugin)
|
|
399
|
-
|
|
400
|
-
with open(account_path) as f:
|
|
401
|
-
account = json.load(f)
|
|
402
|
-
|
|
403
|
-
existing = account.get('enabledPlugins', [])
|
|
404
|
-
existing_set = set(existing)
|
|
405
|
-
added = [p for p in validated if p not in existing_set]
|
|
406
|
-
account['enabledPlugins'] = existing + added
|
|
407
|
-
|
|
408
|
-
with open(account_path, 'w') as f:
|
|
409
|
-
json.dump(account, f, indent=2)
|
|
410
|
-
f.write('\n')
|
|
411
|
-
|
|
412
|
-
if not existing:
|
|
413
|
-
print(f' [seed] seeded enabledPlugins: {validated}')
|
|
414
|
-
elif added:
|
|
415
|
-
print(f' [seed] merged into enabledPlugins: +{added} (existing: {existing})')
|
|
416
|
-
else:
|
|
417
|
-
print(f' [seed] enabledPlugins already contains all defaultEnabled entries')
|
|
418
|
-
"
|
|
419
|
-
fi
|
|
420
|
-
|
|
421
|
-
echo " Account $ACCOUNT_ID at $ACCOUNT_DIR"
|
|
422
|
-
|
|
423
|
-
# ------------------------------------------------------------------
|
|
424
|
-
# 1b. Resolve first admin userId from users.json
|
|
425
|
-
# ------------------------------------------------------------------
|
|
426
|
-
# users.json is created by the set-pin POST during onboarding. The seed
|
|
427
|
-
# script reads it to stamp the AdminUser node; it never creates users.json.
|
|
428
|
-
|
|
429
|
-
CONFIG_DIR="$PROJECT_DIR/config"
|
|
430
|
-
|
|
431
|
-
# Resolve the brand-specific config directory.
|
|
432
|
-
# Mirrors the logic in platform/ui/app/lib/paths.ts.
|
|
433
|
-
_CONFIG_DIR_NAME=".maxy"
|
|
434
|
-
read_brand_json_key "$CONFIG_DIR/brand.json" "configDir"
|
|
435
|
-
[ -n "$BRAND_JSON_VALUE" ] && _CONFIG_DIR_NAME="$BRAND_JSON_VALUE"
|
|
436
|
-
# users.json lives under $HOME/$_CONFIG_DIR_NAME, not the wipe zone.
|
|
437
|
-
USERS_FILE="$HOME/$_CONFIG_DIR_NAME/users.json"
|
|
438
|
-
mkdir -p "$HOME/$_CONFIG_DIR_NAME"
|
|
439
|
-
|
|
440
|
-
if [ -f "$USERS_FILE" ]; then
|
|
441
|
-
USER_ID=$(python3 -c "import json; print(json.load(open('$USERS_FILE'))[0]['userId'])" 2>/dev/null || true)
|
|
442
|
-
[ -n "$USER_ID" ] && echo " Existing users.json found, userId=$USER_ID"
|
|
443
|
-
|
|
444
|
-
# Ensure account.json admins[] contains the owner. Idempotent.
|
|
445
|
-
if [ -n "$USER_ID" ] && [ -f "$ACCOUNT_DIR/account.json" ]; then
|
|
446
|
-
python3 -c "
|
|
447
|
-
import json
|
|
448
|
-
with open('$ACCOUNT_DIR/account.json', 'r') as f:
|
|
449
|
-
config = json.load(f)
|
|
450
|
-
config.setdefault('admins', [])
|
|
451
|
-
if not any(a.get('userId') == '$USER_ID' for a in config['admins']):
|
|
452
|
-
config['admins'].append({'userId': '$USER_ID', 'role': 'owner'})
|
|
453
|
-
with open('$ACCOUNT_DIR/account.json', 'w') as f:
|
|
454
|
-
json.dump(config, f, indent=2)
|
|
455
|
-
f.write('\n')
|
|
456
|
-
print(' Stamped userId=$USER_ID as owner in account.json admins')
|
|
457
|
-
"
|
|
458
|
-
fi
|
|
459
|
-
else
|
|
460
|
-
echo " No users.json found — skipping AdminUser seed (set-pin POST creates it)"
|
|
461
|
-
USER_ID=""
|
|
462
|
-
fi
|
|
463
|
-
|
|
464
57
|
# ------------------------------------------------------------------
|
|
465
58
|
# 2. Apply Neo4j schema (constraints + indexes only)
|
|
466
59
|
# ------------------------------------------------------------------
|
|
@@ -486,7 +79,7 @@ fi
|
|
|
486
79
|
echo "$SCHEMA_CYPHER" | "$CYPHER_SHELL" -u "$NEO4J_USER" -p "$NEO4J_PASSWORD" -a "$NEO4J_URI"
|
|
487
80
|
|
|
488
81
|
# ------------------------------------------------------------------
|
|
489
|
-
#
|
|
82
|
+
# 3. Bootstrap root :LocalBusiness for the account
|
|
490
83
|
# ------------------------------------------------------------------
|
|
491
84
|
# Every node in the graph hierarchy (Project, Task, Person, Organisation,
|
|
492
85
|
# KnowledgeDocument) anchors to a :LocalBusiness via accountId. Without a
|
|
@@ -505,6 +98,7 @@ echo "$SCHEMA_CYPHER" | "$CYPHER_SHELL" -u "$NEO4J_USER" -p "$NEO4J_PASSWORD" -a
|
|
|
505
98
|
# default filled in on re-seed. createdAt is set ON CREATE only, so re-runs
|
|
506
99
|
# preserve the original timestamp.
|
|
507
100
|
|
|
101
|
+
BRAND_JSON="$PROJECT_DIR/config/brand.json"
|
|
508
102
|
read_brand_json_key "$BRAND_JSON" "vertical"
|
|
509
103
|
LOCALBUSINESS_BUSINESS_TYPE=$(derive_business_type "$BRAND_JSON_VALUE")
|
|
510
104
|
LOCALBUSINESS_BT_CYPHER=$(business_type_cypher "$LOCALBUSINESS_BUSINESS_TYPE")
|
|
@@ -547,10 +141,22 @@ fi
|
|
|
547
141
|
echo " [install-invariant] localbusiness-bootstrap accountId=${ACCOUNT_ID:0:8} businessType=$LOCALBUSINESS_BT_LOG result=$LOCALBUSINESS_RESULT"
|
|
548
142
|
|
|
549
143
|
# ------------------------------------------------------------------
|
|
550
|
-
#
|
|
144
|
+
# 4. Create AdminUser node + ADMIN_OF relationship
|
|
551
145
|
# ------------------------------------------------------------------
|
|
146
|
+
# Resolve owner userId from users.json (set-pin POST creates it).
|
|
147
|
+
# Same brand-aware resolution as setup-account.sh.
|
|
148
|
+
CONFIG_DIR="$PROJECT_DIR/config"
|
|
149
|
+
_CONFIG_DIR_NAME=".maxy"
|
|
150
|
+
read_brand_json_key "$CONFIG_DIR/brand.json" "configDir"
|
|
151
|
+
[ -n "$BRAND_JSON_VALUE" ] && _CONFIG_DIR_NAME="$BRAND_JSON_VALUE"
|
|
152
|
+
USERS_FILE="$HOME/$_CONFIG_DIR_NAME/users.json"
|
|
153
|
+
|
|
154
|
+
USER_ID=""
|
|
155
|
+
if [ -f "$USERS_FILE" ]; then
|
|
156
|
+
USER_ID=$(python3 -c "import json; print(json.load(open('$USERS_FILE'))[0]['userId'])" 2>/dev/null || true)
|
|
157
|
+
fi
|
|
552
158
|
|
|
553
|
-
if [ -n "$
|
|
159
|
+
if [ -n "$USER_ID" ]; then
|
|
554
160
|
# Escape single quotes for Cypher string interpolation (e.g. O'Brien → O''Brien).
|
|
555
161
|
USER_NAME=$(python3 -c "import json; n=json.load(open('$USERS_FILE'))[0]['name']; print(n.replace(\"'\",\"''\"))" 2>/dev/null || echo "Owner")
|
|
556
162
|
CREATED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
@@ -576,6 +182,8 @@ ON CREATE SET r.role = 'owner', r.grantedAt = '$CREATED_AT'
|
|
|
576
182
|
RETURN au.userId, b.accountId;
|
|
577
183
|
CYPHER_EOF
|
|
578
184
|
echo " [seed] AdminUser stamped userId=${USER_ID:0:8} accountId=${ACCOUNT_ID:0:8} role=owner"
|
|
185
|
+
else
|
|
186
|
+
echo " No users.json found — skipping AdminUser seed (set-pin POST creates it)"
|
|
579
187
|
fi
|
|
580
188
|
|
|
581
189
|
echo " Done."
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ============================================================
|
|
3
|
+
# setup-account.sh — Phase 0 account setup
|
|
4
|
+
# Creates the account directory from templates, writes the
|
|
5
|
+
# Claude Code project settings file (hooks only — no permission
|
|
6
|
+
# allowlist; native agent frontmatter is the permission surface),
|
|
7
|
+
# installs specialist plugin templates, seeds account.json
|
|
8
|
+
# defaults, and resolves the owner userId. Neo4j seeding lives
|
|
9
|
+
# in `seed-neo4j.sh`; this script does no Neo4j work.
|
|
10
|
+
# ============================================================
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
16
|
+
TEMPLATES_DIR="$PROJECT_DIR/templates"
|
|
17
|
+
# Accounts live at {installDir}/data/accounts/ — outside the platform/ wipe zone.
|
|
18
|
+
INSTALL_DIR="$(dirname "$PROJECT_DIR")"
|
|
19
|
+
ACCOUNTS_DIR="$INSTALL_DIR/data/accounts"
|
|
20
|
+
|
|
21
|
+
# ------------------------------------------------------------------
|
|
22
|
+
# 1. Resolve / create account directory
|
|
23
|
+
# ------------------------------------------------------------------
|
|
24
|
+
# Resolve existing account by identity (users.json[0].userId) or mint a new one on fresh install.
|
|
25
|
+
# Orphan siblings under data/accounts/ — non-matching dirs left behind by the userId
|
|
26
|
+
# regeneration — are swept to data/accounts/.trash/<uuid>-<ISO8601-ts>/. Multi-candidate with
|
|
27
|
+
# no identity match aborts loud; .trash/ is operator-emptied, never auto-cleaned.
|
|
28
|
+
# shellcheck source=lib/resolve-account-dir.sh
|
|
29
|
+
. "$SCRIPT_DIR/lib/resolve-account-dir.sh"
|
|
30
|
+
# shellcheck source=lib/read-brand-json.sh
|
|
31
|
+
. "$SCRIPT_DIR/lib/read-brand-json.sh"
|
|
32
|
+
# Resolve brand-aware persistent users.json path before the resolver runs.
|
|
33
|
+
_RESOLVER_CONFIG_DIR_NAME=".maxy"
|
|
34
|
+
read_brand_json_key "$PROJECT_DIR/config/brand.json" "configDir"
|
|
35
|
+
[ -n "$BRAND_JSON_VALUE" ] && _RESOLVER_CONFIG_DIR_NAME="$BRAND_JSON_VALUE"
|
|
36
|
+
USERS_FILE="$HOME/$_RESOLVER_CONFIG_DIR_NAME/users.json" resolve_and_sweep_account_dir
|
|
37
|
+
|
|
38
|
+
mkdir -p "$ACCOUNT_DIR/agents/admin" "$ACCOUNT_DIR/agents/public" "$ACCOUNT_DIR/.claude" "$ACCOUNT_DIR/specialists/.claude-plugin" "$ACCOUNT_DIR/specialists/agents"
|
|
39
|
+
|
|
40
|
+
# Claude Code discovers project-level .claude/ (agents, settings) relative to the
|
|
41
|
+
# nearest .git root. Without a .git in the account directory, Claude Code traverses
|
|
42
|
+
# up to ~/maxy/.git and misses everything in accountDir/.claude/. Initialise a git
|
|
43
|
+
# repo so the account directory IS the project root for Claude Code.
|
|
44
|
+
[ -d "$ACCOUNT_DIR/.git" ] || git init -q "$ACCOUNT_DIR"
|
|
45
|
+
|
|
46
|
+
# ------------------------------------------------------------------
|
|
47
|
+
# 2. Write project-level .claude/settings.json (HOOKS ONLY)
|
|
48
|
+
# ------------------------------------------------------------------
|
|
49
|
+
# Task 453: no `permissions.allow` block. The previous short-prefix
|
|
50
|
+
# allowlist (mcp__memory__*, mcp__contacts__*, …) never matched the
|
|
51
|
+
# plugin-manifest long-prefix tool names Claude Code actually emits
|
|
52
|
+
# (mcp__plugin_memory_memory__…), so every Task-subagent plugin call
|
|
53
|
+
# was denied at use-time. Permission enforcement comes from each agent's
|
|
54
|
+
# frontmatter `tools:` list (native CC permission surface) and from the
|
|
55
|
+
# PreToolUse approval hooks below for review-gated tools.
|
|
56
|
+
#
|
|
57
|
+
# Hook commands use $PLATFORM_ROOT (set by claude-agent.ts at spawn time)
|
|
58
|
+
# to locate scripts relative to the platform installation, not the account dir.
|
|
59
|
+
ACCOUNT_SETTINGS="$ACCOUNT_DIR/.claude/settings.json"
|
|
60
|
+
HOOKS_PATH="\$PLATFORM_ROOT/plugins/admin/hooks"
|
|
61
|
+
cat > "$ACCOUNT_SETTINGS" << SETTINGS_EOF
|
|
62
|
+
{
|
|
63
|
+
"hooks": {
|
|
64
|
+
"PreToolUse": [
|
|
65
|
+
{
|
|
66
|
+
"matcher": "Write",
|
|
67
|
+
"hooks": [
|
|
68
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" },
|
|
69
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"matcher": "Edit",
|
|
74
|
+
"hooks": [
|
|
75
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" },
|
|
76
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"matcher": "NotebookEdit",
|
|
81
|
+
"hooks": [
|
|
82
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"matcher": "Bash",
|
|
87
|
+
"hooks": [
|
|
88
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" },
|
|
89
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"matcher": "mcp__plugin_memory_memory__memory-write",
|
|
94
|
+
"hooks": [
|
|
95
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" }
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"matcher": "mcp__plugin_memory_memory__memory-update",
|
|
100
|
+
"hooks": [
|
|
101
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/pre-tool-use.sh admin" }
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"hooks": [
|
|
106
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"matcher": "mcp__plugin_playwright_playwright__browser_navigate",
|
|
111
|
+
"hooks": [
|
|
112
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/playwright-file-guard.sh" }
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"matcher": "WebFetch",
|
|
117
|
+
"hooks": [
|
|
118
|
+
{ "type": "command", "command": "node $HOOKS_PATH/webfetch-preflight.mjs" }
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"matcher": "AskUserQuestion",
|
|
123
|
+
"hooks": [
|
|
124
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/askuserquestion-investigate-gate.sh" }
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"PostToolUse": [
|
|
129
|
+
{
|
|
130
|
+
"matcher": "mcp__.*__.*-(export|import)-parse$",
|
|
131
|
+
"hooks": [
|
|
132
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
"UserPromptSubmit": [
|
|
137
|
+
{
|
|
138
|
+
"hooks": [
|
|
139
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
],
|
|
143
|
+
"Stop": [
|
|
144
|
+
{
|
|
145
|
+
"hooks": [
|
|
146
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/session-end-retrospective.sh" }
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
SETTINGS_EOF
|
|
153
|
+
|
|
154
|
+
# ------------------------------------------------------------------
|
|
155
|
+
# 3. Install agent identities and specialist plugin templates
|
|
156
|
+
# ------------------------------------------------------------------
|
|
157
|
+
# Always overwrite IDENTITY.md — Rubytech-controlled, pure behaviour.
|
|
158
|
+
cp "$TEMPLATES_DIR/agents/admin/IDENTITY.md" "$ACCOUNT_DIR/agents/admin/IDENTITY.md"
|
|
159
|
+
cp "$TEMPLATES_DIR/agents/public/IDENTITY.md" "$ACCOUNT_DIR/agents/public/IDENTITY.md"
|
|
160
|
+
echo " agents/public/IDENTITY.md installed"
|
|
161
|
+
|
|
162
|
+
# Always overwrite specialist plugin — Rubytech-controlled, not user-editable.
|
|
163
|
+
# Specialists are a Claude Code plugin loaded via --plugin-dir. The plugin lives at
|
|
164
|
+
# accountDir/specialists/ with .claude-plugin/plugin.json and agents/*.md.
|
|
165
|
+
# The admin agent dispatches them as specialists:{name} via the Agent tool.
|
|
166
|
+
cp "$TEMPLATES_DIR/specialists/.claude-plugin/plugin.json" "$ACCOUNT_DIR/specialists/.claude-plugin/plugin.json"
|
|
167
|
+
|
|
168
|
+
# Remove orphaned core specialist files before copying fresh templates.
|
|
169
|
+
# Core specialists (no '--' in filename) are Rubytech-controlled and fully replaced
|
|
170
|
+
# on every seed. Premium plugin agents (filename contains '--') are preserved —
|
|
171
|
+
# they are managed by the admin agent when plugins are activated/deactivated.
|
|
172
|
+
for _existing in "$ACCOUNT_DIR/specialists/agents/"*.md; do
|
|
173
|
+
[ -f "$_existing" ] || continue
|
|
174
|
+
case "$(basename "$_existing")" in
|
|
175
|
+
*--*) continue ;; # Premium plugin agent — preserve
|
|
176
|
+
esac
|
|
177
|
+
rm -f "$_existing"
|
|
178
|
+
done
|
|
179
|
+
|
|
180
|
+
for specialist in "$TEMPLATES_DIR/specialists/agents/"*.md; do
|
|
181
|
+
[ -f "$specialist" ] && cp "$specialist" "$ACCOUNT_DIR/specialists/agents/$(basename "$specialist")"
|
|
182
|
+
done
|
|
183
|
+
|
|
184
|
+
# Clean up stale .claude/agents/*.md from previous seed format.
|
|
185
|
+
# The old format placed specialists here as slash-command agents — that never worked
|
|
186
|
+
# for programmatic dispatch. Safe to remove; .claude/ dir stays for settings.json.
|
|
187
|
+
rm -f "$ACCOUNT_DIR/.claude/agents/"*.md 2>/dev/null || true
|
|
188
|
+
|
|
189
|
+
# SOUL.md — user-controlled personalisation. Only create if missing. Never overwrite.
|
|
190
|
+
[ -f "$ACCOUNT_DIR/agents/admin/SOUL.md" ] || cp "$TEMPLATES_DIR/agents/admin/SOUL.md" "$ACCOUNT_DIR/agents/admin/SOUL.md"
|
|
191
|
+
|
|
192
|
+
# Public agent SOUL.md + config.json — create if missing, never overwrite.
|
|
193
|
+
# IDENTITY.md is handled in the Rubytech-controlled block above.
|
|
194
|
+
[ -f "$ACCOUNT_DIR/agents/public/SOUL.md" ] || cp "$TEMPLATES_DIR/agents/public/SOUL.md" "$ACCOUNT_DIR/agents/public/SOUL.md"
|
|
195
|
+
[ -f "$ACCOUNT_DIR/agents/public/config.json" ] || cp "$TEMPLATES_DIR/agents/public/config.json" "$ACCOUNT_DIR/agents/public/config.json"
|
|
196
|
+
|
|
197
|
+
# AGENTS.md — specialist registry. Pre-populated from templates, maintained by admin agent at runtime.
|
|
198
|
+
# Always overwrite on re-seed (Rubytech-controlled initial state, like IDENTITY.md).
|
|
199
|
+
# Dispatch format: specialists:{name} via the Agent tool.
|
|
200
|
+
printf '# Installed Roles\n\nDispatch via the Agent tool with `subagent_type: "specialists:{name}"`.\n\n' > "$ACCOUNT_DIR/agents/admin/AGENTS.md"
|
|
201
|
+
for specialist in "$ACCOUNT_DIR/specialists/agents/"*.md; do
|
|
202
|
+
[ -f "$specialist" ] || continue
|
|
203
|
+
# Extract name and description from YAML frontmatter
|
|
204
|
+
_name=$(sed -n 's/^name: *//p' "$specialist" | head -1)
|
|
205
|
+
_desc=$(sed -n 's/^description: *"*//p' "$specialist" | sed 's/"$//' | head -1)
|
|
206
|
+
[ -z "$_name" ] && continue
|
|
207
|
+
# Skip Phase 1 stubs — not yet functional
|
|
208
|
+
echo "$_desc" | grep -qi "Phase 1" && continue
|
|
209
|
+
printf -- '- **specialists:%s**: %s\n' "$_name" "$_desc" >> "$ACCOUNT_DIR/agents/admin/AGENTS.md"
|
|
210
|
+
done
|
|
211
|
+
|
|
212
|
+
# ------------------------------------------------------------------
|
|
213
|
+
# 4. Create / backfill account.json
|
|
214
|
+
# ------------------------------------------------------------------
|
|
215
|
+
# Create account.json only if it doesn't exist (business config is in the graph).
|
|
216
|
+
# Reads defaults from the template so there is a single source of truth.
|
|
217
|
+
if [ ! -f "$ACCOUNT_DIR/account.json" ]; then
|
|
218
|
+
TEMPLATE="$TEMPLATES_DIR/account.json"
|
|
219
|
+
if [ -f "$TEMPLATE" ]; then
|
|
220
|
+
sed "s/\"accountId\": *\"[^\"]*\"/\"accountId\":\"$ACCOUNT_ID\"/" "$TEMPLATE" \
|
|
221
|
+
| sed "s/\"tier\": *\"[^\"]*\"/\"tier\":\"solo\"/" \
|
|
222
|
+
> "$ACCOUNT_DIR/account.json"
|
|
223
|
+
else
|
|
224
|
+
echo "ERROR: account.json template not found at $TEMPLATE" >&2
|
|
225
|
+
exit 1
|
|
226
|
+
fi
|
|
227
|
+
fi
|
|
228
|
+
|
|
229
|
+
# Backfill defaultAgent in account.json if missing (existing accounts earlier).
|
|
230
|
+
# Uses the first non-admin agent directory that has a config.json.
|
|
231
|
+
if [ -f "$ACCOUNT_DIR/account.json" ] && ! grep -q '"defaultAgent"' "$ACCOUNT_DIR/account.json"; then
|
|
232
|
+
_DEFAULT_SLUG=""
|
|
233
|
+
for _AGENT_DIR in "$ACCOUNT_DIR/agents"/*/; do
|
|
234
|
+
_AGENT_NAME="$(basename "$_AGENT_DIR")"
|
|
235
|
+
[ "$_AGENT_NAME" = "admin" ] && continue
|
|
236
|
+
[ -f "$_AGENT_DIR/config.json" ] && { _DEFAULT_SLUG="$_AGENT_NAME"; break; }
|
|
237
|
+
done
|
|
238
|
+
if [ -n "$_DEFAULT_SLUG" ]; then
|
|
239
|
+
# Insert defaultAgent before the closing brace
|
|
240
|
+
sed -i'' "s/}$/,\"defaultAgent\":\"$_DEFAULT_SLUG\"}/" "$ACCOUNT_DIR/account.json"
|
|
241
|
+
echo " Backfilled defaultAgent=$_DEFAULT_SLUG in account.json"
|
|
242
|
+
fi
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
# ------------------------------------------------------------------
|
|
246
|
+
# 5. Seed enabledPlugins from brand.json plugins.defaultEnabled
|
|
247
|
+
# ------------------------------------------------------------------
|
|
248
|
+
# Fresh accounts: replaces the template's empty [] with defaultEnabled.
|
|
249
|
+
# Existing accounts: additive merge — adds missing defaultEnabled entries,
|
|
250
|
+
# never removes plugins the user enabled manually.
|
|
251
|
+
# Dependency validation: skips any defaultEnabled plugin whose PLUGIN.md
|
|
252
|
+
# `requires:` dependencies are not satisfied by core or defaultEnabled.
|
|
253
|
+
BRAND_JSON="$PROJECT_DIR/config/brand.json"
|
|
254
|
+
if [ -f "$BRAND_JSON" ] && [ -f "$ACCOUNT_DIR/account.json" ]; then
|
|
255
|
+
python3 -c "
|
|
256
|
+
import json, os, sys
|
|
257
|
+
|
|
258
|
+
brand_path = '$BRAND_JSON'
|
|
259
|
+
account_path = '$ACCOUNT_DIR/account.json'
|
|
260
|
+
plugins_dir = '$PROJECT_DIR/plugins'
|
|
261
|
+
|
|
262
|
+
with open(brand_path) as f:
|
|
263
|
+
brand = json.load(f)
|
|
264
|
+
|
|
265
|
+
plugins_cfg = brand.get('plugins', {})
|
|
266
|
+
default_enabled = plugins_cfg.get('defaultEnabled', [])
|
|
267
|
+
core = set(plugins_cfg.get('core', []))
|
|
268
|
+
|
|
269
|
+
if not default_enabled:
|
|
270
|
+
print(' [setup] no defaultEnabled plugins in brand.json — skipping')
|
|
271
|
+
sys.exit(0)
|
|
272
|
+
|
|
273
|
+
# Dependency validation: check each plugin's PLUGIN.md requires field.
|
|
274
|
+
# A dependency is satisfied if it appears in core or in defaultEnabled.
|
|
275
|
+
satisfied = core | set(default_enabled)
|
|
276
|
+
validated = []
|
|
277
|
+
for plugin in default_enabled:
|
|
278
|
+
plugin_md = os.path.join(plugins_dir, plugin, 'PLUGIN.md')
|
|
279
|
+
requires = []
|
|
280
|
+
if os.path.isfile(plugin_md):
|
|
281
|
+
in_frontmatter = False
|
|
282
|
+
in_requires = False
|
|
283
|
+
with open(plugin_md) as f:
|
|
284
|
+
for line in f:
|
|
285
|
+
stripped = line.rstrip()
|
|
286
|
+
if stripped == '---':
|
|
287
|
+
if in_frontmatter:
|
|
288
|
+
break
|
|
289
|
+
in_frontmatter = True
|
|
290
|
+
continue
|
|
291
|
+
if not in_frontmatter:
|
|
292
|
+
continue
|
|
293
|
+
if stripped.startswith('requires:'):
|
|
294
|
+
# Handle inline list: requires: [a, b]
|
|
295
|
+
inline = stripped.split(':', 1)[1].strip()
|
|
296
|
+
if inline.startswith('['):
|
|
297
|
+
requires = [x.strip().strip('\"').strip(\"'\") for x in inline.strip('[]').split(',') if x.strip()]
|
|
298
|
+
in_requires = False
|
|
299
|
+
else:
|
|
300
|
+
in_requires = True
|
|
301
|
+
continue
|
|
302
|
+
if in_requires:
|
|
303
|
+
if stripped.startswith(' - '):
|
|
304
|
+
requires.append(stripped.lstrip(' -').strip())
|
|
305
|
+
else:
|
|
306
|
+
in_requires = False
|
|
307
|
+
unmet = [r for r in requires if r not in satisfied]
|
|
308
|
+
if unmet:
|
|
309
|
+
print(f' [setup] WARNING: skipping defaultEnabled plugin \"{plugin}\" — unmet requires: {unmet}')
|
|
310
|
+
else:
|
|
311
|
+
validated.append(plugin)
|
|
312
|
+
|
|
313
|
+
with open(account_path) as f:
|
|
314
|
+
account = json.load(f)
|
|
315
|
+
|
|
316
|
+
existing = account.get('enabledPlugins', [])
|
|
317
|
+
existing_set = set(existing)
|
|
318
|
+
added = [p for p in validated if p not in existing_set]
|
|
319
|
+
account['enabledPlugins'] = existing + added
|
|
320
|
+
|
|
321
|
+
with open(account_path, 'w') as f:
|
|
322
|
+
json.dump(account, f, indent=2)
|
|
323
|
+
f.write('\n')
|
|
324
|
+
|
|
325
|
+
if not existing:
|
|
326
|
+
print(f' [setup] seeded enabledPlugins: {validated}')
|
|
327
|
+
elif added:
|
|
328
|
+
print(f' [setup] merged into enabledPlugins: +{added} (existing: {existing})')
|
|
329
|
+
else:
|
|
330
|
+
print(f' [setup] enabledPlugins already contains all defaultEnabled entries')
|
|
331
|
+
"
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
# ------------------------------------------------------------------
|
|
335
|
+
# 6. Stamp first admin userId into account.json (if users.json present)
|
|
336
|
+
# ------------------------------------------------------------------
|
|
337
|
+
# users.json is created by the set-pin POST during onboarding. This
|
|
338
|
+
# script reads it to stamp the owner into account.json admins[]; the
|
|
339
|
+
# matching :AdminUser graph node is created by seed-neo4j.sh.
|
|
340
|
+
CONFIG_DIR="$PROJECT_DIR/config"
|
|
341
|
+
_CONFIG_DIR_NAME=".maxy"
|
|
342
|
+
read_brand_json_key "$CONFIG_DIR/brand.json" "configDir"
|
|
343
|
+
[ -n "$BRAND_JSON_VALUE" ] && _CONFIG_DIR_NAME="$BRAND_JSON_VALUE"
|
|
344
|
+
USERS_FILE="$HOME/$_CONFIG_DIR_NAME/users.json"
|
|
345
|
+
mkdir -p "$HOME/$_CONFIG_DIR_NAME"
|
|
346
|
+
|
|
347
|
+
if [ -f "$USERS_FILE" ]; then
|
|
348
|
+
USER_ID=$(python3 -c "import json; print(json.load(open('$USERS_FILE'))[0]['userId'])" 2>/dev/null || true)
|
|
349
|
+
[ -n "$USER_ID" ] && echo " Existing users.json found, userId=$USER_ID"
|
|
350
|
+
|
|
351
|
+
# Ensure account.json admins[] contains the owner. Idempotent.
|
|
352
|
+
if [ -n "$USER_ID" ] && [ -f "$ACCOUNT_DIR/account.json" ]; then
|
|
353
|
+
python3 -c "
|
|
354
|
+
import json
|
|
355
|
+
with open('$ACCOUNT_DIR/account.json', 'r') as f:
|
|
356
|
+
config = json.load(f)
|
|
357
|
+
config.setdefault('admins', [])
|
|
358
|
+
if not any(a.get('userId') == '$USER_ID' for a in config['admins']):
|
|
359
|
+
config['admins'].append({'userId': '$USER_ID', 'role': 'owner'})
|
|
360
|
+
with open('$ACCOUNT_DIR/account.json', 'w') as f:
|
|
361
|
+
json.dump(config, f, indent=2)
|
|
362
|
+
f.write('\n')
|
|
363
|
+
print(' Stamped userId=$USER_ID as owner in account.json admins')
|
|
364
|
+
"
|
|
365
|
+
fi
|
|
366
|
+
else
|
|
367
|
+
echo " No users.json found — skipping owner stamp (set-pin POST creates it)"
|
|
368
|
+
fi
|
|
369
|
+
|
|
370
|
+
echo " Account $ACCOUNT_ID at $ACCOUNT_DIR"
|
|
@@ -177,12 +177,12 @@ export function loadConfig(env = process.env) {
|
|
|
177
177
|
const accountDir = resolveAccountDir(platformRoot);
|
|
178
178
|
if (!accountDir) {
|
|
179
179
|
throw new Error(`[claude-session-manager] account-dir-unresolved: no <installDir>/data/accounts/<uuid>/account.json under ${dirname(platformRoot)}/data/accounts. ` +
|
|
180
|
-
'The installer (
|
|
180
|
+
'The installer (setup-account.sh / writeInstallDefaults) must run before manager start.');
|
|
181
181
|
}
|
|
182
182
|
// Claude Code walks `.claude/settings.json` from cwd to .git root. Defaulting
|
|
183
183
|
// spawnCwd to process.cwd() — i.e. the manager service directory — strands
|
|
184
184
|
// the account-scoped settings.json (and its Stop hook) outside that walk.
|
|
185
|
-
// Default to accountDir so
|
|
185
|
+
// Default to accountDir so setup-account.sh's `<accountDir>/.claude/settings.json`
|
|
186
186
|
// is on the discovery path. Env-var override is preserved for tests.
|
|
187
187
|
const spawnCwd = env.CLAUDE_SESSION_MANAGER_SPAWN_CWD ?? accountDir;
|
|
188
188
|
const lan = resolveLanIPv4();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|