@minicor/mcp-server 3.2.0 → 3.2.2

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 (51) hide show
  1. package/README.md +69 -24
  2. package/dist/__tests__/laminar-client.test.d.ts +2 -0
  3. package/dist/__tests__/laminar-client.test.d.ts.map +1 -0
  4. package/dist/__tests__/laminar-client.test.js +70 -0
  5. package/dist/__tests__/laminar-client.test.js.map +1 -0
  6. package/dist/__tests__/token-provider.test.d.ts +2 -0
  7. package/dist/__tests__/token-provider.test.d.ts.map +1 -0
  8. package/dist/__tests__/token-provider.test.js +82 -0
  9. package/dist/__tests__/token-provider.test.js.map +1 -0
  10. package/dist/bootstrap.d.ts +12 -0
  11. package/dist/bootstrap.d.ts.map +1 -0
  12. package/dist/bootstrap.js +244 -0
  13. package/dist/bootstrap.js.map +1 -0
  14. package/dist/config.d.ts +6 -3
  15. package/dist/config.d.ts.map +1 -1
  16. package/dist/config.js +14 -10
  17. package/dist/config.js.map +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +64 -10
  20. package/dist/index.js.map +1 -1
  21. package/dist/laminar-client.d.ts +3 -1
  22. package/dist/laminar-client.d.ts.map +1 -1
  23. package/dist/laminar-client.js +18 -5
  24. package/dist/laminar-client.js.map +1 -1
  25. package/dist/lib.d.ts +10 -7
  26. package/dist/lib.d.ts.map +1 -1
  27. package/dist/lib.js +64 -10
  28. package/dist/lib.js.map +1 -1
  29. package/dist/prompts/workspace-session.d.ts +3 -0
  30. package/dist/prompts/workspace-session.d.ts.map +1 -0
  31. package/dist/prompts/workspace-session.js +58 -0
  32. package/dist/prompts/workspace-session.js.map +1 -0
  33. package/dist/state.d.ts +22 -0
  34. package/dist/state.d.ts.map +1 -1
  35. package/dist/state.js +12 -0
  36. package/dist/state.js.map +1 -1
  37. package/dist/token-provider.d.ts +16 -0
  38. package/dist/token-provider.d.ts.map +1 -0
  39. package/dist/token-provider.js +44 -0
  40. package/dist/token-provider.js.map +1 -0
  41. package/dist/tools/session.d.ts +8 -0
  42. package/dist/tools/session.d.ts.map +1 -0
  43. package/dist/tools/session.js +392 -0
  44. package/dist/tools/session.js.map +1 -0
  45. package/dist/tools/sync-tools.d.ts.map +1 -1
  46. package/dist/tools/sync-tools.js +37 -8
  47. package/dist/tools/sync-tools.js.map +1 -1
  48. package/dist/tools/vm.d.ts.map +1 -1
  49. package/dist/tools/vm.js +17 -9
  50. package/dist/tools/vm.js.map +1 -1
  51. package/package.json +5 -3
package/README.md CHANGED
@@ -34,10 +34,46 @@ npx @minicor/mcp-server-setup
34
34
 
35
35
  Opens a browser to sign in. Tokens stored at `~/.minicor/tokens.json` with auto-refresh. For headless: `npx @minicor/mcp-server-setup --cli`.
36
36
 
37
- ### 3. Update
37
+ ### 3. Bootstrap Workspace (optional)
38
+
39
+ After cloning a workspace, generate harness-specific config files:
40
+
41
+ ```bash
42
+ # For Claude Code — creates CLAUDE.md + .claude/settings.local.json
43
+ npx @minicor/mcp-server minicor-bootstrap claude-code --dir ./my-workspace
44
+
45
+ # For Cursor — creates .cursor/rules/workspace.mdc
46
+ npx @minicor/mcp-server minicor-bootstrap cursor --dir ./my-workspace
47
+
48
+ # All harnesses at once
49
+ npx @minicor/mcp-server minicor-bootstrap all --dir ./my-workspace
50
+ ```
51
+
52
+ ### 4. Update
38
53
 
