@ericsanchezok/meta-synergy 1.1.26 → 1.2.18

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.
@@ -27,13 +27,49 @@ afterAll(async () => {
27
27
  describe("meta-synergy control socket", () => {
28
28
  test("exposes runtime control actions over the local socket", async () => {
29
29
  const runtime = await MetaSynergyRuntime.create()
30
+ const envID = runtime.host.envID
31
+ if (!envID) throw new Error("Expected runtime envID")
30
32
  await runtime.control.start()
31
33
  try {
32
34
  expect(await MetaSynergyControlClient.isAvailable()).toBe(true)
33
35
 
36
+ const mode = await MetaSynergyControlClient.request<{
37
+ mode: string
38
+ ownership: { local: { owned: boolean; activeOwnerID: string | null } }
39
+ }>({ action: "runtime.mode" })
40
+ expect(mode.mode).toBe("standalone")
41
+ expect(mode.ownership.local.owned).toBe(false)
42
+
34
43
  const approval = await MetaSynergyControlClient.request<{ mode: string }>({ action: "approval.get" })
35
44
  expect(approval.mode).toBe("manual")
36
45
 
46
+ const managed = await MetaSynergyControlClient.request<{
47
+ mode: string
48
+ ownership: { local: { owned: boolean; activeOwnerID: string | null } }
49
+ connectionStatus: string
50
+ }>({ action: "runtime.enter_managed" })
51
+ expect(managed.mode).toBe("managed")
52
+ expect(managed.ownership.local.owned).toBe(true)
53
+ expect(managed.ownership.local.activeOwnerID).toMatch(/^env_/)
54
+
55
+ expect(managed.connectionStatus).toBe("disconnected")
56
+
57
+ const standalone = await MetaSynergyControlClient.request<{
58
+ mode: string
59
+ ownership: { local: { owned: boolean; activeOwnerID: string | null } }
60
+ connectionStatus: string
61
+ }>({ action: "runtime.set_mode", mode: "standalone" })
62
+ expect(standalone.mode).toBe("standalone")
63
+ expect(standalone.ownership.local.owned).toBe(false)
64
+
65
+ const managedAgain = await MetaSynergyControlClient.request<{
66
+ mode: string
67
+ ownership: { local: { owned: boolean; activeOwnerID: string | null } }
68
+ connectionStatus: string
69
+ }>({ action: "runtime.enter_managed" })
70
+ expect(managedAgain.mode).toBe("managed")
71
+ expect(managedAgain.ownership.local.owned).toBe(true)
72
+
37
73
  await MetaSynergyControlClient.request({ action: "approval.set", mode: "trusted-only" })
38
74
  const collaboration = await MetaSynergyControlClient.request<{ enabled: boolean; approvalMode: string }>({
39
75
  action: "collaboration.status",
@@ -53,6 +89,93 @@ describe("meta-synergy control socket", () => {
53
89
  value: "agent_test",
54
90
  })
55
91
  expect(trust.agents).toContain("agent_test")
92
+
93
+ const caller = {
94
+ type: "holos",
95
+ agentID: "agent_test",
96
+ ownerUserID: 42,
97
+ profile: { source: "control-socket-test" },
98
+ }
99
+
100
+ const opened = await MetaSynergyControlClient.request<{
101
+ version: 1
102
+ requestID: string
103
+ ok: true
104
+ tool: "session"
105
+ action: "open"
106
+ result: {
107
+ title: string
108
+ metadata: {
109
+ action: "open"
110
+ status: string
111
+ sessionID?: string
112
+ remoteAgentID?: string
113
+ remoteOwnerUserID?: number
114
+ label?: string
115
+ backend: "remote"
116
+ }
117
+ output: string
118
+ }
119
+ }>({
120
+ action: "meta.execute",
121
+ caller,
122
+ body: {
123
+ version: 1,
124
+ requestID: "req_open",
125
+ envID,
126
+ tool: "session",
127
+ action: "open",
128
+ payload: {
129
+ action: "open",
130
+ label: "local proxy test",
131
+ },
132
+ },
133
+ })
134
+ expect(opened.ok).toBe(true)
135
+ expect(opened.tool).toBe("session")
136
+ expect(opened.action).toBe("open")
137
+ expect(opened.result.metadata.status).toBe("opened")
138
+ expect(opened.result.metadata.remoteAgentID).toBe("agent_test")
139
+ expect(opened.result.metadata.remoteOwnerUserID).toBe(42)
140
+ expect(opened.result.metadata.label).toBe("local proxy test")
141
+ expect(opened.result.metadata.sessionID).toBeTruthy()
142
+
143
+ const listed = await MetaSynergyControlClient.request<{
144
+ version: 1
145
+ requestID: string
146
+ ok: true
147
+ tool: "process"
148
+ action: "list"
149
+ result: {
150
+ title: string
151
+ metadata: {
152
+ action: "list"
153
+ processes?: Array<{ processId: string }>
154
+ hostSessionID: string
155
+ envID: string
156
+ backend: "remote"
157
+ }
158
+ output: string
159
+ }
160
+ }>({
161
+ action: "meta.execute",
162
+ caller,
163
+ body: {
164
+ version: 1,
165
+ requestID: "req_list",
166
+ envID,
167
+ tool: "process",
168
+ action: "list",
169
+ sessionID: opened.result.metadata.sessionID!,
170
+ payload: { action: "list" },
171
+ },
172
+ })
173
+ expect(listed.ok).toBe(true)
174
+ expect(listed.tool).toBe("process")
175
+ expect(listed.action).toBe("list")
176
+ expect(listed.result.metadata.action).toBe("list")
177
+ expect(listed.result.metadata.envID).toBe(envID)
178
+ expect(listed.result.metadata.backend).toBe("remote")
56
179
  } finally {
57
180
  await runtime.control.stop()
58
181
  }
@@ -0,0 +1,117 @@
1
+ import { afterEach, describe, expect, test } from "bun:test"
2
+ import { access, mkdtemp, mkdir, readFile, writeFile } from "node:fs/promises"
3
+ import os from "node:os"
4
+ import path from "node:path"
5
+ import process from "node:process"
6
+ import { MetaSynergyHolosAuth } from "../src/holos/auth"
7
+ import { MetaSynergyStore } from "../src/state/store"
8
+
9
+ async function createTempRoot() {
10
+ return await mkdtemp(path.join(os.tmpdir(), "meta-synergy-auth-test-"))
11
+ }
12
+
13
+ describe("meta-synergy holos auth", () => {
14
+ let originalMetaHome: string | undefined
15
+ let originalSynergyHome: string | undefined
16
+
17
+ afterEach(() => {
18
+ if (originalMetaHome === undefined) delete process.env.META_SYNERGY_HOME
19
+ else process.env.META_SYNERGY_HOME = originalMetaHome
20
+
21
+ if (originalSynergyHome === undefined) delete process.env.SYNERGY_TEST_HOME
22
+ else process.env.SYNERGY_TEST_HOME = originalSynergyHome
23
+ })
24
+
25
+ test("loads shared synergy holos credentials", async () => {
26
+ originalMetaHome = process.env.META_SYNERGY_HOME
27
+ originalSynergyHome = process.env.SYNERGY_TEST_HOME
28
+
29
+ const metaRoot = await createTempRoot()
30
+ const synergyHome = await createTempRoot()
31
+ process.env.META_SYNERGY_HOME = metaRoot
32
+ process.env.SYNERGY_TEST_HOME = synergyHome
33
+
34
+ const sharedPath = MetaSynergyHolosAuth.sharedAuthPath()
35
+ await mkdir(path.dirname(sharedPath), { recursive: true })
36
+ await writeFile(
37
+ sharedPath,
38
+ JSON.stringify({ holos: { type: "holos", agentId: "agent_shared", agentSecret: "secret_shared" } }, null, 2),
39
+ )
40
+
41
+ await expect(MetaSynergyHolosAuth.inspect()).resolves.toEqual({
42
+ auth: {
43
+ agentID: "agent_shared",
44
+ agentSecret: "secret_shared",
45
+ },
46
+ source: "shared",
47
+ })
48
+ })
49
+
50
+ test("falls back to legacy auth and migrates it to shared store", async () => {
51
+ originalMetaHome = process.env.META_SYNERGY_HOME
52
+ originalSynergyHome = process.env.SYNERGY_TEST_HOME
53
+
54
+ const metaRoot = await createTempRoot()
55
+ const synergyHome = await createTempRoot()
56
+ process.env.META_SYNERGY_HOME = metaRoot
57
+ process.env.SYNERGY_TEST_HOME = synergyHome
58
+
59
+ await MetaSynergyStore.saveLegacyAuth({ agentID: "agent_legacy", agentSecret: "secret_legacy" })
60
+
61
+ await expect(MetaSynergyHolosAuth.inspect()).resolves.toEqual({
62
+ auth: {
63
+ agentID: "agent_legacy",
64
+ agentSecret: "secret_legacy",
65
+ },
66
+ source: "legacy-migrated",
67
+ })
68
+
69
+ const sharedPath = MetaSynergyHolosAuth.sharedAuthPath()
70
+ const shared = JSON.parse(await readFile(sharedPath, "utf8")) as {
71
+ holos: { type: string; agentId: string; agentSecret: string }
72
+ }
73
+
74
+ expect(shared.holos).toEqual({
75
+ type: "holos",
76
+ agentId: "agent_legacy",
77
+ agentSecret: "secret_legacy",
78
+ })
79
+ })
80
+
81
+ test("clear removes holos credentials from shared and legacy stores", async () => {
82
+ originalMetaHome = process.env.META_SYNERGY_HOME
83
+ originalSynergyHome = process.env.SYNERGY_TEST_HOME
84
+
85
+ const metaRoot = await createTempRoot()
86
+ const synergyHome = await createTempRoot()
87
+ process.env.META_SYNERGY_HOME = metaRoot
88
+ process.env.SYNERGY_TEST_HOME = synergyHome
89
+
90
+ await MetaSynergyStore.saveLegacyAuth({ agentID: "agent_clear", agentSecret: "secret_clear" })
91
+
92
+ const sharedPath = MetaSynergyHolosAuth.sharedAuthPath()
93
+ await mkdir(path.dirname(sharedPath), { recursive: true })
94
+ await writeFile(
95
+ sharedPath,
96
+ JSON.stringify(
97
+ {
98
+ another: { type: "token", value: "keep-me" },
99
+ holos: { type: "holos", agentId: "agent_clear", agentSecret: "secret_clear" },
100
+ },
101
+ null,
102
+ 2,
103
+ ),
104
+ )
105
+
106
+ await MetaSynergyHolosAuth.clear()
107
+
108
+ await expect(MetaSynergyHolosAuth.inspect()).resolves.toEqual({
109
+ auth: undefined,
110
+ source: null,
111
+ })
112
+
113
+ await expect(access(MetaSynergyStore.legacyAuthPath())).rejects.toThrow()
114
+ await expect(readFile(sharedPath, "utf8")).resolves.toContain('"another"')
115
+ await expect(readFile(sharedPath, "utf8")).resolves.not.toContain('"holos"')
116
+ })
117
+ })
@@ -0,0 +1,58 @@
1
+ import { afterEach, describe, expect, test } from "bun:test"
2
+ import { mkdtemp, readFile, writeFile } from "node:fs/promises"
3
+ import os from "node:os"
4
+ import path from "node:path"
5
+ import process from "node:process"
6
+ import { MetaSynergyMigrationRunner } from "../src/migration"
7
+ import { MetaSynergyStore } from "../src/state/store"
8
+
9
+ async function createTempRoot() {
10
+ return await mkdtemp(path.join(os.tmpdir(), "meta-synergy-migration-test-"))
11
+ }
12
+
13
+ describe("meta-synergy migration runner", () => {
14
+ let originalMetaHome: string | undefined
15
+
16
+ afterEach(() => {
17
+ if (originalMetaHome === undefined) delete process.env.META_SYNERGY_HOME
18
+ else process.env.META_SYNERGY_HOME = originalMetaHome
19
+ })
20
+
21
+ test("normalizes persisted state and records migration", async () => {
22
+ originalMetaHome = process.env.META_SYNERGY_HOME
23
+ const root = await createTempRoot()
24
+ process.env.META_SYNERGY_HOME = root
25
+
26
+ await writeFile(
27
+ MetaSynergyStore.statePath(),
28
+ JSON.stringify({
29
+ collaborationEnabled: true,
30
+ approvalMode: "invalid",
31
+ trusted: { agentIDs: ["a", "a"], ownerUserIDs: [1, 1] },
32
+ pendingRequests: [{ id: "r1", callerAgentID: "agent", callerOwnerUserID: 7, requestedAt: 1, status: "weird" }],
33
+ blockedAgentIDs: ["b", "b"],
34
+ connectionStatus: "mystery",
35
+ service: { desiredState: "maybe", runtimeStatus: "wat", pid: "oops", printLogs: true },
36
+ logs: { filePath: "" },
37
+ }),
38
+ )
39
+
40
+ await MetaSynergyMigrationRunner.run()
41
+
42
+ const state = await MetaSynergyStore.loadState()
43
+ expect(state.runtimeMode).toBe("standalone")
44
+ expect(state.ownerRegistry.local.ownerIDs).toEqual([])
45
+ expect(state.approvalMode).toBe("manual")
46
+ expect(state.blockedAgentIDs).toEqual(["b"])
47
+ expect(state.trusted.agentIDs).toEqual(["a"])
48
+ expect(state.trusted.ownerUserIDs).toEqual([1])
49
+ expect(state.connectionStatus).toBe("disconnected")
50
+ expect(state.service.desiredState).toBe("stopped")
51
+ expect(state.service.runtimeStatus).toBe("stopped")
52
+ expect(state.service.pid).toBeUndefined()
53
+ expect(state.pendingRequests[0]?.status).toBe("pending")
54
+
55
+ const log = JSON.parse(await readFile(MetaSynergyStore.migrationLogPath(), "utf8")) as Record<string, number>
56
+ expect(typeof log["20260408-normalize-state"]).toBe("number")
57
+ })
58
+ })
@@ -0,0 +1,111 @@
1
+ import { afterAll, beforeEach, describe, expect, test } from "bun:test"
2
+ import { mkdtemp, rm, writeFile } from "node:fs/promises"
3
+ import os from "node:os"
4
+ import path from "node:path"
5
+ import process from "node:process"
6
+ import { MetaSynergyRuntime } from "../src/runtime"
7
+ import { MetaSynergyStore } from "../src/state/store"
8
+
9
+ const originalHome = process.env.META_SYNERGY_HOME
10
+ const tempRoots: string[] = []
11
+
12
+ beforeEach(async () => {
13
+ const root = await mkdtemp(path.join(os.tmpdir(), "meta-synergy-managed-test-"))
14
+ tempRoots.push(root)
15
+ process.env.META_SYNERGY_HOME = root
16
+ })
17
+
18
+ afterAll(async () => {
19
+ if (originalHome === undefined) {
20
+ delete process.env.META_SYNERGY_HOME
21
+ } else {
22
+ process.env.META_SYNERGY_HOME = originalHome
23
+ }
24
+ await Promise.all(tempRoots.map((root) => rm(root, { recursive: true, force: true })))
25
+ })
26
+
27
+ describe("meta-synergy managed mode", () => {
28
+ test("startup stays healthy without Holos auth or websocket", async () => {
29
+ const state = await MetaSynergyStore.loadState()
30
+ state.runtimeMode = "managed"
31
+ state.ownerRegistry.local.activeOwnerID = "synergy:test"
32
+ state.ownerRegistry.local.ownerIDs = ["synergy:test"]
33
+ state.ownerRegistry.local.leaseExpiresAt = Date.now() + 60_000
34
+ await MetaSynergyStore.saveState(state)
35
+ await writeFile(
36
+ MetaSynergyStore.ownerRegistryPath(),
37
+ JSON.stringify(
38
+ {
39
+ local: {
40
+ ownerIDs: ["synergy:test"],
41
+ activeOwnerID: "synergy:test",
42
+ leaseExpiresAt: Date.now() + 60_000,
43
+ },
44
+ },
45
+ null,
46
+ 2,
47
+ ) + "\n",
48
+ )
49
+
50
+ const runtime = await MetaSynergyRuntime.create()
51
+ const originalLogin = runtime.login.bind(runtime)
52
+ let loginCalled = false
53
+ runtime.login = async () => {
54
+ loginCalled = true
55
+ return await originalLogin()
56
+ }
57
+
58
+ const startPromise = runtime.start()
59
+ await new Promise((resolve) => setTimeout(resolve, 200))
60
+
61
+ expect(loginCalled).toBe(false)
62
+ expect(runtime.state?.runtimeMode).toBe("managed")
63
+ expect(runtime.state?.connectionStatus).toBe("disconnected")
64
+ expect(runtime.state?.service.runtimeStatus).toBe("running")
65
+ expect(runtime.state?.ownerRegistry.local.activeOwnerID).toBe("synergy:test")
66
+
67
+ const status = await runtime.getStatusPayload()
68
+ expect(status.mode).toBe("managed")
69
+ expect(status.auth.loggedIn).toBe(true)
70
+ expect(status.auth.source).toBe("shared")
71
+ expect(status.auth.hiddenReason).toBe("managed")
72
+ expect(status.ownership.local.owned).toBe(true)
73
+
74
+ const reconnect = await runtime.reconnect()
75
+ expect(reconnect.requested).toBe(false)
76
+ expect(reconnect.reason).toBe("Holos is disabled in managed mode")
77
+
78
+ await runtime.stopServerProcess()
79
+ await Promise.race([
80
+ startPromise,
81
+ new Promise((_, reject) => setTimeout(() => reject(new Error("runtime.start did not settle after stop")), 2_000)),
82
+ ])
83
+ })
84
+
85
+ test("startup recovers managed state without an active owner back to standalone", async () => {
86
+ const state = await MetaSynergyStore.loadState()
87
+ state.runtimeMode = "managed"
88
+ state.ownerRegistry.local.activeOwnerID = undefined
89
+ state.ownerRegistry.local.ownerIDs = []
90
+ state.ownerRegistry.local.leaseExpiresAt = undefined
91
+ await MetaSynergyStore.saveState(state)
92
+ await writeFile(
93
+ MetaSynergyStore.ownerRegistryPath(),
94
+ JSON.stringify(
95
+ {
96
+ local: {
97
+ ownerIDs: [],
98
+ activeOwnerID: null,
99
+ leaseExpiresAt: null,
100
+ },
101
+ },
102
+ null,
103
+ 2,
104
+ ) + "\n",
105
+ )
106
+
107
+ const runtime = await MetaSynergyRuntime.create()
108
+ expect(runtime.state?.runtimeMode).toBe("standalone")
109
+ expect(runtime.state?.ownerRegistry.local.activeOwnerID).toBeUndefined()
110
+ })
111
+ })
package/script/publish.ts DELETED
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { Script } from "@ericsanchezok/synergy-script"
3
- import { $ } from "bun"
4
-
5
- const dir = new URL("..", import.meta.url).pathname
6
- process.chdir(dir)
7
-
8
- await $`bun tsc`
9
- const pkg = await import("../package.json").then((m) => m.default)
10
- const original = JSON.parse(JSON.stringify(pkg))
11
- for (const [key, value] of Object.entries(pkg.exports)) {
12
- const source = typeof value === "string" ? value : (value as { import?: string }).import
13
- if (!source || typeof source !== "string") continue
14
- const file = source.replace("./src/", "./dist/").replace(".ts", "").replace(".js", "")
15
- // @ts-ignore
16
- pkg.exports[key] = {
17
- import: file + ".js",
18
- types: file + ".d.ts",
19
- }
20
- }
21
- await Bun.write("package.json", JSON.stringify(pkg, null, 2))
22
-
23
- try {
24
- if (await Script.npmVersionExists(pkg.name, Script.version)) {
25
- console.log(`${pkg.name}@${Script.version} already published, skipping`)
26
- } else {
27
- const NPM_REGISTRY = "https://registry.npmjs.org"
28
- await $`rm -f *.tgz`.nothrow()
29
- await $`bun pm pack`
30
- const tgz = (await $`ls *.tgz`.text()).trim()
31
- const authFlag = process.env.NPM_TOKEN ? `--//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}` : ""
32
- await Script.retry(
33
- () => $`npm publish ${tgz} --tag ${Script.channel} --registry ${NPM_REGISTRY} --access public ${authFlag}`,
34
- )
35
- }
36
- } finally {
37
- await Bun.write("package.json", JSON.stringify(original, null, 2))
38
- }