@livestore/cli 0.5.0-dev.0 → 0.5.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/fixtures/mock-config.d.ts +3 -2
- package/dist/__tests__/fixtures/mock-config.d.ts.map +1 -1
- package/dist/__tests__/fixtures/mock-config.js +14 -4
- package/dist/__tests__/fixtures/mock-config.js.map +1 -1
- package/dist/__tests__/sync-operations.test.js +13 -3
- package/dist/__tests__/sync-operations.test.js.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/commands/__fixtures__/mcp-protocol-server.js +2 -2
- package/dist/commands/__fixtures__/mcp-protocol-server.js.map +1 -1
- package/dist/commands/import-export.d.ts +3 -3
- package/dist/commands/import-export.js +11 -11
- package/dist/commands/mcp-coach.d.ts +2 -2
- package/dist/commands/mcp-coach.d.ts.map +1 -1
- package/dist/commands/mcp-coach.js +3 -3
- package/dist/commands/mcp-coach.js.map +1 -1
- package/dist/commands/mcp-protocols.d.ts +2 -2
- package/dist/commands/mcp-protocols.d.ts.map +1 -1
- package/dist/commands/mcp-protocols.js +1 -1
- package/dist/commands/mcp-protocols.js.map +1 -1
- package/dist/commands/mcp-protocols.test.js +1 -1
- package/dist/commands/mcp-protocols.test.js.map +1 -1
- package/dist/commands/mcp-stdio.test.js.map +1 -1
- package/dist/commands/mcp-tool-handlers.d.ts +1 -1
- package/dist/commands/mcp-tool-handlers.d.ts.map +1 -1
- package/dist/commands/mcp-tool-handlers.js +9 -9
- package/dist/commands/mcp-tool-handlers.js.map +1 -1
- package/dist/commands/mcp-tools-defs.d.ts +26 -26
- package/dist/commands/mcp-tools-defs.d.ts.map +1 -1
- package/dist/commands/mcp-tools-defs.js +7 -7
- package/dist/commands/mcp-tools-defs.js.map +1 -1
- package/dist/commands/mcp-tools-defs.test.js +2 -2
- package/dist/commands/mcp-tools-defs.test.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +13 -13
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/new-project.d.ts +1 -1
- package/dist/commands/new-project.d.ts.map +1 -1
- package/dist/commands/new-project.js +9 -9
- package/dist/commands/new-project.js.map +1 -1
- package/dist/mcp-runtime/runtime.d.ts +3 -3
- package/dist/mcp-runtime/runtime.d.ts.map +1 -1
- package/dist/mcp-runtime/runtime.js +1 -1
- package/dist/mod.js +1 -1
- package/dist/module-loader.d.ts.map +1 -1
- package/dist/module-loader.js +3 -3
- package/dist/module-loader.js.map +1 -1
- package/dist/package-manager.d.ts +3 -3
- package/dist/package-manager.d.ts.map +1 -1
- package/dist/package-manager.test.js +1 -1
- package/dist/sync-operations.d.ts +1 -1
- package/dist/sync-operations.d.ts.map +1 -1
- package/dist/sync-operations.js +6 -4
- package/dist/sync-operations.js.map +1 -1
- package/package.json +43 -43
- package/src/__tests__/fixtures/.gitignore +1 -0
- package/src/__tests__/fixtures/mock-config.ts +16 -5
- package/src/__tests__/sync-operations.test.ts +16 -1
- package/src/bin.ts +0 -0
- package/src/cli.ts +1 -1
- package/src/commands/__fixtures__/mcp-protocol-server.ts +1 -1
- package/src/commands/import-export.ts +10 -10
- package/src/commands/mcp-coach.ts +3 -3
- package/src/commands/mcp-protocols.ts +1 -1
- package/src/commands/mcp-tool-handlers.ts +1 -1
- package/src/commands/mcp-tools-defs.test.ts +1 -1
- package/src/commands/mcp-tools-defs.ts +6 -6
- package/src/commands/mcp.ts +4 -2
- package/src/commands/new-project.ts +8 -8
- package/src/module-loader.ts +3 -4
- package/src/sync-operations.ts +11 -4
package/package.json
CHANGED
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$genie": {
|
|
3
|
+
"source": "package.json.genie.ts",
|
|
4
|
+
"warning": "DO NOT EDIT - changes will be overwritten",
|
|
5
|
+
"workspaceClosureDirs": [
|
|
6
|
+
"packages/@livestore/adapter-node",
|
|
7
|
+
"packages/@livestore/cli",
|
|
8
|
+
"repos/livestore/packages/@livestore/adapter-web",
|
|
9
|
+
"repos/livestore/packages/@livestore/common",
|
|
10
|
+
"repos/livestore/packages/@livestore/common-cf",
|
|
11
|
+
"repos/livestore/packages/@livestore/livestore",
|
|
12
|
+
"repos/livestore/packages/@livestore/peer-deps",
|
|
13
|
+
"repos/livestore/packages/@livestore/sqlite-wasm",
|
|
14
|
+
"repos/livestore/packages/@livestore/utils",
|
|
15
|
+
"repos/livestore/packages/@livestore/utils-dev",
|
|
16
|
+
"repos/livestore/packages/@livestore/wa-sqlite",
|
|
17
|
+
"repos/livestore/packages/@livestore/webmesh"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
2
20
|
"name": "@livestore/cli",
|
|
3
|
-
"version": "0.5.0-dev.
|
|
21
|
+
"version": "0.5.0-dev.1",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"sideEffects": false,
|
|
4
24
|
"license": "Apache-2.0",
|
|
5
25
|
"repository": {
|
|
6
26
|
"type": "git",
|
|
7
27
|
"url": "git+https://github.com/livestorejs/livestore-contrib.git"
|
|
8
28
|
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./dist/mod.js"
|
|
31
|
+
},
|
|
9
32
|
"bin": {
|
|
10
33
|
"livestore": "./dist/bin.js"
|
|
11
34
|
},
|
|
@@ -14,59 +37,36 @@
|
|
|
14
37
|
"package.json",
|
|
15
38
|
"src"
|
|
16
39
|
],
|
|
17
|
-
"type": "module",
|
|
18
|
-
"sideEffects": false,
|
|
19
|
-
"exports": {
|
|
20
|
-
".": "./dist/mod.js"
|
|
21
|
-
},
|
|
22
|
-
"publishConfig": {
|
|
23
|
-
"access": "public"
|
|
24
|
-
},
|
|
25
40
|
"dependencies": {
|
|
26
|
-
"@effect/ai-openai": "4.0.
|
|
27
|
-
"@effect/opentelemetry": "4.0.
|
|
28
|
-
"@livestore/adapter-node": "0.5.0-dev.
|
|
29
|
-
"@livestore/common": "0.5.0-dev.
|
|
30
|
-
"@livestore/livestore": "0.5.0-dev.
|
|
31
|
-
"@livestore/peer-deps": "0.5.0-dev.
|
|
32
|
-
"@livestore/utils": "0.5.0-dev.
|
|
33
|
-
"effect": "4.0.
|
|
41
|
+
"@effect/ai-openai": "4.0.3",
|
|
42
|
+
"@effect/opentelemetry": "4.0.3",
|
|
43
|
+
"@livestore/adapter-node": "0.5.0-dev.1",
|
|
44
|
+
"@livestore/common": "0.5.0-dev.1",
|
|
45
|
+
"@livestore/livestore": "0.5.0-dev.1",
|
|
46
|
+
"@livestore/peer-deps": "0.5.0-dev.1",
|
|
47
|
+
"@livestore/utils": "0.5.0-dev.1",
|
|
48
|
+
"effect": "4.0.3"
|
|
34
49
|
},
|
|
35
50
|
"devDependencies": {
|
|
36
|
-
"@livestore/utils-dev": "0.5.0-dev.
|
|
51
|
+
"@livestore/utils-dev": "0.5.0-dev.1",
|
|
37
52
|
"@types/node": "25.3.3",
|
|
38
|
-
"typescript": "
|
|
53
|
+
"typescript": "7.0.2",
|
|
39
54
|
"vitest": "4.1.9"
|
|
40
55
|
},
|
|
41
56
|
"peerDependencies": {
|
|
42
|
-
"@effect/opentelemetry": "^4.0.
|
|
43
|
-
"@effect/platform-browser": "^4.0.
|
|
44
|
-
"@effect/platform-bun": "^4.0.
|
|
45
|
-
"@effect/platform-node": "^4.0.
|
|
46
|
-
"@effect/platform-node-shared": "^4.0.
|
|
47
|
-
"@effect/vitest": "^4.0.
|
|
57
|
+
"@effect/opentelemetry": "^4.0.3",
|
|
58
|
+
"@effect/platform-browser": "^4.0.3",
|
|
59
|
+
"@effect/platform-bun": "^4.0.3",
|
|
60
|
+
"@effect/platform-node": "^4.0.3",
|
|
61
|
+
"@effect/platform-node-shared": "^4.0.3",
|
|
62
|
+
"@effect/vitest": "^4.0.3",
|
|
48
63
|
"@opentelemetry/api": "^1.9.0",
|
|
49
64
|
"@opentelemetry/resources": "^2.2.0",
|
|
50
65
|
"@standard-schema/spec": "^1.1.0",
|
|
51
|
-
"effect": "^4.0.
|
|
66
|
+
"effect": "^4.0.3"
|
|
52
67
|
},
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"warning": "DO NOT EDIT - changes will be overwritten",
|
|
56
|
-
"workspaceClosureDirs": [
|
|
57
|
-
"packages/@livestore/adapter-node",
|
|
58
|
-
"packages/@livestore/cli",
|
|
59
|
-
"repos/livestore/packages/@livestore/adapter-web",
|
|
60
|
-
"repos/livestore/packages/@livestore/common",
|
|
61
|
-
"repos/livestore/packages/@livestore/common-cf",
|
|
62
|
-
"repos/livestore/packages/@livestore/livestore",
|
|
63
|
-
"repos/livestore/packages/@livestore/peer-deps",
|
|
64
|
-
"repos/livestore/packages/@livestore/sqlite-wasm",
|
|
65
|
-
"repos/livestore/packages/@livestore/utils",
|
|
66
|
-
"repos/livestore/packages/@livestore/utils-dev",
|
|
67
|
-
"repos/livestore/packages/@livestore/wa-sqlite",
|
|
68
|
-
"repos/livestore/packages/@livestore/webmesh"
|
|
69
|
-
]
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"access": "public"
|
|
70
70
|
},
|
|
71
71
|
"scripts": {
|
|
72
72
|
"build": "tsc",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.tmp-test-configs/
|
|
@@ -4,7 +4,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
|
4
4
|
import { Events, makeSchema, State } from '@livestore/common/schema'
|
|
5
5
|
import type { MockSyncBackend } from '@livestore/common/sync'
|
|
6
6
|
import { EventFactory } from '@livestore/common/testing'
|
|
7
|
-
import { Effect, FileSystem, type Queue, Schema } from '@livestore/utils/effect'
|
|
7
|
+
import { Effect, FileSystem, type Queue, Schema, type SubscriptionRef } from '@livestore/utils/effect'
|
|
8
8
|
|
|
9
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
10
10
|
|
|
@@ -49,10 +49,11 @@ const makeTempConfig = () => {
|
|
|
49
49
|
const moduleSource = `
|
|
50
50
|
import { schema } from ${JSON.stringify(schemaModuleUrl)}
|
|
51
51
|
import { makeMockSyncBackend } from '@livestore/common/sync'
|
|
52
|
-
import { Effect, Queue } from '@livestore/utils/effect'
|
|
52
|
+
import { Effect, Queue, SubscriptionRef } from '@livestore/utils/effect'
|
|
53
53
|
|
|
54
54
|
export const mockBackend = await Effect.runPromise(Effect.scoped(makeMockSyncBackend({ startConnected: true })))
|
|
55
55
|
export const connectionEvents = await Effect.runPromise(Queue.make<'connect' | 'disconnect'>())
|
|
56
|
+
export const disconnectShouldFail = await Effect.runPromise(SubscriptionRef.make(false))
|
|
56
57
|
|
|
57
58
|
export { schema }
|
|
58
59
|
|
|
@@ -60,7 +61,11 @@ export const syncBackend = (_args) =>
|
|
|
60
61
|
mockBackend.makeSyncBackend.pipe(
|
|
61
62
|
Effect.tap(() => Queue.offer(connectionEvents, 'connect')),
|
|
62
63
|
Effect.map((backend) => {
|
|
63
|
-
const disconnect =
|
|
64
|
+
const disconnect = SubscriptionRef.get(disconnectShouldFail).pipe(
|
|
65
|
+
Effect.flatMap((shouldFail) =>
|
|
66
|
+
shouldFail ? Effect.fail(new Error('disconnect failed')) : (backend.disconnect ?? Effect.void),
|
|
67
|
+
),
|
|
68
|
+
)
|
|
64
69
|
return {
|
|
65
70
|
...backend,
|
|
66
71
|
disconnect: disconnect.pipe(Effect.tap(() => Queue.offer(connectionEvents, 'disconnect'))),
|
|
@@ -93,14 +98,20 @@ export const useMockConfig = Effect.acquireRelease(
|
|
|
93
98
|
})) as {
|
|
94
99
|
mockBackend: MockSyncBackend
|
|
95
100
|
connectionEvents: Queue.Queue<'connect' | 'disconnect'>
|
|
101
|
+
disconnectShouldFail: SubscriptionRef.SubscriptionRef<boolean>
|
|
96
102
|
}
|
|
97
103
|
|
|
98
|
-
return {
|
|
104
|
+
return {
|
|
105
|
+
configPath: tempPath,
|
|
106
|
+
mockBackend: mod.mockBackend,
|
|
107
|
+
connectionEvents: mod.connectionEvents,
|
|
108
|
+
disconnectShouldFail: mod.disconnectShouldFail,
|
|
109
|
+
}
|
|
99
110
|
}),
|
|
100
111
|
({ configPath }) =>
|
|
101
112
|
Effect.gen(function* () {
|
|
102
113
|
const fs = yield* FileSystem.FileSystem
|
|
103
|
-
yield* fs.remove(configPath, { recursive: false }).pipe(Effect.
|
|
114
|
+
yield* fs.remove(configPath, { recursive: false }).pipe(Effect.ignore)
|
|
104
115
|
}),
|
|
105
116
|
)
|
|
106
117
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, FetchHttpClient, Layer, Queue, Stream } from '@livestore/utils/effect'
|
|
1
|
+
import { Effect, FetchHttpClient, Layer, type Queue, Stream, SubscriptionRef } from '@livestore/utils/effect'
|
|
2
2
|
import { PlatformNode } from '@livestore/utils/node'
|
|
3
3
|
import { Vitest } from '@livestore/utils-dev/node-vitest'
|
|
4
4
|
import { expect } from 'vitest'
|
|
@@ -46,6 +46,21 @@ Vitest.describe('sync-operations', { timeout: 10_000 }, () => {
|
|
|
46
46
|
}).pipe(withTestCtx(test)),
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
+
Vitest.live('preserves a successful export when backend disconnect fails', (test: Vitest.TestContext) =>
|
|
50
|
+
Effect.gen(function* () {
|
|
51
|
+
const { configPath, disconnectShouldFail } = yield* useMockConfig
|
|
52
|
+
yield* SubscriptionRef.set(disconnectShouldFail, true)
|
|
53
|
+
|
|
54
|
+
const result = yield* pullEventsFromSyncBackend({
|
|
55
|
+
configPath,
|
|
56
|
+
storeId,
|
|
57
|
+
clientId,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
expect(result.eventCount).toBe(0)
|
|
61
|
+
}).pipe(withTestCtx(test)),
|
|
62
|
+
)
|
|
63
|
+
|
|
49
64
|
Vitest.live('fails import when backend is not empty', (test: Vitest.TestContext) =>
|
|
50
65
|
Effect.gen(function* () {
|
|
51
66
|
const { mockBackend, connectionEvents, configPath } = yield* useMockConfig
|
package/src/bin.ts
CHANGED
|
File without changes
|
package/src/cli.ts
CHANGED
|
@@ -5,5 +5,5 @@ import { mcpCommand } from './commands/mcp.ts'
|
|
|
5
5
|
import { createCommand } from './commands/new-project.ts'
|
|
6
6
|
|
|
7
7
|
export const command = Cli.Command.make('livestore', {
|
|
8
|
-
verbose: Cli.Flag.
|
|
8
|
+
verbose: Cli.Flag.Boolean('verbose').pipe(Cli.Flag.withDefault(false)),
|
|
9
9
|
}).pipe(Cli.Command.withSubcommands([mcpCommand, createCommand, syncCommand]))
|
|
@@ -171,19 +171,19 @@ const importEvents = ({
|
|
|
171
171
|
export const exportCommand = Cli.Command.make(
|
|
172
172
|
'export',
|
|
173
173
|
{
|
|
174
|
-
config: Cli.Flag.
|
|
174
|
+
config: Cli.Flag.String('config').pipe(
|
|
175
175
|
Cli.Flag.withAlias('c'),
|
|
176
176
|
Cli.Flag.withDescription('Path to the config module that exports schema and syncBackend'),
|
|
177
177
|
),
|
|
178
|
-
storeId: Cli.Flag.
|
|
178
|
+
storeId: Cli.Flag.String('store-id').pipe(
|
|
179
179
|
Cli.Flag.withAlias('i'),
|
|
180
180
|
Cli.Flag.withDescription('Store identifier'),
|
|
181
181
|
),
|
|
182
|
-
clientId: Cli.Flag.
|
|
182
|
+
clientId: Cli.Flag.String('client-id').pipe(
|
|
183
183
|
Cli.Flag.withDefault('cli-export'),
|
|
184
184
|
Cli.Flag.withDescription('Client identifier for the sync connection'),
|
|
185
185
|
),
|
|
186
|
-
output: Cli.Argument.
|
|
186
|
+
output: Cli.Argument.String('file').pipe(Cli.Argument.withDescription('Output JSON file path')),
|
|
187
187
|
},
|
|
188
188
|
Effect.fn(function* ({
|
|
189
189
|
config,
|
|
@@ -218,28 +218,28 @@ export const exportCommand = Cli.Command.make(
|
|
|
218
218
|
export const importCommand = Cli.Command.make(
|
|
219
219
|
'import',
|
|
220
220
|
{
|
|
221
|
-
config: Cli.Flag.
|
|
221
|
+
config: Cli.Flag.String('config').pipe(
|
|
222
222
|
Cli.Flag.withAlias('c'),
|
|
223
223
|
Cli.Flag.withDescription('Path to the config module that exports schema and syncBackend'),
|
|
224
224
|
),
|
|
225
|
-
storeId: Cli.Flag.
|
|
225
|
+
storeId: Cli.Flag.String('store-id').pipe(
|
|
226
226
|
Cli.Flag.withAlias('i'),
|
|
227
227
|
Cli.Flag.withDescription('Store identifier'),
|
|
228
228
|
),
|
|
229
|
-
clientId: Cli.Flag.
|
|
229
|
+
clientId: Cli.Flag.String('client-id').pipe(
|
|
230
230
|
Cli.Flag.withDefault('cli-import'),
|
|
231
231
|
Cli.Flag.withDescription('Client identifier for the sync connection'),
|
|
232
232
|
),
|
|
233
|
-
force: Cli.Flag.
|
|
233
|
+
force: Cli.Flag.Boolean('force').pipe(
|
|
234
234
|
Cli.Flag.withAlias('f'),
|
|
235
235
|
Cli.Flag.withDefault(false),
|
|
236
236
|
Cli.Flag.withDescription('Force import even if store ID does not match'),
|
|
237
237
|
),
|
|
238
|
-
dryRun: Cli.Flag.
|
|
238
|
+
dryRun: Cli.Flag.Boolean('dry-run').pipe(
|
|
239
239
|
Cli.Flag.withDefault(false),
|
|
240
240
|
Cli.Flag.withDescription('Validate the import file without actually importing'),
|
|
241
241
|
),
|
|
242
|
-
input: Cli.Argument.
|
|
242
|
+
input: Cli.Argument.String('file').pipe(Cli.Argument.withDescription('Input JSON file to import')),
|
|
243
243
|
},
|
|
244
244
|
Effect.fn(function* ({
|
|
245
245
|
config,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AiError, LanguageModel, Prompt, Tool } from 'effect/
|
|
1
|
+
import { AiError, LanguageModel, Prompt, Tool } from 'effect/ai'
|
|
2
2
|
import { OpenAiClient, OpenAiLanguageModel } from '@effect/ai-openai'
|
|
3
3
|
|
|
4
4
|
import { Config, Effect, FetchHttpClient, Layer, Schema } from '@livestore/utils/effect'
|
|
@@ -22,7 +22,7 @@ export const coachTool = Tool.make('livestore_coach', {
|
|
|
22
22
|
description: 'AI-generated feedback and recommendations for the code',
|
|
23
23
|
}),
|
|
24
24
|
score: Schema.optional(
|
|
25
|
-
Schema.
|
|
25
|
+
Schema.Finite.annotate({
|
|
26
26
|
description: 'Code quality score from 1-10 (optional)',
|
|
27
27
|
}),
|
|
28
28
|
),
|
|
@@ -39,7 +39,7 @@ export const coachTool = Tool.make('livestore_coach', {
|
|
|
39
39
|
|
|
40
40
|
/** Composed layer: HttpClient → OpenAiClient → LanguageModel */
|
|
41
41
|
const LanguageModelLayer = OpenAiLanguageModel.layer({ model: 'gpt-4o-mini' }).pipe(
|
|
42
|
-
Layer.provide(OpenAiClient.layerConfig({ apiKey: Config.
|
|
42
|
+
Layer.provide(OpenAiClient.layerConfig({ apiKey: Config.Redacted('OPENAI_API_KEY') })),
|
|
43
43
|
Layer.provide(FetchHttpClient.layer),
|
|
44
44
|
)
|
|
45
45
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Tool, Toolkit } from 'effect/
|
|
1
|
+
import { Tool, Toolkit } from 'effect/ai'
|
|
2
2
|
|
|
3
3
|
import { Schema } from '@livestore/utils/effect'
|
|
4
4
|
|
|
@@ -150,7 +150,7 @@ Returns on success:
|
|
|
150
150
|
}),
|
|
151
151
|
success: Schema.Struct({
|
|
152
152
|
rows: Schema.Array(Schema.Record(Schema.String, Schema.Json)),
|
|
153
|
-
rowCount: Schema.
|
|
153
|
+
rowCount: Schema.Finite,
|
|
154
154
|
}),
|
|
155
155
|
}).annotate(Tool.Destructive, false),
|
|
156
156
|
|
|
@@ -188,7 +188,7 @@ Returns on success:
|
|
|
188
188
|
}),
|
|
189
189
|
),
|
|
190
190
|
}),
|
|
191
|
-
success: Schema.Struct({ committed: Schema.
|
|
191
|
+
success: Schema.Struct({ committed: Schema.Finite }),
|
|
192
192
|
}).annotate(Tool.Destructive, true),
|
|
193
193
|
|
|
194
194
|
Tool.make('livestore_instance_status', {
|
|
@@ -213,7 +213,7 @@ Returns when not connected:
|
|
|
213
213
|
storeId: Schema.String,
|
|
214
214
|
clientId: Schema.String,
|
|
215
215
|
sessionId: Schema.String,
|
|
216
|
-
tableCounts: Schema.Record(Schema.String, Schema.
|
|
216
|
+
tableCounts: Schema.Record(Schema.String, Schema.Finite).annotate({
|
|
217
217
|
description: 'Tables in the LiveStore instance with their row count',
|
|
218
218
|
}),
|
|
219
219
|
}),
|
|
@@ -264,7 +264,7 @@ Returns on success:
|
|
|
264
264
|
}),
|
|
265
265
|
success: Schema.Struct({
|
|
266
266
|
storeId: Schema.String,
|
|
267
|
-
eventCount: Schema.
|
|
267
|
+
eventCount: Schema.Finite,
|
|
268
268
|
exportedAt: Schema.String,
|
|
269
269
|
data: Schema.Json.annotate({ description: 'The export file data (can be saved or passed to import)' }),
|
|
270
270
|
}),
|
|
@@ -313,7 +313,7 @@ Returns on success:
|
|
|
313
313
|
}),
|
|
314
314
|
success: Schema.Struct({
|
|
315
315
|
storeId: Schema.String,
|
|
316
|
-
eventCount: Schema.
|
|
316
|
+
eventCount: Schema.Finite,
|
|
317
317
|
dryRun: Schema.Boolean,
|
|
318
318
|
}),
|
|
319
319
|
}).annotate(Tool.Destructive, true),
|
package/src/commands/mcp.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpServer } from 'effect/
|
|
1
|
+
import { McpProtocol, McpServer } from 'effect/ai'
|
|
2
2
|
|
|
3
3
|
import { Effect, Layer, Logger } from '@livestore/utils/effect'
|
|
4
4
|
import { Cli, PlatformNode } from '@livestore/utils/node'
|
|
@@ -91,7 +91,9 @@ const mcpServerCommand = Cli.Command.make(
|
|
|
91
91
|
}).pipe(
|
|
92
92
|
Layer.provide(LivestoreResources),
|
|
93
93
|
Layer.provide(LivestoreTools),
|
|
94
|
-
Layer.provide(
|
|
94
|
+
Layer.provide(
|
|
95
|
+
Layer.merge(Logger.layer([Logger.consolePretty()]), Layer.succeed(Logger.LogToStderr, true)),
|
|
96
|
+
),
|
|
95
97
|
Layer.provide(PlatformNode.NodeStdio.layer),
|
|
96
98
|
Layer.launch,
|
|
97
99
|
)
|
|
@@ -87,7 +87,7 @@ const fetchExamples = (ref: string) =>
|
|
|
87
87
|
|
|
88
88
|
const responseText = yield* response.text
|
|
89
89
|
|
|
90
|
-
const examples = yield* Schema.
|
|
90
|
+
const examples = yield* Schema.decodeEffect(Schema.fromJsonString(GitHubContentsResponseSchema))(
|
|
91
91
|
responseText,
|
|
92
92
|
).pipe(
|
|
93
93
|
Effect.catch(
|
|
@@ -116,7 +116,7 @@ const selectExample = (examples: string[]) =>
|
|
|
116
116
|
return yield* new NoExamplesError({ message: 'No examples available' })
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
const prompt = Cli.Prompt.
|
|
119
|
+
const prompt = Cli.Prompt.Select({
|
|
120
120
|
message: '📦 Select a LiveStore example to create:',
|
|
121
121
|
choices: examples.map((example) => ({
|
|
122
122
|
title: example,
|
|
@@ -213,10 +213,10 @@ const downloadExample = (exampleName: string, ref: string, destinationPath: stri
|
|
|
213
213
|
)
|
|
214
214
|
|
|
215
215
|
// Clean up extract directory
|
|
216
|
-
yield* fs.remove(extractDir, { recursive: true }).pipe(Effect.
|
|
216
|
+
yield* fs.remove(extractDir, { recursive: true }).pipe(Effect.ignore)
|
|
217
217
|
|
|
218
218
|
// Clean up tarball
|
|
219
|
-
yield* fs.remove(tarballPath).pipe(Effect.
|
|
219
|
+
yield* fs.remove(tarballPath).pipe(Effect.ignore)
|
|
220
220
|
|
|
221
221
|
yield* Console.log(`✅ Example "${exampleName}" created successfully at: ${destinationPath}`)
|
|
222
222
|
})
|
|
@@ -224,11 +224,11 @@ const downloadExample = (exampleName: string, ref: string, destinationPath: stri
|
|
|
224
224
|
export const createCommand = Cli.Command.make(
|
|
225
225
|
'create',
|
|
226
226
|
{
|
|
227
|
-
example: Cli.Flag.
|
|
227
|
+
example: Cli.Flag.String('example').pipe(
|
|
228
228
|
Cli.Flag.optional,
|
|
229
229
|
Cli.Flag.withDescription('Example name to create (bypasses interactive selection)'),
|
|
230
230
|
),
|
|
231
|
-
ref: Cli.Flag.
|
|
231
|
+
ref: Cli.Flag.String('ref').pipe(
|
|
232
232
|
Cli.Flag.withAlias('commit'),
|
|
233
233
|
Cli.Flag.withAlias('branch'),
|
|
234
234
|
Cli.Flag.withAlias('tag'),
|
|
@@ -237,7 +237,7 @@ export const createCommand = Cli.Command.make(
|
|
|
237
237
|
'The name of the commit/branch/tag to fetch examples from. Pull requests refs must be fully-formed (e.g., `refs/pull/123/merge`).',
|
|
238
238
|
),
|
|
239
239
|
),
|
|
240
|
-
path: Cli.Argument.
|
|
240
|
+
path: Cli.Argument.String('path').pipe(
|
|
241
241
|
Cli.Argument.optional,
|
|
242
242
|
Cli.Argument.withDescription('Destination path for the new project'),
|
|
243
243
|
),
|
|
@@ -292,7 +292,7 @@ export const createCommand = Cli.Command.make(
|
|
|
292
292
|
const fs = yield* FileSystem.FileSystem
|
|
293
293
|
const packageJsonPath = nodePath.join(destinationPath, 'package.json')
|
|
294
294
|
const packageJsonContent = yield* fs.readFileString(packageJsonPath)
|
|
295
|
-
const runScript = yield* Schema.
|
|
295
|
+
const runScript = yield* Schema.decodeEffect(Schema.fromJsonString(PackageJsonScriptsSchema))(
|
|
296
296
|
packageJsonContent,
|
|
297
297
|
).pipe(
|
|
298
298
|
Effect.map((pkg) => ('dev' in pkg.scripts ? ('dev' as const) : ('start' as const))),
|
package/src/module-loader.ts
CHANGED
|
@@ -79,11 +79,10 @@ export const loadModuleConfig = ({
|
|
|
79
79
|
)
|
|
80
80
|
|
|
81
81
|
const syncPayloadExport = mod?.syncPayload
|
|
82
|
-
const syncPayload =
|
|
82
|
+
const syncPayload =
|
|
83
83
|
syncPayloadExport === undefined
|
|
84
|
-
?
|
|
85
|
-
: Schema.decodeUnknownEffect(syncPayloadSchema)(syncPayloadExport)
|
|
86
|
-
).pipe(UnknownError.mapToUnknownError)
|
|
84
|
+
? undefined
|
|
85
|
+
: yield* Schema.decodeUnknownEffect(syncPayloadSchema)(syncPayloadExport).pipe(UnknownError.mapToUnknownError)
|
|
87
86
|
|
|
88
87
|
return {
|
|
89
88
|
schema,
|
package/src/sync-operations.ts
CHANGED
|
@@ -35,7 +35,7 @@ export const ExportFileSchema = Schema.Struct({
|
|
|
35
35
|
/** ISO timestamp of when the export was created */
|
|
36
36
|
exportedAt: Schema.String,
|
|
37
37
|
/** Total number of events in the export */
|
|
38
|
-
eventCount: Schema.
|
|
38
|
+
eventCount: Schema.Finite,
|
|
39
39
|
/** Array of events in global encoded format */
|
|
40
40
|
events: Schema.Array(LiveStoreEvent.Global.Encoded),
|
|
41
41
|
})
|
|
@@ -125,10 +125,17 @@ export const makeSyncBackend = ({
|
|
|
125
125
|
return syncBackend
|
|
126
126
|
})
|
|
127
127
|
|
|
128
|
+
type SyncBackendWithOptionalDisconnect = SyncBackend.SyncBackend & {
|
|
129
|
+
readonly disconnect?: Effect.Effect<void, UnknownError>
|
|
130
|
+
}
|
|
131
|
+
|
|
128
132
|
const releaseSyncBackend = (syncBackend: SyncBackend.SyncBackend): Effect.Effect<void> => {
|
|
129
|
-
const maybeDisconnect = (syncBackend as
|
|
130
|
-
const releaseEffect =
|
|
131
|
-
|
|
133
|
+
const maybeDisconnect = (syncBackend as SyncBackendWithOptionalDisconnect).disconnect
|
|
134
|
+
const releaseEffect =
|
|
135
|
+
maybeDisconnect !== undefined && Effect.isEffect(maybeDisconnect) === true
|
|
136
|
+
? maybeDisconnect
|
|
137
|
+
: SubscriptionRef.set(syncBackend.isConnected, false)
|
|
138
|
+
return releaseEffect.pipe(Effect.ignore)
|
|
132
139
|
}
|
|
133
140
|
|
|
134
141
|
export interface ExportResult {
|