@plures/praxis 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FRAMEWORK.md +420 -0
- package/LICENSE +21 -0
- package/README.md +1310 -0
- package/dist/adapters/cli.d.ts +43 -0
- package/dist/adapters/cli.d.ts.map +1 -0
- package/dist/adapters/cli.js +126 -0
- package/dist/adapters/cli.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +26 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +233 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/cloud.d.ts +27 -0
- package/dist/cli/commands/cloud.d.ts.map +1 -0
- package/dist/cli/commands/cloud.js +232 -0
- package/dist/cli/commands/cloud.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +25 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +168 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +179 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cloud/auth.d.ts +51 -0
- package/dist/cloud/auth.d.ts.map +1 -0
- package/dist/cloud/auth.js +194 -0
- package/dist/cloud/auth.js.map +1 -0
- package/dist/cloud/billing.d.ts +184 -0
- package/dist/cloud/billing.d.ts.map +1 -0
- package/dist/cloud/billing.js +179 -0
- package/dist/cloud/billing.js.map +1 -0
- package/dist/cloud/client.d.ts +39 -0
- package/dist/cloud/client.d.ts.map +1 -0
- package/dist/cloud/client.js +176 -0
- package/dist/cloud/client.js.map +1 -0
- package/dist/cloud/index.d.ts +44 -0
- package/dist/cloud/index.d.ts.map +1 -0
- package/dist/cloud/index.js +44 -0
- package/dist/cloud/index.js.map +1 -0
- package/dist/cloud/marketplace.d.ts +166 -0
- package/dist/cloud/marketplace.d.ts.map +1 -0
- package/dist/cloud/marketplace.js +159 -0
- package/dist/cloud/marketplace.js.map +1 -0
- package/dist/cloud/provisioning.d.ts +110 -0
- package/dist/cloud/provisioning.d.ts.map +1 -0
- package/dist/cloud/provisioning.js +148 -0
- package/dist/cloud/provisioning.js.map +1 -0
- package/dist/cloud/relay/endpoints.d.ts +62 -0
- package/dist/cloud/relay/endpoints.d.ts.map +1 -0
- package/dist/cloud/relay/endpoints.js +217 -0
- package/dist/cloud/relay/endpoints.js.map +1 -0
- package/dist/cloud/relay/health/index.d.ts +5 -0
- package/dist/cloud/relay/health/index.d.ts.map +1 -0
- package/dist/cloud/relay/health/index.js +9 -0
- package/dist/cloud/relay/health/index.js.map +1 -0
- package/dist/cloud/relay/stats/index.d.ts +5 -0
- package/dist/cloud/relay/stats/index.d.ts.map +1 -0
- package/dist/cloud/relay/stats/index.js +9 -0
- package/dist/cloud/relay/stats/index.js.map +1 -0
- package/dist/cloud/relay/sync/index.d.ts +5 -0
- package/dist/cloud/relay/sync/index.d.ts.map +1 -0
- package/dist/cloud/relay/sync/index.js +9 -0
- package/dist/cloud/relay/sync/index.js.map +1 -0
- package/dist/cloud/relay/usage/index.d.ts +5 -0
- package/dist/cloud/relay/usage/index.d.ts.map +1 -0
- package/dist/cloud/relay/usage/index.js +9 -0
- package/dist/cloud/relay/usage/index.js.map +1 -0
- package/dist/cloud/sponsors.d.ts +81 -0
- package/dist/cloud/sponsors.d.ts.map +1 -0
- package/dist/cloud/sponsors.js +130 -0
- package/dist/cloud/sponsors.js.map +1 -0
- package/dist/cloud/types.d.ts +169 -0
- package/dist/cloud/types.d.ts.map +1 -0
- package/dist/cloud/types.js +7 -0
- package/dist/cloud/types.js.map +1 -0
- package/dist/components/index.d.ts +43 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +17 -0
- package/dist/components/index.js.map +1 -0
- package/dist/core/actors.d.ts +95 -0
- package/dist/core/actors.d.ts.map +1 -0
- package/dist/core/actors.js +158 -0
- package/dist/core/actors.js.map +1 -0
- package/dist/core/component/generator.d.ts +122 -0
- package/dist/core/component/generator.d.ts.map +1 -0
- package/dist/core/component/generator.js +307 -0
- package/dist/core/component/generator.js.map +1 -0
- package/dist/core/engine.d.ts +92 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +199 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/introspection.d.ts +141 -0
- package/dist/core/introspection.d.ts.map +1 -0
- package/dist/core/introspection.js +208 -0
- package/dist/core/introspection.js.map +1 -0
- package/dist/core/logic/generator.d.ts +76 -0
- package/dist/core/logic/generator.d.ts.map +1 -0
- package/dist/core/logic/generator.js +339 -0
- package/dist/core/logic/generator.js.map +1 -0
- package/dist/core/pluresdb/generator.d.ts +58 -0
- package/dist/core/pluresdb/generator.d.ts.map +1 -0
- package/dist/core/pluresdb/generator.js +162 -0
- package/dist/core/pluresdb/generator.js.map +1 -0
- package/dist/core/protocol.d.ts +121 -0
- package/dist/core/protocol.d.ts.map +1 -0
- package/dist/core/protocol.js +46 -0
- package/dist/core/protocol.js.map +1 -0
- package/dist/core/rules.d.ts +120 -0
- package/dist/core/rules.d.ts.map +1 -0
- package/dist/core/rules.js +81 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/schema/loader.d.ts +47 -0
- package/dist/core/schema/loader.d.ts.map +1 -0
- package/dist/core/schema/loader.js +189 -0
- package/dist/core/schema/loader.js.map +1 -0
- package/dist/core/schema/normalize.d.ts +72 -0
- package/dist/core/schema/normalize.d.ts.map +1 -0
- package/dist/core/schema/normalize.js +190 -0
- package/dist/core/schema/normalize.js.map +1 -0
- package/dist/core/schema/types.d.ts +370 -0
- package/dist/core/schema/types.d.ts.map +1 -0
- package/dist/core/schema/types.js +161 -0
- package/dist/core/schema/types.js.map +1 -0
- package/dist/dsl/index.d.ts +152 -0
- package/dist/dsl/index.d.ts.map +1 -0
- package/dist/dsl/index.js +132 -0
- package/dist/dsl/index.js.map +1 -0
- package/dist/dsl.d.ts +124 -0
- package/dist/dsl.d.ts.map +1 -0
- package/dist/dsl.js +130 -0
- package/dist/dsl.js.map +1 -0
- package/dist/examples/advanced-todo/index.d.ts +55 -0
- package/dist/examples/advanced-todo/index.d.ts.map +1 -0
- package/dist/examples/advanced-todo/index.js +222 -0
- package/dist/examples/advanced-todo/index.js.map +1 -0
- package/dist/examples/auth-basic/index.d.ts +17 -0
- package/dist/examples/auth-basic/index.d.ts.map +1 -0
- package/dist/examples/auth-basic/index.js +122 -0
- package/dist/examples/auth-basic/index.js.map +1 -0
- package/dist/examples/cart/index.d.ts +19 -0
- package/dist/examples/cart/index.d.ts.map +1 -0
- package/dist/examples/cart/index.js +202 -0
- package/dist/examples/cart/index.js.map +1 -0
- package/dist/examples/hero-ecommerce/index.d.ts +39 -0
- package/dist/examples/hero-ecommerce/index.d.ts.map +1 -0
- package/dist/examples/hero-ecommerce/index.js +506 -0
- package/dist/examples/hero-ecommerce/index.js.map +1 -0
- package/dist/examples/svelte-counter/index.d.ts +31 -0
- package/dist/examples/svelte-counter/index.d.ts.map +1 -0
- package/dist/examples/svelte-counter/index.js +123 -0
- package/dist/examples/svelte-counter/index.js.map +1 -0
- package/dist/flows.d.ts +125 -0
- package/dist/flows.d.ts.map +1 -0
- package/dist/flows.js +160 -0
- package/dist/flows.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/pluresdb.d.ts +56 -0
- package/dist/integrations/pluresdb.d.ts.map +1 -0
- package/dist/integrations/pluresdb.js +46 -0
- package/dist/integrations/pluresdb.js.map +1 -0
- package/dist/integrations/svelte.d.ts +306 -0
- package/dist/integrations/svelte.d.ts.map +1 -0
- package/dist/integrations/svelte.js +447 -0
- package/dist/integrations/svelte.js.map +1 -0
- package/dist/registry.d.ts +94 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +181 -0
- package/dist/registry.js.map +1 -0
- package/dist/runtime/terminal-adapter.d.ts +105 -0
- package/dist/runtime/terminal-adapter.d.ts.map +1 -0
- package/dist/runtime/terminal-adapter.js +113 -0
- package/dist/runtime/terminal-adapter.js.map +1 -0
- package/dist/step.d.ts +34 -0
- package/dist/step.d.ts.map +1 -0
- package/dist/step.js +111 -0
- package/dist/step.js.map +1 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/docs/MONETIZATION.md +394 -0
- package/docs/TERMINAL_NODE.md +588 -0
- package/docs/guides/canvas.md +389 -0
- package/docs/guides/getting-started.md +347 -0
- package/docs/guides/history-state-pattern.md +618 -0
- package/docs/guides/orchestration.md +617 -0
- package/docs/guides/parallel-state-pattern.md +767 -0
- package/docs/guides/svelte-integration.md +691 -0
- package/package.json +96 -0
- package/src/__tests__/actors.test.ts +270 -0
- package/src/__tests__/billing.test.ts +175 -0
- package/src/__tests__/cloud.test.ts +247 -0
- package/src/__tests__/dsl.test.ts +154 -0
- package/src/__tests__/edge-cases.test.ts +475 -0
- package/src/__tests__/engine.test.ts +137 -0
- package/src/__tests__/generators.test.ts +270 -0
- package/src/__tests__/introspection.test.ts +321 -0
- package/src/__tests__/protocol.test.ts +40 -0
- package/src/__tests__/provisioning.test.ts +162 -0
- package/src/__tests__/schema.test.ts +241 -0
- package/src/__tests__/svelte-integration.test.ts +431 -0
- package/src/__tests__/terminal-node.test.ts +352 -0
- package/src/adapters/cli.ts +175 -0
- package/src/cli/commands/auth.ts +271 -0
- package/src/cli/commands/cloud.ts +281 -0
- package/src/cli/commands/generate.ts +225 -0
- package/src/cli/index.ts +190 -0
- package/src/cloud/README.md +383 -0
- package/src/cloud/auth.ts +245 -0
- package/src/cloud/billing.ts +336 -0
- package/src/cloud/client.ts +221 -0
- package/src/cloud/index.ts +121 -0
- package/src/cloud/marketplace.ts +303 -0
- package/src/cloud/provisioning.ts +254 -0
- package/src/cloud/relay/endpoints.ts +307 -0
- package/src/cloud/relay/health/function.json +17 -0
- package/src/cloud/relay/health/index.ts +10 -0
- package/src/cloud/relay/host.json +15 -0
- package/src/cloud/relay/local.settings.json +8 -0
- package/src/cloud/relay/stats/function.json +17 -0
- package/src/cloud/relay/stats/index.ts +10 -0
- package/src/cloud/relay/sync/function.json +17 -0
- package/src/cloud/relay/sync/index.ts +10 -0
- package/src/cloud/relay/usage/function.json +17 -0
- package/src/cloud/relay/usage/index.ts +10 -0
- package/src/cloud/sponsors.ts +213 -0
- package/src/cloud/types.ts +198 -0
- package/src/components/README.md +125 -0
- package/src/components/TerminalNode.svelte +457 -0
- package/src/components/index.ts +46 -0
- package/src/core/actors.ts +205 -0
- package/src/core/component/generator.ts +432 -0
- package/src/core/engine.ts +243 -0
- package/src/core/introspection.ts +329 -0
- package/src/core/logic/generator.ts +420 -0
- package/src/core/pluresdb/generator.ts +229 -0
- package/src/core/protocol.ts +132 -0
- package/src/core/rules.ts +167 -0
- package/src/core/schema/loader.ts +247 -0
- package/src/core/schema/normalize.ts +322 -0
- package/src/core/schema/types.ts +557 -0
- package/src/dsl/index.ts +218 -0
- package/src/dsl.ts +214 -0
- package/src/examples/advanced-todo/App.svelte +506 -0
- package/src/examples/advanced-todo/README.md +371 -0
- package/src/examples/advanced-todo/index.ts +309 -0
- package/src/examples/auth-basic/index.ts +163 -0
- package/src/examples/cart/index.ts +259 -0
- package/src/examples/hero-ecommerce/index.ts +657 -0
- package/src/examples/svelte-counter/index.ts +168 -0
- package/src/flows.ts +268 -0
- package/src/index.ts +154 -0
- package/src/integrations/pluresdb.ts +93 -0
- package/src/integrations/svelte.ts +617 -0
- package/src/registry.ts +223 -0
- package/src/runtime/terminal-adapter.ts +175 -0
- package/src/step.ts +151 -0
- package/src/types.ts +70 -0
- package/templates/basic-app/README.md +147 -0
- package/templates/fullstack-app/README.md +279 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { validateSchema } from '../core/schema/types.js';
|
|
3
|
+
import { loadSchemaFromYaml, loadSchemaFromJson } from '../core/schema/loader.js';
|
|
4
|
+
import {
|
|
5
|
+
createTerminalAdapter,
|
|
6
|
+
runTerminalCommand,
|
|
7
|
+
type TerminalExecutionResult,
|
|
8
|
+
} from '../runtime/terminal-adapter.js';
|
|
9
|
+
import type { PraxisSchema } from '../core/schema/types.js';
|
|
10
|
+
|
|
11
|
+
describe('Terminal Node', () => {
|
|
12
|
+
describe('Schema Validation', () => {
|
|
13
|
+
it('validates a schema with terminal node', () => {
|
|
14
|
+
const schema: PraxisSchema = {
|
|
15
|
+
version: '1.0.0',
|
|
16
|
+
name: 'TestTerminalSchema',
|
|
17
|
+
orchestration: {
|
|
18
|
+
type: 'custom',
|
|
19
|
+
nodes: [
|
|
20
|
+
{
|
|
21
|
+
id: 't1',
|
|
22
|
+
type: 'terminal',
|
|
23
|
+
x: 100,
|
|
24
|
+
y: 80,
|
|
25
|
+
config: {},
|
|
26
|
+
props: {
|
|
27
|
+
inputMode: 'text',
|
|
28
|
+
history: [],
|
|
29
|
+
lastOutput: null,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const result = validateSchema(schema);
|
|
37
|
+
expect(result.valid).toBe(true);
|
|
38
|
+
expect(result.errors).toHaveLength(0);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('validates terminal node with widget input mode', () => {
|
|
42
|
+
const schema: PraxisSchema = {
|
|
43
|
+
version: '1.0.0',
|
|
44
|
+
name: 'TestTerminalSchema',
|
|
45
|
+
orchestration: {
|
|
46
|
+
type: 'custom',
|
|
47
|
+
nodes: [
|
|
48
|
+
{
|
|
49
|
+
id: 't2',
|
|
50
|
+
type: 'terminal',
|
|
51
|
+
config: {},
|
|
52
|
+
props: {
|
|
53
|
+
inputMode: 'widget',
|
|
54
|
+
history: ['ls', 'pwd'],
|
|
55
|
+
lastOutput: 'test output',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const result = validateSchema(schema);
|
|
63
|
+
expect(result.valid).toBe(true);
|
|
64
|
+
expect(result.errors).toHaveLength(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('fails validation with invalid inputMode', () => {
|
|
68
|
+
const schema: PraxisSchema = {
|
|
69
|
+
version: '1.0.0',
|
|
70
|
+
name: 'TestTerminalSchema',
|
|
71
|
+
orchestration: {
|
|
72
|
+
type: 'custom',
|
|
73
|
+
nodes: [
|
|
74
|
+
{
|
|
75
|
+
id: 't3',
|
|
76
|
+
type: 'terminal',
|
|
77
|
+
config: {},
|
|
78
|
+
props: {
|
|
79
|
+
inputMode: 'invalid' as any,
|
|
80
|
+
history: [],
|
|
81
|
+
lastOutput: null,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const result = validateSchema(schema);
|
|
89
|
+
expect(result.valid).toBe(false);
|
|
90
|
+
expect(result.errors.length).toBeGreaterThan(0);
|
|
91
|
+
expect(result.errors[0].message).toContain('inputMode');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('fails validation when history is not an array', () => {
|
|
95
|
+
const schema: PraxisSchema = {
|
|
96
|
+
version: '1.0.0',
|
|
97
|
+
name: 'TestTerminalSchema',
|
|
98
|
+
orchestration: {
|
|
99
|
+
type: 'custom',
|
|
100
|
+
nodes: [
|
|
101
|
+
{
|
|
102
|
+
id: 't4',
|
|
103
|
+
type: 'terminal',
|
|
104
|
+
config: {},
|
|
105
|
+
props: {
|
|
106
|
+
inputMode: 'text',
|
|
107
|
+
history: 'not-an-array' as any,
|
|
108
|
+
lastOutput: null,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const result = validateSchema(schema);
|
|
116
|
+
expect(result.valid).toBe(false);
|
|
117
|
+
expect(result.errors.length).toBeGreaterThan(0);
|
|
118
|
+
expect(result.errors[0].message).toContain('history');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('validates terminal node with bindings', () => {
|
|
122
|
+
const schema: PraxisSchema = {
|
|
123
|
+
version: '1.0.0',
|
|
124
|
+
name: 'TestTerminalSchema',
|
|
125
|
+
orchestration: {
|
|
126
|
+
type: 'custom',
|
|
127
|
+
nodes: [
|
|
128
|
+
{
|
|
129
|
+
id: 't5',
|
|
130
|
+
type: 'terminal',
|
|
131
|
+
config: {},
|
|
132
|
+
props: {
|
|
133
|
+
inputMode: 'text',
|
|
134
|
+
history: [],
|
|
135
|
+
lastOutput: null,
|
|
136
|
+
},
|
|
137
|
+
bindings: {
|
|
138
|
+
input: '/terminal/input',
|
|
139
|
+
output: '/terminal/output',
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const result = validateSchema(schema);
|
|
147
|
+
expect(result.valid).toBe(true);
|
|
148
|
+
expect(result.errors).toHaveLength(0);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe('YAML Loading', () => {
|
|
153
|
+
it('loads terminal node from YAML', () => {
|
|
154
|
+
const yaml = `
|
|
155
|
+
version: "1.0.0"
|
|
156
|
+
name: "TerminalTestSchema"
|
|
157
|
+
orchestration:
|
|
158
|
+
type: custom
|
|
159
|
+
nodes:
|
|
160
|
+
- id: t1
|
|
161
|
+
type: terminal
|
|
162
|
+
x: 100
|
|
163
|
+
y: 80
|
|
164
|
+
props:
|
|
165
|
+
inputMode: text
|
|
166
|
+
history: []
|
|
167
|
+
lastOutput: null
|
|
168
|
+
`;
|
|
169
|
+
|
|
170
|
+
const result = loadSchemaFromYaml(yaml);
|
|
171
|
+
expect(result.errors).toHaveLength(0);
|
|
172
|
+
expect(result.schema).toBeDefined();
|
|
173
|
+
expect(result.schema?.orchestration?.nodes).toHaveLength(1);
|
|
174
|
+
expect(result.schema?.orchestration?.nodes?.[0].type).toBe('terminal');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('loads terminal node with bindings from YAML', () => {
|
|
178
|
+
const yaml = `
|
|
179
|
+
version: "1.0.0"
|
|
180
|
+
name: "TerminalTestSchema"
|
|
181
|
+
orchestration:
|
|
182
|
+
type: custom
|
|
183
|
+
nodes:
|
|
184
|
+
- id: t1
|
|
185
|
+
type: terminal
|
|
186
|
+
x: 200
|
|
187
|
+
y: 150
|
|
188
|
+
props:
|
|
189
|
+
inputMode: widget
|
|
190
|
+
history:
|
|
191
|
+
- echo hello
|
|
192
|
+
- ls -la
|
|
193
|
+
lastOutput: null
|
|
194
|
+
bindings:
|
|
195
|
+
input: /plures/terminal/input
|
|
196
|
+
output: /plures/terminal/output
|
|
197
|
+
`;
|
|
198
|
+
|
|
199
|
+
const result = loadSchemaFromYaml(yaml);
|
|
200
|
+
expect(result.errors).toHaveLength(0);
|
|
201
|
+
expect(result.schema).toBeDefined();
|
|
202
|
+
|
|
203
|
+
const node = result.schema?.orchestration?.nodes?.[0];
|
|
204
|
+
expect(node?.type).toBe('terminal');
|
|
205
|
+
expect(node?.bindings?.input).toBe('/plures/terminal/input');
|
|
206
|
+
expect(node?.bindings?.output).toBe('/plures/terminal/output');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe('JSON Loading', () => {
|
|
211
|
+
it('loads terminal node from JSON', () => {
|
|
212
|
+
const json = JSON.stringify({
|
|
213
|
+
version: '1.0.0',
|
|
214
|
+
name: 'TerminalTestSchema',
|
|
215
|
+
orchestration: {
|
|
216
|
+
type: 'custom',
|
|
217
|
+
nodes: [
|
|
218
|
+
{
|
|
219
|
+
id: 't1',
|
|
220
|
+
type: 'terminal',
|
|
221
|
+
x: 100,
|
|
222
|
+
y: 80,
|
|
223
|
+
config: {},
|
|
224
|
+
props: {
|
|
225
|
+
inputMode: 'text',
|
|
226
|
+
history: [],
|
|
227
|
+
lastOutput: null,
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const result = loadSchemaFromJson(json);
|
|
235
|
+
expect(result.errors).toHaveLength(0);
|
|
236
|
+
expect(result.schema).toBeDefined();
|
|
237
|
+
expect(result.schema?.orchestration?.nodes).toHaveLength(1);
|
|
238
|
+
expect(result.schema?.orchestration?.nodes?.[0].type).toBe('terminal');
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe('Terminal Adapter', () => {
|
|
243
|
+
it('creates a terminal adapter', () => {
|
|
244
|
+
const adapter = createTerminalAdapter({
|
|
245
|
+
nodeId: 'test-terminal',
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
expect(adapter).toBeDefined();
|
|
249
|
+
const state = adapter.getState();
|
|
250
|
+
expect(state.nodeId).toBe('test-terminal');
|
|
251
|
+
expect(state.inputMode).toBe('text');
|
|
252
|
+
expect(state.history).toEqual([]);
|
|
253
|
+
expect(state.lastOutput).toBeNull();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('creates terminal adapter with custom props', () => {
|
|
257
|
+
const adapter = createTerminalAdapter({
|
|
258
|
+
nodeId: 'test-terminal',
|
|
259
|
+
props: {
|
|
260
|
+
inputMode: 'widget',
|
|
261
|
+
history: ['echo test'],
|
|
262
|
+
lastOutput: 'test output',
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const state = adapter.getState();
|
|
267
|
+
expect(state.inputMode).toBe('widget');
|
|
268
|
+
expect(state.history).toEqual(['echo test']);
|
|
269
|
+
expect(state.lastOutput).toBe('test output');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('creates terminal adapter with pluresDB bindings', () => {
|
|
273
|
+
const adapter = createTerminalAdapter({
|
|
274
|
+
nodeId: 'test-terminal',
|
|
275
|
+
inputPath: '/terminal/input',
|
|
276
|
+
outputPath: '/terminal/output',
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
expect(adapter).toBeDefined();
|
|
280
|
+
const state = adapter.getState();
|
|
281
|
+
expect(state.nodeId).toBe('test-terminal');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('executes a command', async () => {
|
|
285
|
+
const adapter = createTerminalAdapter({
|
|
286
|
+
nodeId: 'test-terminal',
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
const result = await adapter.executeCommand('echo hello');
|
|
290
|
+
|
|
291
|
+
expect(result).toBeDefined();
|
|
292
|
+
expect(result.command).toBe('echo hello');
|
|
293
|
+
expect(result.output).toContain('echo hello');
|
|
294
|
+
expect(result.exitCode).toBe(0);
|
|
295
|
+
expect(result.timestamp).toBeGreaterThan(0);
|
|
296
|
+
|
|
297
|
+
const state = adapter.getState();
|
|
298
|
+
expect(state.history).toContain('echo hello');
|
|
299
|
+
expect(state.lastOutput).toBe(result.output);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('maintains command history', async () => {
|
|
303
|
+
const adapter = createTerminalAdapter({
|
|
304
|
+
nodeId: 'test-terminal',
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
await adapter.executeCommand('ls');
|
|
308
|
+
await adapter.executeCommand('pwd');
|
|
309
|
+
await adapter.executeCommand('echo test');
|
|
310
|
+
|
|
311
|
+
const history = adapter.getHistory();
|
|
312
|
+
expect(history).toEqual(['ls', 'pwd', 'echo test']);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('clears command history', async () => {
|
|
316
|
+
const adapter = createTerminalAdapter({
|
|
317
|
+
nodeId: 'test-terminal',
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
await adapter.executeCommand('ls');
|
|
321
|
+
await adapter.executeCommand('pwd');
|
|
322
|
+
|
|
323
|
+
expect(adapter.getHistory()).toHaveLength(2);
|
|
324
|
+
|
|
325
|
+
adapter.clearHistory();
|
|
326
|
+
expect(adapter.getHistory()).toHaveLength(0);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('updates terminal props', () => {
|
|
330
|
+
const adapter = createTerminalAdapter({
|
|
331
|
+
nodeId: 'test-terminal',
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
adapter.updateProps({
|
|
335
|
+
inputMode: 'widget',
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const state = adapter.getState();
|
|
339
|
+
expect(state.inputMode).toBe('widget');
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
describe('runTerminalCommand convenience function', () => {
|
|
344
|
+
it('executes command using convenience function', async () => {
|
|
345
|
+
const result = await runTerminalCommand('test-node', 'ls -la');
|
|
346
|
+
|
|
347
|
+
expect(result).toBeDefined();
|
|
348
|
+
expect(result.command).toBe('ls -la');
|
|
349
|
+
expect(result.exitCode).toBe(0);
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
});
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Praxis CLI Adapter
|
|
4
|
+
*
|
|
5
|
+
* JSON-based CLI interface for cross-language Praxis engine invocation.
|
|
6
|
+
* Reads JSON from stdin, processes through Praxis engine, outputs JSON to stdout.
|
|
7
|
+
*
|
|
8
|
+
* This enables PowerShell, Python, and other languages to use Praxis.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as fs from "fs";
|
|
12
|
+
import {
|
|
13
|
+
createPraxisEngine,
|
|
14
|
+
PraxisRegistry,
|
|
15
|
+
type PraxisState,
|
|
16
|
+
type PraxisEvent,
|
|
17
|
+
type PraxisStepResult,
|
|
18
|
+
type RuleDescriptor,
|
|
19
|
+
type ConstraintDescriptor,
|
|
20
|
+
} from "../index.js";
|
|
21
|
+
|
|
22
|
+
interface CLIInput {
|
|
23
|
+
state: PraxisState;
|
|
24
|
+
events: PraxisEvent[];
|
|
25
|
+
configPath: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface RegistryConfig {
|
|
29
|
+
rules: Array<{
|
|
30
|
+
id: string;
|
|
31
|
+
description: string;
|
|
32
|
+
// Implementation loaded from separate files or inline
|
|
33
|
+
impl?: string; // JavaScript code as string
|
|
34
|
+
}>;
|
|
35
|
+
constraints: Array<{
|
|
36
|
+
id: string;
|
|
37
|
+
description: string;
|
|
38
|
+
impl?: string;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Load registry configuration from JSON file
|
|
44
|
+
*/
|
|
45
|
+
function loadRegistryConfig(configPath: string): RegistryConfig {
|
|
46
|
+
try {
|
|
47
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
48
|
+
return JSON.parse(content);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
throw new Error(`Failed to load registry config from ${configPath}: ${error}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create a registry from configuration
|
|
56
|
+
* Note: For simplicity, this uses eval for rule implementations.
|
|
57
|
+
* In production, use a safer approach like loading from pre-compiled modules.
|
|
58
|
+
*/
|
|
59
|
+
function createRegistryFromConfig<TContext = unknown>(
|
|
60
|
+
config: RegistryConfig
|
|
61
|
+
): PraxisRegistry<TContext> {
|
|
62
|
+
const registry = new PraxisRegistry<TContext>();
|
|
63
|
+
|
|
64
|
+
// Register rules
|
|
65
|
+
for (const ruleConfig of config.rules) {
|
|
66
|
+
if (!ruleConfig.impl) {
|
|
67
|
+
throw new Error(`Rule ${ruleConfig.id} missing implementation`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
// Eval the implementation (for demo purposes)
|
|
72
|
+
// In production, load from modules or use a safer evaluation method
|
|
73
|
+
const impl = eval(ruleConfig.impl);
|
|
74
|
+
|
|
75
|
+
const rule: RuleDescriptor<TContext> = {
|
|
76
|
+
id: ruleConfig.id,
|
|
77
|
+
description: ruleConfig.description,
|
|
78
|
+
impl,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
registry.registerRule(rule);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
throw new Error(`Failed to load rule ${ruleConfig.id}: ${error}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Register constraints
|
|
88
|
+
for (const constraintConfig of config.constraints) {
|
|
89
|
+
if (!constraintConfig.impl) {
|
|
90
|
+
throw new Error(`Constraint ${constraintConfig.id} missing implementation`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const impl = eval(constraintConfig.impl);
|
|
95
|
+
|
|
96
|
+
const constraint: ConstraintDescriptor<TContext> = {
|
|
97
|
+
id: constraintConfig.id,
|
|
98
|
+
description: constraintConfig.description,
|
|
99
|
+
impl,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
registry.registerConstraint(constraint);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
throw new Error(`Failed to load constraint ${constraintConfig.id}: ${error}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return registry;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Process a step through the Praxis engine
|
|
113
|
+
*/
|
|
114
|
+
function processStep(input: CLIInput): PraxisStepResult {
|
|
115
|
+
// Load registry configuration
|
|
116
|
+
const config = loadRegistryConfig(input.configPath);
|
|
117
|
+
const registry = createRegistryFromConfig(config);
|
|
118
|
+
|
|
119
|
+
// Create engine with state from input
|
|
120
|
+
const engine = createPraxisEngine({
|
|
121
|
+
initialContext: input.state.context,
|
|
122
|
+
initialFacts: input.state.facts,
|
|
123
|
+
initialMeta: input.state.meta,
|
|
124
|
+
registry,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Process events
|
|
128
|
+
return engine.step(input.events);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Main CLI entry point
|
|
133
|
+
*/
|
|
134
|
+
async function main() {
|
|
135
|
+
try {
|
|
136
|
+
// Read input from stdin
|
|
137
|
+
let inputData = "";
|
|
138
|
+
|
|
139
|
+
for await (const chunk of process.stdin) {
|
|
140
|
+
inputData += chunk;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!inputData.trim()) {
|
|
144
|
+
throw new Error("No input provided");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Parse input
|
|
148
|
+
const input: CLIInput = JSON.parse(inputData);
|
|
149
|
+
|
|
150
|
+
// Validate input
|
|
151
|
+
if (!input.state || !input.events || !input.configPath) {
|
|
152
|
+
throw new Error("Invalid input: must provide state, events, and configPath");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Process step
|
|
156
|
+
const result = processStep(input);
|
|
157
|
+
|
|
158
|
+
// Output result as JSON
|
|
159
|
+
console.log(JSON.stringify(result, null, 2));
|
|
160
|
+
process.exit(0);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error(JSON.stringify({
|
|
163
|
+
error: error instanceof Error ? error.message : String(error),
|
|
164
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
165
|
+
}, null, 2));
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Run if executed directly
|
|
171
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
172
|
+
main();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export { processStep, loadRegistryConfig, createRegistryFromConfig };
|