39
54
  `npx` users: restart your editor (auto-fetches latest). Global: `npm update -g @minicor/mcp-server`.
40
55
 
56
+ ## Session Lifecycle
57
+
58
+ The MCP server sends **instructions** to every client on connect, telling agents to call `session_start` first when in a workspace clone. This works across all harnesses — Claude Code, Cursor, Bedrock, etc.
59
+
60
+ ### Session Tools
61
+
62
+ | Tool | What it does |
63
+ | --- | --- |
64
+ | `session_start` | Load workspace context (AGENTS.md, VMs, skills, issues, prior session). Call FIRST in a workspace clone. |
65
+ | `session_checkpoint` | Save progress mid-session. Writes `.minicor/session.json` + syncs `[Workspace:Session]` issue. |
66
+ | `session_end` | Persist final state, sync to platform, optionally update context.md. Call before ending work. |
67
+ | `set_workspaces_root` | Set default root directory for cloning workspaces (saved to `~/.minicor/config.json`). |
68
+
69
+ ### Auto-Save on Disconnect
70
+
71
+ If the agent crashes or the user closes the IDE, the server auto-checkpoints with `status: "interrupted"` so no session state is lost. The next agent resumes from that checkpoint.
72
+
73
+ ### Multi-Agent Handoff
74
+
75
+ Sessions are synced to `[Workspace:Session]` issues on the platform, so agents on other machines (or scheduled Bedrock agents) can resume where the last agent left off.
76
+
41
77
  ## The RPA Lifecycle
42
78
 
43
79
  This is the complete flow from zero to production automation. The agent handles each phase using MCP tools and skills.
@@ -310,24 +346,36 @@ Agents are autonomous runners that execute tasks on VMs using MCP tools. After b
310
346
  ### Workspace Sync
311
347
 
312
348
 
313
- | Tool | What it does |
314
- | --------------------------------- | -------------------------------------------------------------- |
315
- | `clone_workspace` | Full workspace clone: workflows + skills + issues + metadata |
316
- | `init_project` | Scaffold a git-ready project from a workspace (workflows only) |
317
- | `pull_workflow` / `push_workflow` | Sync individual workflows |
318
- | `pull_all` / `push_changed` | Bulk sync |
319
- | `sync_status` | Diff local vs deployed |
349
+ | Tool | What it does |
350
+ | --------------------------------- | ------------------------------------------------------------------------------ |
351
+ | `clone_workspace` | Full workspace clone: workflows + skills + issues + metadata. Defaults to configured workspaces root if outputDir omitted. |
352
+ | `init_project` | Scaffold a git-ready project from a workspace (workflows only) |
353
+ | `pull_workflow` / `push_workflow` | Sync individual workflows |
354
+ | `pull_all` / `push_changed` | Bulk sync |
355
+ | `sync_status` | Diff local vs deployed |
356
+ | `set_workspaces_root` | Set default root directory for cloning workspaces (`~/.minicor/config.json`) |
357
+
358
+
359
+ ### Session Lifecycle
360
+
361
+
362
+ | Tool | What it does |
363
+ | --------------------- | --------------------------------------------------------------------------------------------- |
364
+ | `session_start` | Load full workspace context + begin session tracking. Call FIRST in a workspace clone. |
365
+ | `session_checkpoint` | Save progress: writes `.minicor/session.json` + syncs `[Workspace:Session]` issue. |
366
+ | `session_end` | End session: persist final state, sync to platform, optionally update context.md. |
320
367
 
321
368
 
322
369
  ## Prompts
323
370
 
324
371
 
