@evref-bl/plexus-core 0.1.0-alpha.0

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.
Files changed (73) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +164 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/config.d.ts +15 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +62 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/imageRescue.d.ts +136 -0
  10. package/dist/imageRescue.d.ts.map +1 -0
  11. package/dist/imageRescue.js +686 -0
  12. package/dist/imageRescue.js.map +1 -0
  13. package/dist/index.d.ts +16 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +16 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/pathStyle.d.ts +10 -0
  18. package/dist/pathStyle.d.ts.map +1 -0
  19. package/dist/pathStyle.js +33 -0
  20. package/dist/pathStyle.js.map +1 -0
  21. package/dist/pharoLauncherMcpClient.d.ts +12 -0
  22. package/dist/pharoLauncherMcpClient.d.ts.map +1 -0
  23. package/dist/pharoLauncherMcpClient.js +74 -0
  24. package/dist/pharoLauncherMcpClient.js.map +1 -0
  25. package/dist/pharoMcpHealth.d.ts +22 -0
  26. package/dist/pharoMcpHealth.d.ts.map +1 -0
  27. package/dist/pharoMcpHealth.js +80 -0
  28. package/dist/pharoMcpHealth.js.map +1 -0
  29. package/dist/projectClose.d.ts +28 -0
  30. package/dist/projectClose.d.ts.map +1 -0
  31. package/dist/projectClose.js +93 -0
  32. package/dist/projectClose.js.map +1 -0
  33. package/dist/projectConfig.d.ts +44 -0
  34. package/dist/projectConfig.d.ts.map +1 -0
  35. package/dist/projectConfig.js +208 -0
  36. package/dist/projectConfig.js.map +1 -0
  37. package/dist/projectLifecycle.d.ts +115 -0
  38. package/dist/projectLifecycle.d.ts.map +1 -0
  39. package/dist/projectLifecycle.js +495 -0
  40. package/dist/projectLifecycle.js.map +1 -0
  41. package/dist/projectOpen.d.ts +49 -0
  42. package/dist/projectOpen.d.ts.map +1 -0
  43. package/dist/projectOpen.js +218 -0
  44. package/dist/projectOpen.js.map +1 -0
  45. package/dist/projectStartupScript.d.ts +56 -0
  46. package/dist/projectStartupScript.d.ts.map +1 -0
  47. package/dist/projectStartupScript.js +150 -0
  48. package/dist/projectStartupScript.js.map +1 -0
  49. package/dist/projectState.d.ts +128 -0
  50. package/dist/projectState.d.ts.map +1 -0
  51. package/dist/projectState.js +192 -0
  52. package/dist/projectState.js.map +1 -0
  53. package/dist/scopedPharoLauncherServer.d.ts +87 -0
  54. package/dist/scopedPharoLauncherServer.d.ts.map +1 -0
  55. package/dist/scopedPharoLauncherServer.js +186 -0
  56. package/dist/scopedPharoLauncherServer.js.map +1 -0
  57. package/dist/scopedProjectContext.d.ts +93 -0
  58. package/dist/scopedProjectContext.d.ts.map +1 -0
  59. package/dist/scopedProjectContext.js +181 -0
  60. package/dist/scopedProjectContext.js.map +1 -0
  61. package/dist/server.d.ts +42 -0
  62. package/dist/server.d.ts.map +1 -0
  63. package/dist/server.js +133 -0
  64. package/dist/server.js.map +1 -0
  65. package/dist/target.d.ts +19 -0
  66. package/dist/target.d.ts.map +1 -0
  67. package/dist/target.js +2 -0
  68. package/dist/target.js.map +1 -0
  69. package/dist/workspaceMcpConfig.d.ts +42 -0
  70. package/dist/workspaceMcpConfig.d.ts.map +1 -0
  71. package/dist/workspaceMcpConfig.js +79 -0
  72. package/dist/workspaceMcpConfig.js.map +1 -0
  73. package/package.json +37 -0
