@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.
- package/README.md +47 -0
- package/install +444 -0
- package/package.json +7 -6
- package/script/build.ts +93 -0
- package/src/cli-backend.ts +118 -16
- package/src/cli.ts +178 -33
- package/src/control/schema.ts +25 -0
- package/src/display.ts +70 -0
- package/src/exec/process-registry.ts +14 -5
- package/src/holos/auth.ts +183 -0
- package/src/holos/login.ts +148 -8
- package/src/inbound/handler.ts +20 -9
- package/src/index.ts +1 -0
- package/src/migration/index.ts +22 -0
- package/src/migration/types.ts +5 -0
- package/src/owner-registry.ts +162 -0
- package/src/runtime.ts +283 -33
- package/src/service.ts +169 -77
- package/src/state/migration.ts +19 -0
- package/src/state/store.ts +53 -7
- package/src/types.ts +8 -0
- package/test/cli-backend-auth.test.ts +86 -0
- package/test/cli-backend-mode.test.ts +49 -0
- package/test/control-socket.test.ts +123 -0
- package/test/holos-auth.test.ts +117 -0
- package/test/migration.test.ts +58 -0
- package/test/runtime-managed-mode.test.ts +111 -0
- package/script/publish.ts +0 -38
|
@@ -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
|
-
}
|