325
- | Prompt | What it does |
326
- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
327
- | `build-rpa-workflow` | Guided automation building with POC/production mode. Loads skills, iterative build loop, per-step Minicor testing, optional hardening. |
328
- | `debug-workflow-execution` | Analyze a failed execution with VM-aware debugging and replay |
329
- | `minicor-workflow-guide` | Full workflow specification: step types, data access, keywords, libraries |
330
- | `2fa-workflow-guide` | Handling 2FA in workflows: provisioning channels, TOTP secrets, auto-resolving OTP codes |
372
+ | Prompt | What it does |
373
+ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
374
+ | `build-rpa-workflow` | Guided automation building with POC/production mode. Loads skills, iterative build loop, per-step Minicor testing, optional hardening. |
375
+ | `debug-workflow-execution` | Analyze a failed execution with VM-aware debugging and replay |
376
+ | `minicor-workflow-guide` | Full workflow specification: step types, data access, keywords, libraries |
377
+ | `2fa-workflow-guide` | Handling 2FA in workflows: provisioning channels, TOTP secrets, auto-resolving OTP codes |
378
+ | `workspace-session-guide` | Returns AGENTS.md rules and session state for any workspace clone |
331
379
 
332
380
 
333
381
  The `build-rpa-workflow` prompt accepts a `mode` parameter:
@@ -363,27 +411,24 @@ npm test
363
411
 
364
412
  ```
365
413
  src/
366
- index.ts — CLI MCP entry (stdio transport, token management)
414
+ index.ts — CLI MCP entry (stdio transport, token management, disconnect hooks)
367
415
  lib.ts — Embeddable server factory (in-process, no side effects)
416
+ bootstrap.ts — CLI to generate harness configs (CLAUDE.md, .cursor/rules, etc.)
417
+ config.ts — User config (~/.minicor/config.json) — workspacesRoot, etc.
418
+ state.ts — Shared mutable state (VM connections, active session tracking)
368
419
  skills.ts — Skill loader, parser, index builder
369
- skills-service-client.ts — HTTP client for skills service
370
- seed-skills.ts — CLI to seed skills service from bundled files
371
420
  tools/
421
+ session.ts — session_start, session_checkpoint, session_end, auto-checkpoint
372
422
  skills.ts — list_skills, get_skill, save_skill, generate_skill
423
+ sync-tools.ts — clone_workspace, init_project, pull/push, set_workspaces_root
373
424
  vm.ts, vm-rpa.ts — VM and RPA tools
374
425
  core.ts — Workflows, flows, executions
375
- sync-tools.ts — clone_workspace, init_project, pull/push
376
426
  ...
377
427
  prompts/
428
+ workspace-session.ts — Workspace session guide prompt
378
429
  build-rpa.ts — Guided RPA building (POC/production modes)
379
430
  ...
380
431
  skills/
381
432
  general/ — Bundled skill files (shipped with npm package)
382
- rpa-testing-workflow.md
383
- cdp-browser-automation.md
384
- desktop-uiautomation.md
385
- data-extraction-strategies.md
386
- data-passing-between-steps.md
387
- state-verification.md
388
433
  ```