@@ -0,0 +1,192 @@
1
+ import fs from "node:fs";
2
+ import { basenamePathLike, dirnamePathLike, joinPathLike, } from "./pathStyle.js";
3
+ export const plexusStateDirectoryName = ".plexus";
4
+ export const plexusProjectsStateDirectoryName = "projects";
5
+ export const plexusWorkspacesStateDirectoryName = "workspaces";
6
+ export const projectStateFileName = "state.json";
7
+ export const defaultWorkspaceIdValue = "default";
8
+ export const defaultProjectPortRange = {
9
+ start: 7_100,
10
+ end: 7_199,
11
+ };
12
+ export class PortAllocationError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = "PortAllocationError";
16
+ }
17
+ }
18
+ export class ProjectStateError extends Error {
19
+ constructor(message) {
20
+ super(message);
21
+ this.name = "ProjectStateError";
22
+ }
23
+ }
24
+ export function defaultPlexusStateRoot(projectRoot) {
25
+ return joinPathLike(projectRoot, plexusStateDirectoryName);
26
+ }
27
+ export function sanitizeRuntimeId(value) {
28
+ const sanitized = value.trim().replace(/[^A-Za-z0-9._-]+/g, "-");
29
+ return sanitized.replace(/^-+|-+$/g, "") || defaultWorkspaceIdValue;
30
+ }
31
+ export function defaultWorkspaceId(projectRoot) {
32
+ return sanitizeRuntimeId(basenamePathLike(projectRoot));
33
+ }
34
+ export function defaultTargetId(projectId, workspaceId) {
35
+ return `${projectId}--${workspaceId}`;
36
+ }
37
+ export function projectWorkspacesStateDirectoryPath(options) {
38
+ const stateRoot = options.stateRoot ?? defaultPlexusStateRoot(options.projectRoot);
39
+ return joinPathLike(stateRoot, plexusProjectsStateDirectoryName, options.projectId, plexusWorkspacesStateDirectoryName);
40
+ }
41
+ export function projectStateDirectoryPath(options) {
42
+ return joinPathLike(projectWorkspacesStateDirectoryPath(options), options.workspaceId
43
+ ? sanitizeRuntimeId(options.workspaceId)
44
+ : defaultWorkspaceId(options.projectRoot));
45
+ }
46
+ export function projectStatePath(options) {
47
+ return joinPathLike(projectStateDirectoryPath(options), projectStateFileName);
48
+ }
49
+ export function projectStatePathForConfig(options) {
50
+ return projectStatePath({
51
+ projectRoot: options.projectRoot,
52
+ projectId: options.config.kanban.projectId,
53
+ workspaceId: options.workspaceId,
54
+ stateRoot: options.stateRoot,
55
+ });
56
+ }
57
+ function validatePortRange(range) {
58
+ if (!Number.isInteger(range.start) ||
59
+ !Number.isInteger(range.end) ||
60
+ range.start < 1 ||
61
+ range.end > 65_535 ||
62
+ range.start > range.end) {
63
+ throw new PortAllocationError("Port range must use integer ports between 1 and 65535 with start <= end");
64
+ }
65
+ }
66
+ function nextAvailablePort(range, unavailablePorts) {
67
+ for (let port = range.start; port <= range.end; port += 1) {
68
+ if (!unavailablePorts.has(port)) {
69
+ return port;
70
+ }
71
+ }
72
+ throw new PortAllocationError(`No available port in range ${range.start}-${range.end}`);
73
+ }
74
+ function previousImagePort(previousState, imageId) {
75
+ return previousState?.images.find((image) => image.id === imageId)
76
+ ?.assignedPort;
77
+ }
78
+ function normalizeCreateProjectStateOptions(optionsOrUpdatedAt) {
79
+ if (typeof optionsOrUpdatedAt === "string") {
80
+ const workspaceId = defaultWorkspaceIdValue;
81
+ return {
82
+ updatedAt: optionsOrUpdatedAt,
83
+ previousState: undefined,
84
+ portRange: defaultProjectPortRange,
85
+ reservedPorts: new Set(),
86
+ workspaceId,
87
+ targetId: undefined,
88
+ };
89
+ }
90
+ const workspaceId = sanitizeRuntimeId(optionsOrUpdatedAt?.workspaceId ??
91
+ optionsOrUpdatedAt?.previousState?.workspaceId ??
92
+ defaultWorkspaceIdValue);
93
+ return {
94
+ updatedAt: optionsOrUpdatedAt?.updatedAt ?? new Date().toISOString(),
95
+ previousState: optionsOrUpdatedAt?.previousState,
96
+ portRange: optionsOrUpdatedAt?.portRange ?? defaultProjectPortRange,
97
+ reservedPorts: new Set(optionsOrUpdatedAt?.reservedPorts ?? []),
98
+ workspaceId,
99
+ targetId: optionsOrUpdatedAt?.targetId ?? optionsOrUpdatedAt?.previousState?.targetId,
100
+ };
101
+ }
102
+ export function loadProjectState(filePath) {
103
+ if (!fs.existsSync(filePath)) {
104
+ return undefined;
105
+ }
106
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
107
+ }
108
+ export function saveProjectState(filePath, state) {
109
+ fs.mkdirSync(dirnamePathLike(filePath), { recursive: true });
110
+ fs.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}\n`, "utf8");
111
+ }
112
+ export function collectReservedProjectPorts(options) {
113
+ const workspacesDir = projectWorkspacesStateDirectoryPath(options);
114
+ if (!fs.existsSync(workspacesDir)) {
115
+ return [];
116
+ }
117
+ const excludedWorkspaceId = options.excludeWorkspaceId
118
+ ? sanitizeRuntimeId(options.excludeWorkspaceId)
119
+ : undefined;
120
+ const ports = new Set();
121
+ for (const entry of fs.readdirSync(workspacesDir, { withFileTypes: true })) {
122
+ if (!entry.isDirectory() || entry.name === excludedWorkspaceId) {
123
+ continue;
124
+ }
125
+ const state = loadProjectState(joinPathLike(workspacesDir, entry.name, projectStateFileName));
126
+ for (const image of state?.images ?? []) {
127
+ if (image.status !== "stopped") {
128
+ ports.add(image.assignedPort);
129
+ }
130
+ }
131
+ }
132
+ return [...ports];
133
+ }
134
+ export function renderProjectImageName(template, context) {
135
+ return template.replace(/\{(projectId|projectName|workspaceId|targetId|imageId)\}/g, (_match, key) => context[key]);
136
+ }
137
+ export function createProjectState(config, optionsOrUpdatedAt) {
138
+ const options = normalizeCreateProjectStateOptions(optionsOrUpdatedAt);
139
+ validatePortRange(options.portRange);
140
+ const targetId = options.targetId ??
141
+ defaultTargetId(config.kanban.projectId, options.workspaceId);
142
+ const configuredPorts = new Set(config.images
143
+ .map((image) => image.mcp.port)
144
+ .filter((port) => port !== undefined));
145
+ const unavailablePorts = new Set([...options.reservedPorts, ...configuredPorts]);
146
+ const images = config.images.map((image) => {
147
+ const previousPort = previousImagePort(options.previousState, image.id);
148
+ let assignedPort = image.mcp.port;
149
+ if (assignedPort !== undefined && options.reservedPorts.has(assignedPort)) {
150
+ throw new PortAllocationError(`Configured port ${assignedPort} is already reserved by another workspace`);
151
+ }
152
+ if (assignedPort === undefined) {
153
+ if (previousPort !== undefined &&
154
+ !configuredPorts.has(previousPort) &&
155
+ !unavailablePorts.has(previousPort)) {
156
+ assignedPort = previousPort;
157
+ }
158
+ else {
159
+ assignedPort = nextAvailablePort(options.portRange, unavailablePorts);
160
+ }
161
+ }
162
+ unavailablePorts.add(assignedPort);
163
+ return {
164
+ id: image.id,
165
+ imageName: renderProjectImageName(image.imageName, {
166
+ projectId: config.kanban.projectId,
167
+ projectName: config.name,
168
+ workspaceId: options.workspaceId,
169
+ targetId,
170
+ imageId: image.id,
171
+ }),
172
+ assignedPort,
173
+ status: image.active ? "starting" : "stopped",
174
+ };
175
+ });
176
+ const imageNames = new Set();
177
+ for (const image of images) {
178
+ if (imageNames.has(image.imageName)) {
179
+ throw new ProjectStateError(`Rendered image names must be unique: ${image.imageName}`);
180
+ }
181
+ imageNames.add(image.imageName);
182
+ }
183
+ return {
184
+ projectId: config.kanban.projectId,
185
+ projectName: config.name,
186
+ workspaceId: options.workspaceId,
187
+ targetId,
188
+ updatedAt: options.updatedAt,
189
+ images,
190
+ };
191
+ }
192
+ //# sourceMappingURL=projectState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectState.js","sourceRoot":"","sources":["../src/projectState.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { type ProjectImageState } from "./projectState.js";
3
+ export interface ScopedPharoLauncherOptions {
4
+ projectRoot: string;
5
+ workspaceId?: string;
6
+ targetId?: string;
7
+ stateRoot?: string;
8
+ }
9
+ interface ResolvedScope {
10
+ projectRoot: string;
11
+ workspaceId: string;
12
+ targetId: string;
13
+ stateRoot?: string;
14
+ }
15
+ interface WorkspaceImageSummary {
16
+ imageId: string;
17
+ imageName: string;
18
+ active: boolean;
19
+ assignedPort?: number;
20
+ pid?: number;
21
+ status: ProjectImageState["status"] | "declared";
22
+ pharoMcpContract?: ProjectImageState["pharoMcpContract"];
23
+ }
24
+ export declare class ScopedPharoLauncherError extends Error {
25
+ constructor(message: string);
26
+ }
27
+ export declare class ScopedPharoLauncher {
28
+ private readonly options;
29
+ constructor(options: ScopedPharoLauncherOptions);
30
+ listImages(): {
31
+ scope: ResolvedScope;
32
+ images: WorkspaceImageSummary[];
33
+ };
34
+ imageInfo(imageId: string): {
35
+ scope: ResolvedScope;
36
+ image: WorkspaceImageSummary;
37
+ };
38
+ startImage(imageId: string): Promise<{
39
+ scope: ResolvedScope;
40
+ image: WorkspaceImageSummary;
41
+ }>;
42
+ stopImage(imageId: string): Promise<{
43
+ scope: ResolvedScope;
44
+ image: WorkspaceImageSummary;
45
+ }>;
46
+ }
47
+ export declare const scopedPharoLauncherTools: readonly [{
48
+ readonly name: "pharo_launcher_image_list";
49
+ readonly description: "List Pharo images declared in the current PLexus project/workspace scope.";
50
+ readonly inputSchema: {
51
+ readonly type: "object";
52
+ readonly properties: Record<string, unknown>;
53
+ readonly required: string[];
54
+ readonly additionalProperties: false;
55
+ };
56
+ }, {
57
+ readonly name: "pharo_launcher_image_info";
58
+ readonly description: "Return scoped state for one Pharo image handle in the current PLexus workspace.";
59
+ readonly inputSchema: {
60
+ readonly type: "object";
61
+ readonly properties: Record<string, unknown>;
62
+ readonly required: string[];
63
+ readonly additionalProperties: false;
64
+ };
65
+ }, {
66
+ readonly name: "pharo_launcher_image_start";
67
+ readonly description: "Start a workspace-scoped active image through PLexus project open policy.";
68
+ readonly inputSchema: {
69
+ readonly type: "object";
70
+ readonly properties: Record<string, unknown>;
71
+ readonly required: string[];
72
+ readonly additionalProperties: false;
73
+ };
74
+ }, {
75
+ readonly name: "pharo_launcher_image_stop";
76
+ readonly description: "Reserved scoped stop entry point. Does not accept arbitrary host pids or image names.";
77
+ readonly inputSchema: {
78
+ readonly type: "object";
79
+ readonly properties: Record<string, unknown>;
80
+ readonly required: string[];
81
+ readonly additionalProperties: false;
82
+ };
83
+ }];
84
+ export declare function createScopedPharoLauncherServer(options: ScopedPharoLauncherOptions): Server;
85
+ export declare function startScopedPharoLauncherServer(options: ScopedPharoLauncherOptions): Promise<void>;
86
+ export {};
87
+ //# sourceMappingURL=scopedPharoLauncherServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopedPharoLauncherServer.d.ts","sourceRoot":"","sources":["../src/scopedPharoLauncherServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAgB3B,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,aAAa;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC;IACjD,gBAAgB,CAAC,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;CAC1D;AAED,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,EAAE,MAAM;CAI5B;AA6DD,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,0BAA0B;IAEhE,UAAU,IAAI;QACZ,KAAK,EAAE,aAAa,CAAC;QACrB,MAAM,EAAE,qBAAqB,EAAE,CAAC;KACjC;IAuBD,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG;QAC1B,KAAK,EAAE,aAAa,CAAC;QACrB,KAAK,EAAE,qBAAqB,CAAC;KAC9B;IAeK,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QACzC,KAAK,EAAE,aAAa,CAAC;QACrB,KAAK,EAAE,qBAAqB,CAAC;KAC9B,CAAC;IAmBI,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QACxC,KAAK,EAAE,aAAa,CAAC;QACrB,KAAK,EAAE,qBAAqB,CAAC;KAC9B,CAAC;CAMH;AAED,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+B3B,CAAC;AAEX,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,0BAA0B,GAClC,MAAM,CAuDR;AAED,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAGf"}
@@ -0,0 +1,186 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
+ import { loadProjectConfig } from "./projectConfig.js";
5
+ import { openProject } from "./projectOpen.js";
6
+ import { defaultTargetId, defaultWorkspaceId, loadProjectState, projectStatePathForConfig, } from "./projectState.js";
7
+ const stringSchema = { type: "string", minLength: 1 };
8
+ function objectSchema(properties, required = []) {
9
+ return {
10
+ type: "object",
11
+ properties,
12
+ required,
13
+ additionalProperties: false,
14
+ };
15
+ }
16
+ export class ScopedPharoLauncherError extends Error {
17
+ constructor(message) {
18
+ super(message);
19
+ this.name = "ScopedPharoLauncherError";
20
+ }
21
+ }
22
+ function textResult(value, isError = false) {
23
+ return {
24
+ content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
25
+ ...(isError ? { isError } : {}),
26
+ };
27
+ }
28
+ function objectInput(input) {
29
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
30
+ return {};
31
+ }
32
+ return input;
33
+ }
34
+ function requireString(input, key) {
35
+ const value = input[key];
36
+ if (typeof value !== "string" || value.length === 0) {
37
+ throw new ScopedPharoLauncherError(`${key} is required`);
38
+ }
39
+ return value;
40
+ }
41
+ function requireConfirm(input) {
42
+ if (input.confirm !== true) {
43
+ throw new ScopedPharoLauncherError("confirm: true is required");
44
+ }
45
+ }
46
+ function resolveScope(options) {
47
+ const projectConfig = loadProjectConfig(options.projectRoot);
48
+ const workspaceId = options.workspaceId ?? defaultWorkspaceId(options.projectRoot);
49
+ return {
50
+ projectRoot: options.projectRoot,
51
+ workspaceId,
52
+ targetId: options.targetId ?? defaultTargetId(projectConfig.kanban.projectId, workspaceId),
53
+ ...(options.stateRoot ? { stateRoot: options.stateRoot } : {}),
54
+ };
55
+ }
56
+ function imageSummary(imageConfig, imageState) {
57
+ return {
58
+ imageId: imageConfig.id,
59
+ imageName: imageState?.imageName ?? imageConfig.imageName,
60
+ active: imageConfig.active,
61
+ ...(imageState?.assignedPort ? { assignedPort: imageState.assignedPort } : {}),
62
+ ...(imageState?.pid ? { pid: imageState.pid } : {}),
63
+ status: imageState?.status ?? "declared",
64
+ ...(imageState?.pharoMcpContract
65
+ ? { pharoMcpContract: imageState.pharoMcpContract }
66
+ : {}),
67
+ };
68
+ }
69
+ export class ScopedPharoLauncher {
70
+ options;
71
+ constructor(options) {
72
+ this.options = options;
73
+ }
74
+ listImages() {
75
+ const scope = resolveScope(this.options);
76
+ const projectConfig = loadProjectConfig(scope.projectRoot);
77
+ const state = loadProjectState(projectStatePathForConfig({
78
+ projectRoot: scope.projectRoot,
79
+ config: projectConfig,
80
+ workspaceId: scope.workspaceId,
81
+ stateRoot: scope.stateRoot,
82
+ }));
83
+ return {
84
+ scope,
85
+ images: projectConfig.images.map((imageConfig) => imageSummary(imageConfig, state?.images.find((image) => image.id === imageConfig.id))),
86
+ };
87
+ }
88
+ imageInfo(imageId) {
89
+ const listed = this.listImages();
90
+ const image = listed.images.find((candidate) => candidate.imageId === imageId);
91
+ if (!image) {
92
+ throw new ScopedPharoLauncherError(`Image ${imageId} is not declared in this PLexus workspace`);
93
+ }
94
+ return {
95
+ scope: listed.scope,
96
+ image,
97
+ };
98
+ }
99
+ async startImage(imageId) {
100
+ const before = this.imageInfo(imageId);
101
+ if (!before.image.active) {
102
+ throw new ScopedPharoLauncherError(`Image ${imageId} is not active in project config; scoped start is rejected`);
103
+ }
104
+ await openProject({
105
+ projectRoot: before.scope.projectRoot,
106
+ workspaceId: before.scope.workspaceId,
107
+ targetId: before.scope.targetId,
108
+ stateRoot: before.scope.stateRoot,
109
+ imageIds: [imageId],
110
+ });
111
+ return this.imageInfo(imageId);
112
+ }
113
+ async stopImage(imageId) {
114
+ const before = this.imageInfo(imageId);
115
+ throw new ScopedPharoLauncherError(`Scoped per-image stop is not implemented for ${before.image.imageId}; use PLexus project close policy`);
116
+ }
117
+ }
118
+ export const scopedPharoLauncherTools = [
119
+ {
120
+ name: "pharo_launcher_image_list",
121
+ description: "List Pharo images declared in the current PLexus project/workspace scope.",
122
+ inputSchema: objectSchema({}),
123
+ },
124
+ {
125
+ name: "pharo_launcher_image_info",
126
+ description: "Return scoped state for one Pharo image handle in the current PLexus workspace.",
127
+ inputSchema: objectSchema({ imageId: stringSchema }, ["imageId"]),
128
+ },
129
+ {
130
+ name: "pharo_launcher_image_start",
131
+ description: "Start a workspace-scoped active image through PLexus project open policy.",
132
+ inputSchema: objectSchema({ imageId: stringSchema }, ["imageId"]),
133
+ },
134
+ {
135
+ name: "pharo_launcher_image_stop",
136
+ description: "Reserved scoped stop entry point. Does not accept arbitrary host pids or image names.",
137
+ inputSchema: objectSchema({
138
+ imageId: stringSchema,
139
+ confirm: { type: "boolean" },
140
+ }, ["imageId", "confirm"]),
141
+ },
142
+ ];
143
+ export function createScopedPharoLauncherServer(options) {
144
+ const facade = new ScopedPharoLauncher(options);
145
+ const server = new Server({
146
+ name: "pharo-launcher",
147
+ version: "0.1.0",
148
+ }, {
149
+ capabilities: {
150
+ tools: {},
151
+ },
152
+ });
153
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
154
+ tools: [...scopedPharoLauncherTools],
155
+ }));
156
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
157
+ try {
158
+ const input = objectInput(request.params.arguments ?? {});
159
+ switch (request.params.name) {
160
+ case "pharo_launcher_image_list":
161
+ return textResult(facade.listImages());
162
+ case "pharo_launcher_image_info":
163
+ return textResult(facade.imageInfo(requireString(input, "imageId")));
164
+ case "pharo_launcher_image_start":
165
+ return textResult(await facade.startImage(requireString(input, "imageId")));
166
+ case "pharo_launcher_image_stop":
167
+ requireConfirm(input);
168
+ return textResult(await facade.stopImage(requireString(input, "imageId")));
169
+ default:
170
+ return textResult({ ok: false, error: `Unknown tool: ${request.params.name}` }, true);
171
+ }
172
+ }
173
+ catch (error) {
174
+ return textResult({
175
+ ok: false,
176
+ error: error instanceof Error ? error.message : String(error),
177
+ }, true);
178
+ }
179
+ });
180
+ return server;
181
+ }
182
+ export async function startScopedPharoLauncherServer(options) {
183
+ const server = createScopedPharoLauncherServer(options);
184
+ await server.connect(new StdioServerTransport());
185
+ }
186
+ //# sourceMappingURL=scopedPharoLauncherServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopedPharoLauncherServer.js","sourceRoot":"","sources":["../src/scopedPharoLauncherServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import { type ProjectConfig } from "./projectConfig.js";
2
+ import { type ProjectImageStatus, type ProjectState } from "./projectState.js";
3
+ export type ScopedProjectContextSchemaVersion = 1;
4
+ export type ScopedImageStatus = ProjectImageStatus | "declared";
5
+ export type ScopedImageCleanupPolicy = "workspace_cleanup_only";
6
+ export interface ScopedProjectContextScope {
7
+ projectRoot: string;
8
+ projectId: string;
9
+ projectName: string;
10
+ workspaceId: string;
11
+ targetId: string;
12
+ stateRoot?: string;
13
+ statePath: string;
14
+ }
15
+ export interface ScopedImageOwnership {
16
+ projectId: string;
17
+ workspaceId: string;
18
+ targetId: string;
19
+ owned: true;
20
+ disposable: true;
21
+ }
22
+ export interface ScopedImageAffordanceAllowed {
23
+ allowed: true;
24
+ toolName: string;
25
+ arguments: Record<string, unknown>;
26
+ }
27
+ export interface ScopedImageAffordanceDenied {
28
+ allowed: false;
29
+ reason: string;
30
+ }
31
+ export type ScopedImageAffordance = ScopedImageAffordanceAllowed | ScopedImageAffordanceDenied;
32
+ export interface ScopedImageAffordances {
33
+ create: ScopedImageAffordance;
34
+ start: ScopedImageAffordance;
35
+ stop: ScopedImageAffordance;
36
+ delete: ScopedImageAffordanceDenied;
37
+ }
38
+ export interface ScopedImageCleanupPaths {
39
+ imagePath?: string;
40
+ imageDirectoryPath?: string;
41
+ changesPath?: string;
42
+ localDirectoryPath?: string;
43
+ ombuDirectoryPath?: string;
44
+ }
45
+ export interface ScopedImageCleanupMetadata {
46
+ disposable: true;
47
+ statePath: string;
48
+ launcherImageName: string;
49
+ policy: ScopedImageCleanupPolicy;
50
+ paths: ScopedImageCleanupPaths;
51
+ }
52
+ export interface ScopedImageGatewayRouteMetadata {
53
+ serverName: "gateway";
54
+ requiredArgument: "imageId";
55
+ imageId: string;
56
+ routeReference: {
57
+ projectId: string;
58
+ workspaceId: string;
59
+ targetId: string;
60
+ };
61
+ imageIdSource: string;
62
+ recordHint: string;
63
+ }
64
+ export interface ScopedImageContext {
65
+ imageId: string;
66
+ launcherImageName: string;
67
+ active: boolean;
68
+ status: ScopedImageStatus;
69
+ assignedPort?: number;
70
+ pid?: number;
71
+ ownership: ScopedImageOwnership;
72
+ affordances: ScopedImageAffordances;
73
+ cleanup: ScopedImageCleanupMetadata;
74
+ route: ScopedImageGatewayRouteMetadata;
75
+ }
76
+ export interface ScopedProjectContext {
77
+ schemaVersion: ScopedProjectContextSchemaVersion;
78
+ scope: ScopedProjectContextScope;
79
+ images: ScopedImageContext[];
80
+ }
81
+ export interface BuildScopedProjectContextOptions {
82
+ projectRoot: string;
83
+ projectConfig?: ProjectConfig;
84
+ workspaceId?: string;
85
+ targetId?: string;
86
+ stateRoot?: string;
87
+ projectState?: ProjectState;
88
+ }
89
+ export declare class ScopedProjectContextError extends Error {
90
+ constructor(message: string);
91
+ }
92
+ export declare function buildScopedProjectContext(options: BuildScopedProjectContextOptions): ScopedProjectContext;
93
+ //# sourceMappingURL=scopedProjectContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopedProjectContext.d.ts","sourceRoot":"","sources":["../src/scopedProjectContext.ts"],"names":[],"mappings":"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"}