@seat-mesh/core 0.1.25 → 0.1.27
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/chatfile/store.d.ts +1 -1
- package/dist/chatfile/store.d.ts.map +1 -1
- package/dist/chatfile/store.js +2 -2
- package/dist/chatfile/store.js.map +1 -1
- package/dist/chatroom/calls.d.ts +1 -1
- package/dist/chatroom/calls.d.ts.map +1 -1
- package/dist/chatroom/calls.js +1 -1
- package/dist/chatroom/calls.js.map +1 -1
- package/dist/chatroom/calls.test.js +1 -1
- package/dist/chatroom/calls.test.js.map +1 -1
- package/dist/chatroom/notify-act-client.d.ts +2 -0
- package/dist/chatroom/notify-act-client.d.ts.map +1 -1
- package/dist/chatroom/notify-act-client.js +11 -3
- package/dist/chatroom/notify-act-client.js.map +1 -1
- package/dist/chatroom/notify-act-client.test.d.ts +2 -0
- package/dist/chatroom/notify-act-client.test.d.ts.map +1 -0
- package/dist/chatroom/notify-act-client.test.js +27 -0
- package/dist/chatroom/notify-act-client.test.js.map +1 -0
- package/dist/chatroom/room.d.ts +1 -1
- package/dist/chatroom/room.d.ts.map +1 -1
- package/dist/chatroom/room.js +2 -2
- package/dist/chatroom/room.js.map +1 -1
- package/dist/chatroom/room.test.js +1 -1
- package/dist/chatroom/room.test.js.map +1 -1
- package/dist/chatroom/types.d.ts +2 -2
- package/dist/comms/envelope.d.ts +11 -11
- package/dist/contracts/balance.d.ts +1 -1
- package/dist/contracts/balance.d.ts.map +1 -1
- package/dist/contracts/supervise.d.ts +5 -3
- package/dist/contracts/supervise.d.ts.map +1 -1
- package/dist/contracts/supervise.js +19 -1
- package/dist/contracts/supervise.js.map +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/messages/mesh-copy.js +1 -1
- package/dist/messages/mesh-copy.js.map +1 -1
- package/dist/paths/engine-paths.d.ts +4 -0
- package/dist/paths/engine-paths.d.ts.map +1 -0
- package/dist/paths/engine-paths.js +45 -0
- package/dist/paths/engine-paths.js.map +1 -0
- package/dist/paths/paths-manifest.d.ts +34 -0
- package/dist/paths/paths-manifest.d.ts.map +1 -0
- package/dist/paths/paths-manifest.js +79 -0
- package/dist/paths/paths-manifest.js.map +1 -0
- package/dist/paths/paths-manifest.test.d.ts +2 -0
- package/dist/paths/paths-manifest.test.d.ts.map +1 -0
- package/dist/paths/paths-manifest.test.js +58 -0
- package/dist/paths/paths-manifest.test.js.map +1 -0
- package/dist/paths/paths.d.ts +5 -0
- package/dist/paths/paths.d.ts.map +1 -0
- package/dist/paths/paths.js +17 -0
- package/dist/paths/paths.js.map +1 -0
- package/dist/paths/runtime-paths.d.ts +43 -0
- package/dist/paths/runtime-paths.d.ts.map +1 -0
- package/dist/paths/runtime-paths.js +94 -0
- package/dist/paths/runtime-paths.js.map +1 -0
- package/dist/paths/runtime-paths.test.d.ts +2 -0
- package/dist/paths/runtime-paths.test.d.ts.map +1 -0
- package/dist/paths/runtime-paths.test.js +86 -0
- package/dist/paths/runtime-paths.test.js.map +1 -0
- package/dist/profile/profile-edit.d.ts +26 -0
- package/dist/profile/profile-edit.d.ts.map +1 -0
- package/dist/profile/profile-edit.js +87 -0
- package/dist/profile/profile-edit.js.map +1 -0
- package/dist/profile/profile-edit.test.d.ts +2 -0
- package/dist/profile/profile-edit.test.d.ts.map +1 -0
- package/dist/profile/profile-edit.test.js +111 -0
- package/dist/profile/profile-edit.test.js.map +1 -0
- package/dist/profile/profile.d.ts +52 -0
- package/dist/profile/profile.d.ts.map +1 -0
- package/dist/profile/profile.js +93 -0
- package/dist/profile/profile.js.map +1 -0
- package/dist/profile/profile.test.d.ts +2 -0
- package/dist/profile/profile.test.d.ts.map +1 -0
- package/dist/profile/profile.test.js +25 -0
- package/dist/profile/profile.test.js.map +1 -0
- package/dist/runtime/dotdir.d.ts +11 -0
- package/dist/runtime/dotdir.d.ts.map +1 -0
- package/dist/runtime/dotdir.js +30 -0
- package/dist/runtime/dotdir.js.map +1 -0
- package/dist/runtime/dotdir.test.d.ts +2 -0
- package/dist/runtime/dotdir.test.d.ts.map +1 -0
- package/dist/runtime/dotdir.test.js +26 -0
- package/dist/runtime/dotdir.test.js.map +1 -0
- package/dist/runtime/global-registry.d.ts +28 -0
- package/dist/runtime/global-registry.d.ts.map +1 -0
- package/dist/runtime/global-registry.js +124 -0
- package/dist/runtime/global-registry.js.map +1 -0
- package/dist/runtime/mesh-state-merge.d.ts +7 -0
- package/dist/runtime/mesh-state-merge.d.ts.map +1 -0
- package/dist/runtime/mesh-state-merge.js +48 -0
- package/dist/runtime/mesh-state-merge.js.map +1 -0
- package/dist/runtime/mesh-state-merge.test.d.ts +2 -0
- package/dist/runtime/mesh-state-merge.test.d.ts.map +1 -0
- package/dist/runtime/mesh-state-merge.test.js +36 -0
- package/dist/runtime/mesh-state-merge.test.js.map +1 -0
- package/dist/runtime/role-index.d.ts +53 -0
- package/dist/runtime/role-index.d.ts.map +1 -0
- package/dist/runtime/role-index.js +179 -0
- package/dist/runtime/role-index.js.map +1 -0
- package/dist/runtime/role-index.test.d.ts +2 -0
- package/dist/runtime/role-index.test.d.ts.map +1 -0
- package/dist/runtime/role-index.test.js +85 -0
- package/dist/runtime/role-index.test.js.map +1 -0
- package/dist/schema/agents.d.ts +75 -75
- package/dist/schema/profile.d.ts +2 -2
- package/dist/stack/exec.d.ts +1 -1
- package/dist/stack/exec.d.ts.map +1 -1
- package/dist/stack/stack.test.js +2 -2
- package/dist/stack/stack.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dotdir.test.js","sourceRoot":"","sources":["../../src/runtime/dotdir.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7D,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;IACtB,IAAI,GAAG,GAAG,EAAE,CAAC;IAEb,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,GAAG;YAAE,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;QACxD,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACjC,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,kBAAkB,CAAC,EAAE,WAAW,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAC7C,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { LoadedProfile } from "../profile/profile.js";
|
|
2
|
+
export declare const GLOBAL_REGISTRY_VERSION = 1;
|
|
3
|
+
export interface GlobalSessionEntry {
|
|
4
|
+
/** Stable id — workspace scope hash. */
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
profilePath: string;
|
|
8
|
+
workspace: string;
|
|
9
|
+
workspaceId: string;
|
|
10
|
+
sessionName: string;
|
|
11
|
+
daemonPort: number;
|
|
12
|
+
lastSeen: string;
|
|
13
|
+
}
|
|
14
|
+
export interface GlobalRegistry {
|
|
15
|
+
version: number;
|
|
16
|
+
sessions: GlobalSessionEntry[];
|
|
17
|
+
}
|
|
18
|
+
export declare function globalConfigDir(): string;
|
|
19
|
+
export declare function globalRegistryPath(): string;
|
|
20
|
+
export declare function readGlobalRegistry(): GlobalRegistry;
|
|
21
|
+
/** Project `.sm/` profiles only — not bundled minimal fallback. */
|
|
22
|
+
export declare function isProjectProfilePath(profilePath: string): boolean;
|
|
23
|
+
export declare function sessionLabel(loaded: LoadedProfile): string;
|
|
24
|
+
export declare function entryFromLoaded(loaded: LoadedProfile): GlobalSessionEntry;
|
|
25
|
+
export declare function upsertGlobalSession(loaded: LoadedProfile): Promise<GlobalSessionEntry | null>;
|
|
26
|
+
export declare function forgetGlobalSession(idOrPath: string): Promise<boolean>;
|
|
27
|
+
export declare function findGlobalSession(reg: GlobalRegistry, idOrPath: string): GlobalSessionEntry | undefined;
|
|
28
|
+
//# sourceMappingURL=global-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-registry.d.ts","sourceRoot":"","sources":["../../src/runtime/global-registry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAI3D,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED,wBAAgB,eAAe,IAAI,MAAM,CAIxC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAMD,wBAAgB,kBAAkB,IAAI,cAAc,CAUnD;AA6BD,mEAAmE;AACnE,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAGjE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAE1D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,kBAAkB,CAYzE;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAgBpC;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkB5E;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,MAAM,GACf,kBAAkB,GAAG,SAAS,CAWhC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import lockfile from "proper-lockfile";
|
|
5
|
+
import { profilePaths } from "../profile/profile.js";
|
|
6
|
+
import { SM_DIR } from "./dotdir.js";
|
|
7
|
+
export const GLOBAL_REGISTRY_VERSION = 1;
|
|
8
|
+
export function globalConfigDir() {
|
|
9
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
10
|
+
const base = xdg && xdg.length > 0 ? xdg : path.join(os.homedir(), ".config");
|
|
11
|
+
return path.join(base, "seatmesh");
|
|
12
|
+
}
|
|
13
|
+
export function globalRegistryPath() {
|
|
14
|
+
return path.join(globalConfigDir(), "sessions.json");
|
|
15
|
+
}
|
|
16
|
+
function emptyRegistry() {
|
|
17
|
+
return { version: GLOBAL_REGISTRY_VERSION, sessions: [] };
|
|
18
|
+
}
|
|
19
|
+
export function readGlobalRegistry() {
|
|
20
|
+
const file = globalRegistryPath();
|
|
21
|
+
if (!fs.existsSync(file))
|
|
22
|
+
return emptyRegistry();
|
|
23
|
+
try {
|
|
24
|
+
const raw = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
25
|
+
if (!raw || !Array.isArray(raw.sessions))
|
|
26
|
+
return emptyRegistry();
|
|
27
|
+
return { version: GLOBAL_REGISTRY_VERSION, sessions: raw.sessions };
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return emptyRegistry();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function withRegistryLock(fn) {
|
|
34
|
+
const file = globalRegistryPath();
|
|
35
|
+
fs.mkdirSync(globalConfigDir(), { recursive: true });
|
|
36
|
+
if (!fs.existsSync(file)) {
|
|
37
|
+
fs.writeFileSync(file, `${JSON.stringify(emptyRegistry(), null, 2)}\n`);
|
|
38
|
+
}
|
|
39
|
+
let release;
|
|
40
|
+
try {
|
|
41
|
+
release = await lockfile.lock(file, { retries: { retries: 5, minTimeout: 20 } });
|
|
42
|
+
return await fn();
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
if (release)
|
|
46
|
+
await release();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function writeGlobalRegistrySync(reg) {
|
|
50
|
+
const file = globalRegistryPath();
|
|
51
|
+
fs.mkdirSync(globalConfigDir(), { recursive: true });
|
|
52
|
+
const sorted = {
|
|
53
|
+
...reg,
|
|
54
|
+
sessions: [...reg.sessions].sort((a, b) => new Date(b.lastSeen).getTime() - new Date(a.lastSeen).getTime()),
|
|
55
|
+
};
|
|
56
|
+
fs.writeFileSync(file, `${JSON.stringify(sorted, null, 2)}\n`);
|
|
57
|
+
}
|
|
58
|
+
/** Project `.sm/` profiles only — not bundled minimal fallback. */
|
|
59
|
+
export function isProjectProfilePath(profilePath) {
|
|
60
|
+
const norm = profilePath.split(path.sep).join("/");
|
|
61
|
+
return norm.includes(`/${SM_DIR}/`) || norm.endsWith(`/${SM_DIR}/mesh.config.yaml`);
|
|
62
|
+
}
|
|
63
|
+
export function sessionLabel(loaded) {
|
|
64
|
+
return loaded.profile.name || path.basename(loaded.workspace);
|
|
65
|
+
}
|
|
66
|
+
export function entryFromLoaded(loaded) {
|
|
67
|
+
const paths = profilePaths(loaded);
|
|
68
|
+
return {
|
|
69
|
+
id: loaded.workspaceId,
|
|
70
|
+
label: sessionLabel(loaded),
|
|
71
|
+
profilePath: loaded.profilePath,
|
|
72
|
+
workspace: loaded.workspace,
|
|
73
|
+
workspaceId: loaded.workspaceId,
|
|
74
|
+
sessionName: loaded.sessionName,
|
|
75
|
+
daemonPort: paths.daemonPort,
|
|
76
|
+
lastSeen: new Date().toISOString(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export async function upsertGlobalSession(loaded) {
|
|
80
|
+
if (!isProjectProfilePath(loaded.profilePath))
|
|
81
|
+
return null;
|
|
82
|
+
const entry = entryFromLoaded(loaded);
|
|
83
|
+
await withRegistryLock(() => {
|
|
84
|
+
const reg = readGlobalRegistry();
|
|
85
|
+
const idx = reg.sessions.findIndex((s) => s.id === entry.id || s.profilePath === entry.profilePath);
|
|
86
|
+
if (idx >= 0) {
|
|
87
|
+
reg.sessions[idx] = { ...reg.sessions[idx], ...entry };
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
reg.sessions.push(entry);
|
|
91
|
+
}
|
|
92
|
+
writeGlobalRegistrySync(reg);
|
|
93
|
+
});
|
|
94
|
+
return entry;
|
|
95
|
+
}
|
|
96
|
+
export async function forgetGlobalSession(idOrPath) {
|
|
97
|
+
let removed = false;
|
|
98
|
+
await withRegistryLock(() => {
|
|
99
|
+
const reg = readGlobalRegistry();
|
|
100
|
+
const key = idOrPath.trim();
|
|
101
|
+
const next = reg.sessions.filter((s) => {
|
|
102
|
+
const hit = s.id === key ||
|
|
103
|
+
s.profilePath === key ||
|
|
104
|
+
path.resolve(s.profilePath) === path.resolve(key) ||
|
|
105
|
+
s.workspace === key ||
|
|
106
|
+
path.resolve(s.workspace) === path.resolve(key);
|
|
107
|
+
if (hit)
|
|
108
|
+
removed = true;
|
|
109
|
+
return !hit;
|
|
110
|
+
});
|
|
111
|
+
writeGlobalRegistrySync({ ...reg, sessions: next });
|
|
112
|
+
});
|
|
113
|
+
return removed;
|
|
114
|
+
}
|
|
115
|
+
export function findGlobalSession(reg, idOrPath) {
|
|
116
|
+
const key = idOrPath.trim();
|
|
117
|
+
return reg.sessions.find((s) => s.id === key ||
|
|
118
|
+
s.profilePath === key ||
|
|
119
|
+
path.resolve(s.profilePath) === path.resolve(key) ||
|
|
120
|
+
s.sessionName === key ||
|
|
121
|
+
s.workspace === key ||
|
|
122
|
+
path.resolve(s.workspace) === path.resolve(key));
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=global-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-registry.js","sourceRoot":"","sources":["../../src/runtime/global-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MeshProfile } from "../schema/profile.js";
|
|
2
|
+
import type { MeshAgents, SavedMinisLayout } from "../schema/agents.js";
|
|
3
|
+
/** Effective minis layout: saved mesh-agents.json wins over profile yaml defaults. */
|
|
4
|
+
export declare function effectiveMinisLayout(profile: MeshProfile, saved?: SavedMinisLayout | null): SavedMinisLayout;
|
|
5
|
+
/** Merge saved mesh-agents layout into a loaded profile (session.miniMax synced). */
|
|
6
|
+
export declare function mergeMeshAgentsIntoProfile(profile: MeshProfile, mesh: Pick<MeshAgents, "layout"> | null): MeshProfile;
|
|
7
|
+
//# sourceMappingURL=mesh-state-merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh-state-merge.d.ts","sourceRoot":"","sources":["../../src/runtime/mesh-state-merge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAExE,sFAAsF;AACtF,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,WAAW,EACpB,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAC9B,gBAAgB,CAiBlB;AAED,qFAAqF;AACrF,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,IAAI,GACtC,WAAW,CA8Bb"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Effective minis layout: saved mesh-agents.json wins over profile yaml defaults. */
|
|
2
|
+
export function effectiveMinisLayout(profile, saved) {
|
|
3
|
+
const base = profile.layout?.minis;
|
|
4
|
+
if (!base) {
|
|
5
|
+
throw new Error("profile missing layout.minis");
|
|
6
|
+
}
|
|
7
|
+
if (!saved) {
|
|
8
|
+
return {
|
|
9
|
+
grid: base.grid,
|
|
10
|
+
max: base.max,
|
|
11
|
+
leads: Array.isArray(base.leads) ? base.leads : [1, 2],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
grid: saved.grid,
|
|
16
|
+
max: saved.max,
|
|
17
|
+
leads: saved.leads,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Merge saved mesh-agents layout into a loaded profile (session.miniMax synced). */
|
|
21
|
+
export function mergeMeshAgentsIntoProfile(profile, mesh) {
|
|
22
|
+
const saved = mesh?.layout;
|
|
23
|
+
if (!saved || !profile.layout)
|
|
24
|
+
return profile;
|
|
25
|
+
const minisSaved = saved.minis;
|
|
26
|
+
const minis = minisSaved
|
|
27
|
+
? { ...profile.layout.minis, ...minisSaved }
|
|
28
|
+
: profile.layout.minis;
|
|
29
|
+
const workers = saved.workers
|
|
30
|
+
? { ...profile.layout.workers, ...saved.workers }
|
|
31
|
+
: profile.layout.workers;
|
|
32
|
+
const nvim = saved.nvim ? { ...profile.layout.nvim, ...saved.nvim } : profile.layout.nvim;
|
|
33
|
+
const base = saved.base
|
|
34
|
+
? { ...profile.layout.base, ...saved.base }
|
|
35
|
+
: profile.layout.base;
|
|
36
|
+
return {
|
|
37
|
+
...profile,
|
|
38
|
+
layout: {
|
|
39
|
+
...profile.layout,
|
|
40
|
+
base,
|
|
41
|
+
nvim,
|
|
42
|
+
workers,
|
|
43
|
+
minis,
|
|
44
|
+
},
|
|
45
|
+
session: { ...profile.session, miniMax: minis.max },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=mesh-state-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh-state-merge.js","sourceRoot":"","sources":["../../src/runtime/mesh-state-merge.ts"],"names":[],"mappings":"AAGA,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAClC,OAAoB,EACpB,KAA+B;IAE/B,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC;IACnC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACvD,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,CAAC;AACJ,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,0BAA0B,CACxC,OAAoB,EACpB,IAAuC;IAEvC,MAAM,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC;IAE9C,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC;IAC/B,MAAM,KAAK,GAAG,UAAU;QACtB,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,UAAU,EAAE;QAC5C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IAEzB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO;QAC3B,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE;QACjD,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;IAE3B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;IAE1F,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI;QACrB,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE;QAC3C,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;IAExB,OAAO;QACL,GAAG,OAAO;QACV,MAAM,EAAE;YACN,GAAG,OAAO,CAAC,MAAM;YACjB,IAAI;YACJ,IAAI;YACJ,OAAO;YACP,KAAK;SACN;QACD,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE;KACpD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh-state-merge.test.d.ts","sourceRoot":"","sources":["../../src/runtime/mesh-state-merge.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { mergeMeshAgentsIntoProfile } from "./mesh-state-merge.js";
|
|
3
|
+
const baseProfile = {
|
|
4
|
+
name: "test",
|
|
5
|
+
workspace: ".",
|
|
6
|
+
session: { name: "mesh", workerCount: 6, miniMax: 8 },
|
|
7
|
+
layout: {
|
|
8
|
+
nvim: { window: "nvim" },
|
|
9
|
+
base: { window: "base", columns: ["manager", "secretary"] },
|
|
10
|
+
workers: { window: "workers", grid: "3x2", slots: 6 },
|
|
11
|
+
minis: { window: "minis", grid: "4x2", max: 8, leads: [1, 2] },
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
describe("mergeMeshAgentsIntoProfile", () => {
|
|
15
|
+
it("overrides yaml minis layout when mesh-agents.json has layout.minis", () => {
|
|
16
|
+
const merged = mergeMeshAgentsIntoProfile(baseProfile, {
|
|
17
|
+
layout: { minis: { grid: "2x2", max: 4, leads: [1] } },
|
|
18
|
+
});
|
|
19
|
+
expect(merged.layout?.minis.grid).toBe("2x2");
|
|
20
|
+
expect(merged.layout?.minis.max).toBe(4);
|
|
21
|
+
expect(merged.layout?.minis.leads).toEqual([1]);
|
|
22
|
+
expect(merged.session.miniMax).toBe(4);
|
|
23
|
+
});
|
|
24
|
+
it("returns profile unchanged when no saved layout", () => {
|
|
25
|
+
const merged = mergeMeshAgentsIntoProfile(baseProfile, null);
|
|
26
|
+
expect(merged.layout?.minis.grid).toBe("4x2");
|
|
27
|
+
expect(merged.session.miniMax).toBe(8);
|
|
28
|
+
});
|
|
29
|
+
it("merges layout.base.coordSync from saved layout", () => {
|
|
30
|
+
const merged = mergeMeshAgentsIntoProfile(baseProfile, {
|
|
31
|
+
layout: { base: { coordSync: { reload: true, attach: false } } },
|
|
32
|
+
});
|
|
33
|
+
expect(merged.layout?.base.coordSync).toEqual({ reload: true, attach: false });
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=mesh-state-merge.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh-state-merge.test.js","sourceRoot":"","sources":["../../src/runtime/mesh-state-merge.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAGnE,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;IACrD,MAAM,EAAE;QACN,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;QACxB,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE;QAC3D,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAc,EAAE,KAAK,EAAE,CAAC,EAAE;QAC9D,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;KAC/D;CACwB,CAAC;AAE5B,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,MAAM,GAAG,0BAA0B,CAAC,WAAW,EAAE;YACrD,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;SACvD,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,MAAM,GAAG,0BAA0B,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,MAAM,GAAG,0BAA0B,CAAC,WAAW,EAAE;YACrD,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;SACjE,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface RoleIndexEntry {
|
|
2
|
+
path: string;
|
|
3
|
+
note?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface RolePolicy {
|
|
6
|
+
id: string;
|
|
7
|
+
text?: string;
|
|
8
|
+
path?: string;
|
|
9
|
+
rule?: string;
|
|
10
|
+
cmd?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RoleAllowDeny {
|
|
13
|
+
allow?: string[];
|
|
14
|
+
deny?: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface RoleIndex {
|
|
17
|
+
kind: string;
|
|
18
|
+
/** Parent role file name (no .yaml) — merged before this file. */
|
|
19
|
+
extends?: string;
|
|
20
|
+
/** Printed first on whoami (patterns.md / ONE-PATH). */
|
|
21
|
+
banner?: string[];
|
|
22
|
+
read_first?: RoleIndexEntry[];
|
|
23
|
+
policies?: RolePolicy[];
|
|
24
|
+
files?: string[];
|
|
25
|
+
inject?: string[];
|
|
26
|
+
vars?: Record<string, string>;
|
|
27
|
+
/** Comms + builtin command guards (AGENT-FUNC-GUARDS.md / ROLE-YAML.md). */
|
|
28
|
+
guards?: RoleAllowDeny;
|
|
29
|
+
/** Attached-external (seatmesh func) allow/deny per role. */
|
|
30
|
+
funcs?: RoleAllowDeny;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* True when `id` is usable for this merged role: explicit deny always wins;
|
|
34
|
+
* otherwise an explicit allow list restricts to just that list; with neither,
|
|
35
|
+
* default to allowed (profile-level `external.default` is the real gate for funcs).
|
|
36
|
+
*/
|
|
37
|
+
export declare function roleAllows(rule: RoleAllowDeny | undefined, id: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Pane column id -> merged role index.
|
|
40
|
+
* 1. Seat kind file (`manager.yaml`) with optional `extends:` chain (+ implicit common).
|
|
41
|
+
* 2. Optional column overlay `.sm/roles/columns/<columnId>.yaml` with `extends: manager` (etc.).
|
|
42
|
+
* Never load `roles/<columnId>.yaml` as a kind — use `columns/<columnId>.yaml`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function loadRoleIndex(rolesDir: string, paneRoleId: string): RoleIndex;
|
|
45
|
+
export declare function renderRoleIndex(index: RoleIndex, vars?: Record<string, string>, opts?: {
|
|
46
|
+
skipBanner?: boolean;
|
|
47
|
+
skipFiles?: boolean;
|
|
48
|
+
}): string;
|
|
49
|
+
export declare function validateRoleIndex(index: RoleIndex, workspace: string): {
|
|
50
|
+
ok: boolean;
|
|
51
|
+
missing: string[];
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=role-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-index.d.ts","sourceRoot":"","sources":["../../src/runtime/role-index.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAuCD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAK/E;AA8DD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,CAa7E;AAMD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,EAChB,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACjC,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,GACvD,MAAM,CA0CR;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,MAAM,GAChB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAcpC"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
import { seatKindFromId } from "../schema/seat-kind.js";
|
|
5
|
+
/** Deny accumulates from base; child role's own allow list wins over base's allow. */
|
|
6
|
+
function mergeAllowDeny(base, role) {
|
|
7
|
+
if (!base && !role)
|
|
8
|
+
return undefined;
|
|
9
|
+
const deny = [...new Set([...(base?.deny ?? []), ...(role?.deny ?? [])])];
|
|
10
|
+
const allow = role?.allow ?? base?.allow;
|
|
11
|
+
return { ...(allow ? { allow } : {}), ...(deny.length ? { deny } : {}) };
|
|
12
|
+
}
|
|
13
|
+
function mergeRoleIndex(base, role) {
|
|
14
|
+
const readFirst = [...(base.read_first ?? []), ...(role.read_first ?? [])];
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
const dedupedReadFirst = readFirst.filter((item) => {
|
|
17
|
+
if (seen.has(item.path))
|
|
18
|
+
return false;
|
|
19
|
+
seen.add(item.path);
|
|
20
|
+
return true;
|
|
21
|
+
});
|
|
22
|
+
const policyById = new Map();
|
|
23
|
+
for (const p of [...(base.policies ?? []), ...(role.policies ?? [])]) {
|
|
24
|
+
policyById.set(p.id, p);
|
|
25
|
+
}
|
|
26
|
+
const policies = [...policyById.values()];
|
|
27
|
+
return {
|
|
28
|
+
...role,
|
|
29
|
+
kind: role.kind ?? base.kind ?? "worker",
|
|
30
|
+
banner: [...(base.banner ?? []), ...(role.banner ?? [])],
|
|
31
|
+
read_first: dedupedReadFirst,
|
|
32
|
+
policies,
|
|
33
|
+
files: [...new Set([...(base.files ?? []), ...(role.files ?? [])])],
|
|
34
|
+
inject: [...(base.inject ?? []), ...(role.inject ?? [])],
|
|
35
|
+
vars: { ...(base.vars ?? {}), ...(role.vars ?? {}) },
|
|
36
|
+
guards: mergeAllowDeny(base.guards, role.guards),
|
|
37
|
+
funcs: mergeAllowDeny(base.funcs, role.funcs),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* True when `id` is usable for this merged role: explicit deny always wins;
|
|
42
|
+
* otherwise an explicit allow list restricts to just that list; with neither,
|
|
43
|
+
* default to allowed (profile-level `external.default` is the real gate for funcs).
|
|
44
|
+
*/
|
|
45
|
+
export function roleAllows(rule, id) {
|
|
46
|
+
if (!rule)
|
|
47
|
+
return true;
|
|
48
|
+
if (rule.deny?.includes(id))
|
|
49
|
+
return false;
|
|
50
|
+
if (rule.allow?.length)
|
|
51
|
+
return rule.allow.includes(id);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
/** Deprecated alias: prefer "manager" not "master" for the coordinator pane. */
|
|
55
|
+
function normalizeRoleKind(kind) {
|
|
56
|
+
return kind === "master" ? "manager" : kind;
|
|
57
|
+
}
|
|
58
|
+
function roleYamlPath(rolesDir, name) {
|
|
59
|
+
return path.join(rolesDir, `${name}.yaml`);
|
|
60
|
+
}
|
|
61
|
+
function columnOverlayPath(rolesDir, columnId) {
|
|
62
|
+
return path.join(rolesDir, "columns", `${columnId}.yaml`);
|
|
63
|
+
}
|
|
64
|
+
/** Load one yaml file and merge its `extends` chain (child wins on conflicts). */
|
|
65
|
+
function loadRoleFileChain(rolesDir, name, filePath, visiting) {
|
|
66
|
+
const key = `${filePath}`;
|
|
67
|
+
if (visiting.has(key)) {
|
|
68
|
+
throw new Error(`role extends cycle at ${filePath}`);
|
|
69
|
+
}
|
|
70
|
+
visiting.add(key);
|
|
71
|
+
if (!fs.existsSync(filePath)) {
|
|
72
|
+
throw new Error(`role index missing: ${filePath}`);
|
|
73
|
+
}
|
|
74
|
+
const raw = YAML.parse(fs.readFileSync(filePath, "utf8"));
|
|
75
|
+
const extendsName = raw.extends?.trim();
|
|
76
|
+
let merged = { kind: raw.kind ?? name };
|
|
77
|
+
if (extendsName) {
|
|
78
|
+
const parentNorm = normalizeRoleKind(extendsName);
|
|
79
|
+
const parentPath = roleYamlPath(rolesDir, parentNorm);
|
|
80
|
+
const parent = loadRoleFileChain(rolesDir, parentNorm, parentPath, visiting);
|
|
81
|
+
merged = mergeRoleIndex(parent, { ...merged, ...stripExtends(raw), kind: raw.kind ?? name });
|
|
82
|
+
}
|
|
83
|
+
else if (name === "common") {
|
|
84
|
+
merged = mergeRoleIndex({}, { ...merged, ...stripExtends(raw), kind: "common" });
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const commonPath = roleYamlPath(rolesDir, "common");
|
|
88
|
+
if (fs.existsSync(commonPath)) {
|
|
89
|
+
const common = loadRoleFileChain(rolesDir, "common", commonPath, visiting);
|
|
90
|
+
merged = mergeRoleIndex(common, { ...merged, ...stripExtends(raw), kind: raw.kind ?? name });
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
merged = mergeRoleIndex({}, { ...merged, ...stripExtends(raw), kind: raw.kind ?? name });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
visiting.delete(key);
|
|
97
|
+
return merged;
|
|
98
|
+
}
|
|
99
|
+
function stripExtends(raw) {
|
|
100
|
+
const { extends: _e, ...rest } = raw;
|
|
101
|
+
return rest;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Pane column id -> merged role index.
|
|
105
|
+
* 1. Seat kind file (`manager.yaml`) with optional `extends:` chain (+ implicit common).
|
|
106
|
+
* 2. Optional column overlay `.sm/roles/columns/<columnId>.yaml` with `extends: manager` (etc.).
|
|
107
|
+
* Never load `roles/<columnId>.yaml` as a kind — use `columns/<columnId>.yaml`.
|
|
108
|
+
*/
|
|
109
|
+
export function loadRoleIndex(rolesDir, paneRoleId) {
|
|
110
|
+
const columnId = normalizeRoleKind(paneRoleId);
|
|
111
|
+
const seatKind = seatKindFromId(columnId);
|
|
112
|
+
const overlayPath = columnOverlayPath(rolesDir, columnId);
|
|
113
|
+
if (columnId !== seatKind && fs.existsSync(overlayPath)) {
|
|
114
|
+
const merged = loadRoleFileChain(rolesDir, columnId, overlayPath, new Set());
|
|
115
|
+
merged.kind = seatKind;
|
|
116
|
+
return merged;
|
|
117
|
+
}
|
|
118
|
+
const kindPath = roleYamlPath(rolesDir, seatKind);
|
|
119
|
+
const merged = loadRoleFileChain(rolesDir, seatKind, kindPath, new Set());
|
|
120
|
+
merged.kind = seatKind;
|
|
121
|
+
return merged;
|
|
122
|
+
}
|
|
123
|
+
function substituteVars(text, vars) {
|
|
124
|
+
return text.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? "");
|
|
125
|
+
}
|
|
126
|
+
export function renderRoleIndex(index, vars = {}, opts = {}) {
|
|
127
|
+
const lines = [];
|
|
128
|
+
if (!opts.skipBanner) {
|
|
129
|
+
for (const line of index.banner ?? []) {
|
|
130
|
+
lines.push(substituteVars(line, vars));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
for (const item of index.read_first ?? []) {
|
|
134
|
+
const p = substituteVars(item.path, vars);
|
|
135
|
+
const note = item.note ? substituteVars(item.note, vars) : "";
|
|
136
|
+
lines.push(`file=${p}${note ? ` | ${note}` : ""}`);
|
|
137
|
+
}
|
|
138
|
+
for (const pol of index.policies ?? []) {
|
|
139
|
+
if (pol.path) {
|
|
140
|
+
lines.push(`policy_${pol.id}=${substituteVars(pol.path, vars)}${pol.rule ? ` | ${substituteVars(pol.rule, vars)}` : ""}`);
|
|
141
|
+
}
|
|
142
|
+
else if (pol.text) {
|
|
143
|
+
lines.push(`policy_${pol.id}=${substituteVars(pol.text, vars)}`);
|
|
144
|
+
}
|
|
145
|
+
else if (pol.cmd) {
|
|
146
|
+
lines.push(`policy_${pol.id}=${substituteVars(pol.cmd, vars)}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!opts.skipFiles) {
|
|
150
|
+
for (const f of index.files ?? []) {
|
|
151
|
+
lines.push(`file=${substituteVars(f, vars)}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
for (const [k, v] of Object.entries(index.vars ?? {})) {
|
|
155
|
+
lines.push(`${k}=${substituteVars(v, vars)}`);
|
|
156
|
+
}
|
|
157
|
+
for (const line of index.inject ?? []) {
|
|
158
|
+
lines.push(`inject=${substituteVars(line, vars)}`);
|
|
159
|
+
}
|
|
160
|
+
return lines.join("\n");
|
|
161
|
+
}
|
|
162
|
+
export function validateRoleIndex(index, workspace) {
|
|
163
|
+
const missing = [];
|
|
164
|
+
const check = (rel) => {
|
|
165
|
+
const p = path.isAbsolute(rel) ? rel : path.resolve(workspace, rel);
|
|
166
|
+
if (!fs.existsSync(p))
|
|
167
|
+
missing.push(rel);
|
|
168
|
+
};
|
|
169
|
+
for (const item of index.read_first ?? [])
|
|
170
|
+
check(item.path);
|
|
171
|
+
for (const pol of index.policies ?? []) {
|
|
172
|
+
if (pol.path)
|
|
173
|
+
check(pol.path);
|
|
174
|
+
}
|
|
175
|
+
for (const f of index.files ?? [])
|
|
176
|
+
check(f);
|
|
177
|
+
return { ok: missing.length === 0, missing };
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=role-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-index.js","sourceRoot":"","sources":["../../src/runtime/role-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-index.test.d.ts","sourceRoot":"","sources":["../../src/runtime/role-index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { loadRoleIndex, roleAllows, validateRoleIndex } from "./role-index.js";
|
|
6
|
+
describe("role-index", () => {
|
|
7
|
+
it("merges common + role and validates paths", () => {
|
|
8
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "sm-role-"));
|
|
9
|
+
const rolesDir = path.join(root, "roles");
|
|
10
|
+
fs.mkdirSync(rolesDir, { recursive: true });
|
|
11
|
+
fs.writeFileSync(path.join(rolesDir, "common.yaml"), `banner:\n - "test=common"\nread_first:\n - path: docs/a.md\n note: shared\n`);
|
|
12
|
+
fs.writeFileSync(path.join(rolesDir, "worker.yaml"), `kind: worker\nfiles:\n - docs/b.md\npolicies:\n - id: p1\n path: docs/c.md\n`);
|
|
13
|
+
fs.mkdirSync(path.join(root, "docs"), { recursive: true });
|
|
14
|
+
for (const f of ["a.md", "b.md", "c.md"]) {
|
|
15
|
+
fs.writeFileSync(path.join(root, "docs", f), "# ok\n");
|
|
16
|
+
}
|
|
17
|
+
const index = loadRoleIndex(rolesDir, "worker");
|
|
18
|
+
expect(index.banner).toContain("test=common");
|
|
19
|
+
expect(index.read_first?.map((x) => x.path)).toContain("docs/a.md");
|
|
20
|
+
expect(index.files).toContain("docs/b.md");
|
|
21
|
+
const ok = validateRoleIndex(index, root);
|
|
22
|
+
expect(ok.ok).toBe(true);
|
|
23
|
+
expect(ok.missing).toEqual([]);
|
|
24
|
+
});
|
|
25
|
+
it("reports missing role-index paths", () => {
|
|
26
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "sm-role-"));
|
|
27
|
+
const rolesDir = path.join(root, "roles");
|
|
28
|
+
fs.mkdirSync(rolesDir, { recursive: true });
|
|
29
|
+
fs.writeFileSync(path.join(rolesDir, "manager.yaml"), `kind: manager\nread_first:\n - path: missing/playbook.md\n`);
|
|
30
|
+
const index = loadRoleIndex(rolesDir, "manager");
|
|
31
|
+
const result = validateRoleIndex(index, root);
|
|
32
|
+
expect(result.ok).toBe(false);
|
|
33
|
+
expect(result.missing).toEqual(["missing/playbook.md"]);
|
|
34
|
+
});
|
|
35
|
+
it("merges funcs/guards — common deny accumulates, role's own allow wins", () => {
|
|
36
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "sm-role-"));
|
|
37
|
+
const rolesDir = path.join(root, "roles");
|
|
38
|
+
fs.mkdirSync(rolesDir, { recursive: true });
|
|
39
|
+
fs.writeFileSync(path.join(rolesDir, "common.yaml"), `guards:\n deny: [merge, board.mutate]\nfuncs:\n allow: [dc-sh, notify]\n`);
|
|
40
|
+
fs.writeFileSync(path.join(rolesDir, "worker.yaml"), `kind: worker\nfuncs:\n allow: [dc-sh]\n deny: [docker-exec]\n`);
|
|
41
|
+
const index = loadRoleIndex(rolesDir, "worker");
|
|
42
|
+
// common's deny accumulates even though worker's own funcs has no deny for it
|
|
43
|
+
expect(index.guards?.deny).toEqual(["merge", "board.mutate"]);
|
|
44
|
+
// worker's own allow list wins over common's broader one
|
|
45
|
+
expect(index.funcs?.allow).toEqual(["dc-sh"]);
|
|
46
|
+
expect(index.funcs?.deny).toEqual(["docker-exec"]);
|
|
47
|
+
expect(roleAllows(index.funcs, "dc-sh")).toBe(true);
|
|
48
|
+
expect(roleAllows(index.funcs, "notify")).toBe(false); // not in worker's own allow list
|
|
49
|
+
expect(roleAllows(index.funcs, "docker-exec")).toBe(false); // denied
|
|
50
|
+
});
|
|
51
|
+
it("roleAllows defaults to true with no rule and true with an empty rule", () => {
|
|
52
|
+
expect(roleAllows(undefined, "anything")).toBe(true);
|
|
53
|
+
expect(roleAllows({}, "anything")).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
it("inherits manager via columns/manager-2.yaml extends (ignores roles/manager-2.yaml)", () => {
|
|
56
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "sm-role-"));
|
|
57
|
+
const rolesDir = path.join(root, "roles");
|
|
58
|
+
fs.mkdirSync(path.join(rolesDir, "columns"), { recursive: true });
|
|
59
|
+
fs.writeFileSync(path.join(rolesDir, "common.yaml"), `banner:\n - "from=common"\n`);
|
|
60
|
+
fs.writeFileSync(path.join(rolesDir, "manager.yaml"), `kind: manager\nextends: common\nbanner:\n - "from=manager"\n`);
|
|
61
|
+
fs.writeFileSync(path.join(rolesDir, "manager-2.yaml"), `kind: manager-2\nbanner:\n - "from=legacy-kind-file"\n`);
|
|
62
|
+
fs.writeFileSync(path.join(rolesDir, "columns", "manager-2.yaml"), `extends: manager\nbanner:\n - "from=column-overlay"\n`);
|
|
63
|
+
const index = loadRoleIndex(rolesDir, "manager-2");
|
|
64
|
+
expect(index.banner).toEqual(["from=common", "from=manager", "from=column-overlay"]);
|
|
65
|
+
expect(index.banner).not.toContain("from=legacy-kind-file");
|
|
66
|
+
});
|
|
67
|
+
it("extends chain merges policies by id (child wins)", () => {
|
|
68
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "sm-role-"));
|
|
69
|
+
const rolesDir = path.join(root, "roles");
|
|
70
|
+
fs.mkdirSync(rolesDir, { recursive: true });
|
|
71
|
+
fs.writeFileSync(path.join(rolesDir, "worker.yaml"), `kind: worker\npolicies:\n - id: p1\n text: base\n`);
|
|
72
|
+
fs.writeFileSync(path.join(rolesDir, "mini.yaml"), `kind: mini\nextends: worker\npolicies:\n - id: p1\n text: mini override\n`);
|
|
73
|
+
const index = loadRoleIndex(rolesDir, "mini-3");
|
|
74
|
+
expect(index.policies?.find((p) => p.id === "p1")?.text).toBe("mini override");
|
|
75
|
+
});
|
|
76
|
+
it("normalizes master alias to manager", () => {
|
|
77
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "sm-role-"));
|
|
78
|
+
const rolesDir = path.join(root, "roles");
|
|
79
|
+
fs.mkdirSync(rolesDir, { recursive: true });
|
|
80
|
+
fs.writeFileSync(path.join(rolesDir, "manager.yaml"), `kind: manager\n`);
|
|
81
|
+
const index = loadRoleIndex(rolesDir, "master");
|
|
82
|
+
expect(index.kind).toBe("manager");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=role-index.test.js.map
|