389
434
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=laminar-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"laminar-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/laminar-client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,70 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { LaminarClient } from "../laminar-client.js";
3
+ import { TokenProvider } from "../token-provider.js";
4
+ let fetchMock;
5
+ beforeEach(() => {
6
+ fetchMock = vi.fn();
7
+ vi.stubGlobal("fetch", fetchMock);
8
+ });
9
+ afterEach(() => {
10
+ vi.restoreAllMocks();
11
+ });
12
+ function jsonResponse(status, body) {
13
+ return new Response(JSON.stringify(body), {
14
+ status,
15
+ headers: { "Content-Type": "application/json" },
16
+ });
17
+ }
18
+ describe("LaminarClient 401 retry", () => {
19
+ it("retries once on 401 when tokenProvider is available", async () => {
20
+ const refreshFn = vi.fn().mockResolvedValue({
21
+ token: "tok-new",
22
+ expiresAt: Date.now() + 3600_000,
23
+ });
24
+ const provider = new TokenProvider("tok-old", Date.now() - 1000, refreshFn);
25
+ const client = new LaminarClient({ type: "bearer", token: "tok-old" }, "https://api.test.com", provider);
26
+ fetchMock
27
+ .mockResolvedValueOnce(new Response("Unauthorized", { status: 401 }))
28
+ .mockResolvedValueOnce(jsonResponse(200, { id: 1 }));
29
+ const result = await client.getMe();
30
+ expect(result).toEqual({ id: 1 });
31
+ expect(fetchMock).toHaveBeenCalledTimes(2);
32
+ expect(refreshFn).toHaveBeenCalledOnce();
33
+ });
34
+ it("throws on 401 without tokenProvider (existing behavior)", async () => {
35
+ const client = new LaminarClient({ type: "bearer", token: "tok-old" }, "https://api.test.com");
36
+ fetchMock.mockResolvedValueOnce(new Response("Unauthorized", { status: 401 }));
37
+ await expect(client.getMe()).rejects.toThrow("failed (401)");
38
+ expect(fetchMock).toHaveBeenCalledOnce();
39
+ });
40
+ it("throws if retry also returns 401", async () => {
41
+ const refreshFn = vi.fn().mockResolvedValue({
42
+ token: "tok-still-bad",
43
+ expiresAt: Date.now() + 3600_000,
44
+ });
45
+ const provider = new TokenProvider("tok-old", Date.now() - 1000, refreshFn);
46
+ const client = new LaminarClient({ type: "bearer", token: "tok-old" }, "https://api.test.com", provider);
47
+ fetchMock
48
+ .mockResolvedValueOnce(new Response("Unauthorized", { status: 401 }))
49
+ .mockResolvedValueOnce(new Response("Unauthorized", { status: 401 }));
50
+ await expect(client.getMe()).rejects.toThrow("failed (401)");
51
+ expect(fetchMock).toHaveBeenCalledTimes(2);
52
+ });
53
+ it("uses refreshed token in the retry request header", async () => {
54
+ const refreshFn = vi.fn().mockResolvedValue({
55
+ token: "tok-fresh",
56
+ expiresAt: Date.now() + 3600_000,
57
+ });
58
+ const provider = new TokenProvider("tok-stale", Date.now() - 1000, refreshFn);
59
+ const client = new LaminarClient({ type: "bearer", token: "ignored" }, "https://api.test.com", provider);
60
+ fetchMock
61
+ .mockResolvedValueOnce(new Response("Unauthorized", { status: 401 }))
62
+ .mockResolvedValueOnce(jsonResponse(200, { ok: true }));
63
+ await client.listWorkspaces();
64
+ const firstCall = fetchMock.mock.calls[0][1].headers;
65
+ expect(firstCall["Authorization"]).toBe("Bearer tok-stale");
66
+ const retryCall = fetchMock.mock.calls[1][1].headers;
67
+ expect(retryCall["Authorization"]).toBe("Bearer tok-fresh");
68
+ });
69
+ });
70
+ //# sourceMappingURL=laminar-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"laminar-client.test.js","sourceRoot":"","sources":["../../src/__tests__/laminar-client.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=token-provider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-provider.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/token-provider.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,82 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { TokenProvider } from "../token-provider.js";
3
+ describe("TokenProvider", () => {
4
+ it("returns the initial token", () => {
5
+ const provider = new TokenProvider("tok-1", Date.now() + 60_000);
6
+ expect(provider.getToken()).toBe("tok-1");
7
+ });
8
+ it("refreshes the token and updates state", async () => {
9
+ const refreshFn = vi.fn().mockResolvedValue({
10
+ token: "tok-2",
11
+ expiresAt: Date.now() + 3600_000,
12
+ });
13
+ const provider = new TokenProvider("tok-1", Date.now() - 1000, refreshFn);
14
+ const newToken = await provider.refreshToken();
15
+ expect(newToken).toBe("tok-2");
16
+ expect(provider.getToken()).toBe("tok-2");
17
+ expect(refreshFn).toHaveBeenCalledOnce();
18
+ });
19
+ it("fires onTokenRefreshed callback", async () => {
20
+ const refreshFn = vi.fn().mockResolvedValue({
21
+ token: "tok-2",
22
+ expiresAt: Date.now() + 3600_000,
23
+ });
24
+ const provider = new TokenProvider("tok-1", Date.now() - 1000, refreshFn);
25
+ const hook = vi.fn();
26
+ provider.onTokenRefreshed = hook;
27
+ await provider.refreshToken();
28
+ expect(hook).toHaveBeenCalledWith("tok-2");
29
+ });
30
+ it("deduplicates concurrent refresh calls (mutex)", async () => {
31
+ let resolveRefresh;
32
+ const refreshFn = vi.fn().mockImplementation(() => new Promise((r) => { resolveRefresh = r; }));
33
+ const provider = new TokenProvider("tok-1", Date.now() - 1000, refreshFn);
34
+ const p1 = provider.refreshToken();
35
+ const p2 = provider.refreshToken();
36
+ resolveRefresh({ token: "tok-2", expiresAt: Date.now() + 3600_000 });
37
+ const [r1, r2] = await Promise.all([p1, p2]);
38
+ expect(r1).toBe("tok-2");
39
+ expect(r2).toBe("tok-2");
40
+ expect(refreshFn).toHaveBeenCalledOnce();
41
+ });
42
+ it("throws when refresh returns null", async () => {
43
+ const refreshFn = vi.fn().mockResolvedValue(null);
44
+ const provider = new TokenProvider("tok-1", Date.now() - 1000, refreshFn);
45
+ await expect(provider.refreshToken()).rejects.toThrow("Token refresh returned null");
46
+ expect(provider.getToken()).toBe("tok-1");
47
+ });
48
+ it("throws when no refresh function is configured", async () => {
49
+ const provider = new TokenProvider("tok-1", Date.now() - 1000);
50
+ await expect(provider.refreshToken()).rejects.toThrow("No refresh function configured");
51
+ });
52
+ it("allows a new refresh after a previous one completes", async () => {
53
+ let callCount = 0;
54
+ const refreshFn = vi.fn().mockImplementation(async () => {
55
+ callCount++;
56
+ return { token: `tok-${callCount + 1}`, expiresAt: Date.now() + 3600_000 };
57
+ });
58
+ const provider = new TokenProvider("tok-1", Date.now() - 1000, refreshFn);
59
+ await provider.refreshToken();
60
+ expect(provider.getToken()).toBe("tok-2");
61
+ await provider.refreshToken();
62
+ expect(provider.getToken()).toBe("tok-3");
63
+ expect(refreshFn).toHaveBeenCalledTimes(2);
64
+ });
65
+ it("succeeds even if onTokenRefreshed callback throws", async () => {
66
+ const refreshFn = vi.fn().mockResolvedValue({
67
+ token: "tok-2",
68
+ expiresAt: Date.now() + 3600_000,
69
+ });
70
+ const provider = new TokenProvider("tok-1", Date.now() - 1000, refreshFn);
71
+ provider.onTokenRefreshed = () => { throw new Error("disk write failed"); };
72
+ const result = await provider.refreshToken();
73
+ expect(result).toBe("tok-2");
74
+ expect(provider.getToken()).toBe("tok-2");
75
+ });
76
+ it("isExpiringSoon returns true when token is about to expire", () => {
77
+ const provider = new TokenProvider("tok-1", Date.now() + 60_000);
78
+ expect(provider.isExpiringSoon(120_000)).toBe(true);
79
+ expect(provider.isExpiringSoon(30_000)).toBe(false);
80
+ });
81
+ });
82
+ //# sourceMappingURL=token-provider.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-provider.test.js","sourceRoot":"","sources":["../../src/__tests__/token-provider.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Bootstrap CLI — generates harness-specific config files for a Minicor workspace clone.
4
+ *
5
+ * Usage:
6
+ * minicor-bootstrap claude-code [--dir <workspace-dir>]
7
+ * minicor-bootstrap cursor [--dir <workspace-dir>]
8
+ * minicor-bootstrap generic [--dir <workspace-dir>]
9
+ * minicor-bootstrap all [--dir <workspace-dir>]
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG"}
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Bootstrap CLI — generates harness-specific config files for a Minicor workspace clone.
4
+ *
5
+ * Usage:
6
+ * minicor-bootstrap claude-code [--dir <workspace-dir>]
7
+ * minicor-bootstrap cursor [--dir <workspace-dir>]
8
+ * minicor-bootstrap generic [--dir <workspace-dir>]
9
+ * minicor-bootstrap all [--dir <workspace-dir>]
10
+ */
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ function resolveDir(args) {
14
+ const idx = args.indexOf("--dir");
15
+ if (idx !== -1 && args[idx + 1]) {
16
+ return path.resolve(args[idx + 1]);
17
+ }
18
+ return process.cwd();
19
+ }
20
+ function loadWorkspaceInfo(dir) {
21
+ const manifestPath = path.join(dir, "minicor.json");
22
+ if (!fs.existsSync(manifestPath)) {
23
+ console.error(`Error: ${dir} is not a Minicor workspace clone (no minicor.json found).`);
24
+ process.exit(1);
25
+ }
26
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
27
+ let name = "Minicor Workspace";
28
+ let region;
29
+ const wsPath = path.join(dir, ".minicor", "workspace.json");
30
+ if (fs.existsSync(wsPath)) {
31
+ const ws = JSON.parse(fs.readFileSync(wsPath, "utf-8"));
32
+ name = ws.name || name;
33
+ region = ws.region;
34
+ }
35
+ return {
36
+ dir,
37
+ name,
38
+ workspaceId: manifest.workspace ?? 0,
39
+ region,
40
+ hasAgentsMd: fs.existsSync(path.join(dir, "AGENTS.md")),
41
+ };
42
+ }
43
+ function bootstrapClaudeCode(info) {
44
+ const claudeMd = `# ${info.name} — Minicor Workspace
45
+
46
+ This workspace is a Minicor workspace clone (workspace **${info.workspaceId}**).
47
+
48
+ ## CRITICAL: First Action
49
+
50
+ Call \`session_start(directory: "${info.dir}")\` as your FIRST action in every session.
51
+ It returns the workspace rules (AGENTS.md), prior session state for resuming, and all
52
+ context you need. Follow the phase loop it describes.
53
+
54
+ ## Session Management
55
+
56
+ - **Resume**: If session_start returns a prior session, resume from where the last agent left off.
57
+ Do NOT start over.
58
+ - **Checkpoint**: Call \`session_checkpoint\` between phases or after significant progress.
59
+ - **End**: Call \`session_end\` before ending your work. Other agents depend on this to resume.
60
+
61
+ ## Key Rules
62
+
63
+ - Use \`create_rpa_flow\` for RPA steps, never \`create_flow\`
64
+ - Follow the \`rpa-testing-workflow\` skill for testing
65
+ - Fix failures through the executor, NOT \`vm_execute_script\`
66
+ - Update \`.minicor/context.md\` when you learn something new
67
+ - Create/update \`[Workspace:Session]\` and \`[Workspace:Context]\` issues
68
+ `;
69
+ const claudeMdPath = path.join(info.dir, "CLAUDE.md");
70
+ fs.writeFileSync(claudeMdPath, claudeMd, "utf-8");
71
+ console.log(` Created ${claudeMdPath}`);
72
+ const claudeDir = path.join(info.dir, ".claude");
73
+ if (!fs.existsSync(claudeDir))
74
+ fs.mkdirSync(claudeDir, { recursive: true });
75
+ const settingsPath = path.join(claudeDir, "settings.local.json");
76
+ let settings = {};
77
+ if (fs.existsSync(settingsPath)) {
78
+ try {
79
+ settings = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
80
+ }
81
+ catch {
82
+ settings = {};
83
+ }
84
+ }
85
+ if (!settings.permissions)
86
+ settings.permissions = {};
87
+ if (!settings.permissions.allow)
88
+ settings.permissions.allow = [];
89
+ const requiredPerms = [
90
+ "mcp__minicor__session_start",
91
+ "mcp__minicor__session_checkpoint",
92
+ "mcp__minicor__session_end",
93
+ "mcp__minicor__get_workspace_context",
94
+ "mcp__minicor__list_workspaces",
95
+ "mcp__minicor__list_workflows",
96
+ "mcp__minicor__get_workflow",
97
+ "mcp__minicor__get_workflow_overview",
98
+ "mcp__minicor__list_executions",
99
+ "mcp__minicor__get_execution",
100
+ "mcp__minicor__get_execution_status",
101
+ "mcp__minicor__get_execution_result",
102
+ "mcp__minicor__execute_workflow",
103
+ "mcp__minicor__execute_workflow_async",
104
+ "mcp__minicor__create_rpa_flow",
105
+ "mcp__minicor__debug_rpa_step",
106
+ "mcp__minicor__vm_connect",
107
+ "mcp__minicor__vm_disconnect",
108
+ "mcp__minicor__vm_status",
109
+ "mcp__minicor__vm_screenshot",
110
+ "mcp__minicor__vm_execute_script",
111
+ "mcp__minicor__vm_inspect_ui",
112
+ "mcp__minicor__vm_list",
113
+ "mcp__minicor__list_issues",
114
+ "mcp__minicor__get_issue",
115
+ "mcp__minicor__create_issue",
116
+ "mcp__minicor__update_issue",
117
+ "mcp__minicor__list_skills",
118
+ "mcp__minicor__get_skill",
119
+ "mcp__minicor__save_skill",
120
+ "mcp__minicor__generate_skill",
121
+ "mcp__minicor__push_changed",
122
+ "mcp__minicor__pull_all",
123
+ "mcp__minicor__sync_status",
124
+ "mcp__minicor__create_agent",
125
+ "mcp__minicor__list_agents",
126
+ "mcp__minicor__test_workflow_step",
127
+ "mcp__minicor__diagnose_execution",
128
+ ];
129
+ const existing = new Set(settings.permissions.allow);
130
+ for (const perm of requiredPerms) {
131
+ if (!existing.has(perm)) {
132
+ settings.permissions.allow.push(perm);
133
+ }
134
+ }
135
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
136
+ console.log(` Updated ${settingsPath}`);
137
+ }
138
+ function bootstrapCursor(info) {
139
+ const cursorDir = path.join(info.dir, ".cursor", "rules");
140
+ if (!fs.existsSync(cursorDir))
141
+ fs.mkdirSync(cursorDir, { recursive: true });
142
+ const mdc = `---
143
+ description: Minicor workspace clone
144
+ alwaysApply: true
145
+ ---
146
+ You are in a Minicor workspace clone (${info.name}). Call \`session_start(directory: "${info.dir}")\` as your FIRST action. It returns AGENTS.md, workspace metadata, VMs, skills, session state, and any prior context. If there is an active session, resume from where the last agent left off. Before ending your session, call \`session_end()\` to persist progress and sync it to a [Workspace:Session] issue.
147
+ `;
148
+ const mdcPath = path.join(cursorDir, "workspace.mdc");
149
+ fs.writeFileSync(mdcPath, mdc, "utf-8");
150
+ console.log(` Created ${mdcPath}`);
151
+ }
152
+ function bootstrapGeneric(info) {
153
+ const minicorDir = path.join(info.dir, ".minicor");
154
+ if (!fs.existsSync(minicorDir))
155
+ fs.mkdirSync(minicorDir, { recursive: true });
156
+ const prompt = `# ${info.name} — System Prompt
157
+
158
+ You are working in a Minicor workspace clone (workspace ${info.workspaceId}).
159
+
160
+ ## Required First Action
161
+
162
+ Call \`session_start(directory: "${info.dir}")\` as your FIRST action.
163
+ It returns:
164
+ - AGENTS.md with the full agent phase loop
165
+ - Workspace metadata (VMs, agents, skills)
166
+ - Prior session state for resuming
167
+ - Context from previous agent runs
168
+
169
+ ## Session Lifecycle
170
+
171
+ 1. **Start**: \`session_start\` — loads context and begins tracking
172
+ 2. **Checkpoint**: \`session_checkpoint\` — saves progress between phases
173
+ 3. **End**: \`session_end\` — persists final state, syncs to platform
174
+
175
+ ## Key Rules
176
+
177
+ - Follow the phase loop from AGENTS.md: gather-context → orient → scope → build → test → harden → learn
178
+ - If a prior session exists, resume from where it left off
179
+ - Use \`create_rpa_flow\` for RPA steps (never \`create_flow\`)
180
+ - Always call \`session_end\` before finishing
181
+ `;
182
+ const promptPath = path.join(minicorDir, "system-prompt.md");
183
+ fs.writeFileSync(promptPath, prompt, "utf-8");
184
+ console.log(` Created ${promptPath}`);
185
+ }
186
+ function showHelp() {
187
+ console.log(`
188
+ minicor-bootstrap — Generate harness-specific config for a Minicor workspace clone
189
+
190
+ Usage:
191
+ minicor-bootstrap <target> [--dir <workspace-dir>]
192
+
193
+ Targets:
194
+ claude-code Generate CLAUDE.md + .claude/settings.local.json
195
+ cursor Generate .cursor/rules/workspace.mdc
196
+ generic Generate .minicor/system-prompt.md
197
+ all Generate all of the above
198
+
199
+ Options:
200
+ --dir <path> Workspace directory (default: current directory)
201
+
202
+ Examples:
203
+ minicor-bootstrap all
204
+ minicor-bootstrap claude-code --dir /path/to/workspace
205
+ minicor-bootstrap cursor --dir ./my-workspace
206
+ `);
207
+ }
208
+ async function main() {
209
+ const args = process.argv.slice(2);
210
+ const target = args[0];
211
+ if (!target || target === "help" || target === "--help") {
212
+ showHelp();
213
+ return;
214
+ }
215
+ const dir = resolveDir(args);
216
+ const info = loadWorkspaceInfo(dir);
217
+ console.log(`Bootstrapping "${info.name}" (workspace ${info.workspaceId}) at ${dir}\n`);
218
+ switch (target) {
219
+ case "claude-code":
220
+ bootstrapClaudeCode(info);
221
+ break;
222
+ case "cursor":
223
+ bootstrapCursor(info);
224
+ break;
225
+ case "generic":
226
+ bootstrapGeneric(info);
227
+ break;
228
+ case "all":
229
+ bootstrapClaudeCode(info);
230
+ bootstrapCursor(info);
231
+ bootstrapGeneric(info);
232
+ break;
233
+ default:
234
+ console.error(`Unknown target: ${target}`);
235
+ showHelp();
236
+ process.exit(1);
237
+ }
238
+ console.log("\nDone. Re-run after updating AGENTS.md to regenerate configs.");
239
+ }
240
+ main().catch((err) => {
241
+ console.error(`Error: ${err.message}`);
242
+ process.exit(1);
243
+ });
244
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  /**
2
2
  * Configuration helpers for Minicor MCP.
3
3
  *
4
- * Previously housed Elasticsearch + CRON service config.
5
- * Kept for future extensibility; config file paths still used by setup.
4
+ * Stores user preferences in ~/.minicor/config.json:
5
+ * - workspacesRoot: default directory for cloning workspaces
6
6
  */
7
7
  export interface ServiceConfig {
8
+ /** Default root directory for cloning workspaces (e.g. ~/laminar/customers) */
9
+ workspacesRoot?: string;
8
10
  }
9
11
  export declare function loadServiceConfig(): ServiceConfig;
10
- export declare function saveServiceConfig(update: ServiceConfig): void;
12
+ export declare function saveServiceConfig(update: Partial<ServiceConfig>): void;
13
+ export declare function getWorkspacesRoot(): string | undefined;
11
14
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;CAAG;AAEjC,wBAAgB,iBAAiB,IAAI,aAAa,CAEjD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,QAiBtD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,iBAAiB,IAAI,aAAa,CAQjD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,QAU/D;AAED,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAGtD"}