@mawaru/sdk 0.11.0 → 0.14.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/_schemas/ai-manifest.test.ts +54 -59
- package/_schemas/ai-manifest.ts +38 -23
- package/_schemas/duplicate-selection.test.ts +235 -0
- package/_schemas/duplicate-selection.ts +48 -0
- package/_schemas/extract-component.test.ts +51 -2
- package/_schemas/extract-component.ts +4 -2
- package/_schemas/graph.test.ts +105 -86
- package/_schemas/graph.ts +20 -77
- package/_schemas/node.ts +4 -0
- package/_schemas/port-spec.test.ts +194 -113
- package/_schemas/port-spec.ts +95 -107
- package/dist/_cli/credentials.d.ts +14 -0
- package/dist/_cli/credentials.js +81 -0
- package/dist/_cli/login.d.ts +5 -0
- package/dist/_cli/login.js +82 -0
- package/dist/_cli/resumeSession.d.ts +21 -0
- package/dist/_cli/resumeSession.js +125 -0
- package/dist/_cli/sessionCommand.d.ts +3 -0
- package/dist/_cli/sessionCommand.js +55 -0
- package/dist/_schemas/ai-manifest.d.ts +12 -1
- package/dist/_schemas/ai-manifest.js +35 -20
- package/dist/_schemas/duplicate-selection.d.ts +12 -0
- package/dist/_schemas/duplicate-selection.js +34 -0
- package/dist/_schemas/extract-component.js +4 -2
- package/dist/_schemas/graph.d.ts +14 -12
- package/dist/_schemas/graph.js +21 -60
- package/dist/_schemas/hook-manifest.d.ts +2 -2
- package/dist/_schemas/node.d.ts +3 -2
- package/dist/_schemas/node.js +4 -0
- package/dist/_schemas/port-spec.d.ts +11 -6
- package/dist/_schemas/port-spec.js +72 -97
- package/dist/cli.js +50 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/init.js +1 -1
- package/dist/typegen.js +6 -6
- package/docs/development.md +5 -1
- package/index.ts +1 -0
- package/package.json +11 -18
- package/skills/create-loop/SKILL.md +1 -1
- package/templates/CLAUDE.md +1 -1
- package/templates/echo/main.ts +1 -1
- package/templates/mawaru-runner.yml +1 -1
|
@@ -3,12 +3,9 @@ import type { GraphPort, JsonSchema } from "./node.js"
|
|
|
3
3
|
import {
|
|
4
4
|
dataFormatOf,
|
|
5
5
|
dataSchemaOf,
|
|
6
|
-
envelopeDataSchemaOf,
|
|
7
|
-
envelopeSchemaOf,
|
|
8
6
|
fileSchema,
|
|
9
7
|
hasInboundConflict,
|
|
10
8
|
instructionSchema,
|
|
11
|
-
isAiEnvelopeSchema,
|
|
12
9
|
isFileSchema,
|
|
13
10
|
isSchemaSubset,
|
|
14
11
|
kindPortsViolation,
|
|
@@ -77,102 +74,19 @@ describe("データフォーマットカタログ(S)", () => {
|
|
|
77
74
|
})
|
|
78
75
|
})
|
|
79
76
|
|
|
80
|
-
describe("
|
|
81
|
-
it("
|
|
82
|
-
const text = envelopeSchemaOf({ type: "string" })
|
|
83
|
-
expect(text).toEqual({
|
|
84
|
-
type: "object",
|
|
85
|
-
properties: {
|
|
86
|
-
data: { type: "string" },
|
|
87
|
-
description: { type: "string" },
|
|
88
|
-
},
|
|
89
|
-
required: ["data", "description"],
|
|
90
|
-
})
|
|
91
|
-
// カタログ外の任意型も包める
|
|
92
|
-
const custom = {
|
|
93
|
-
type: "object",
|
|
94
|
-
properties: { title: { type: "string" }, count: { type: "number" } },
|
|
95
|
-
required: ["title"],
|
|
96
|
-
}
|
|
97
|
-
expect(envelopeSchemaOf(custom).properties).toMatchObject({ data: custom })
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
it("envelopeDataSchemaOf:封筒型なら data のサブスキーマ、そうでなければ null", () => {
|
|
101
|
-
const dataSchema = { type: "array", items: { type: "string" } }
|
|
102
|
-
expect(envelopeDataSchemaOf(envelopeSchemaOf(dataSchema))).toEqual(
|
|
103
|
-
dataSchema,
|
|
104
|
-
)
|
|
105
|
-
// data キーが無い / optional / object でない
|
|
106
|
-
expect(envelopeDataSchemaOf({ type: "object", properties: {} })).toBeNull()
|
|
77
|
+
describe("kindPortsViolation(kind 別ポート構成)", () => {
|
|
78
|
+
it("ai は in / out とも key 自由(構成の固定なし。口数は graph 側が見る)", () => {
|
|
107
79
|
expect(
|
|
108
|
-
|
|
109
|
-
type: "object",
|
|
110
|
-
properties: { data: { type: "string" } },
|
|
111
|
-
}),
|
|
80
|
+
kindPortsViolation("ai", [port("in", "in"), port("out", "main")]),
|
|
112
81
|
).toBeNull()
|
|
113
|
-
expect(envelopeDataSchemaOf({ type: "string" })).toBeNull()
|
|
114
|
-
expect(envelopeDataSchemaOf(UNDECLARED_SCHEMA)).toBeNull()
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
it("isAiEnvelopeSchema:data と description: string の両方が必須のときだけ true", () => {
|
|
118
|
-
expect(isAiEnvelopeSchema(envelopeSchemaOf({ type: "string" }))).toBe(true)
|
|
119
|
-
expect(isAiEnvelopeSchema(envelopeSchemaOf({ type: "object" }))).toBe(true)
|
|
120
|
-
// description が無い / optional / string でない
|
|
121
|
-
expect(
|
|
122
|
-
isAiEnvelopeSchema({
|
|
123
|
-
type: "object",
|
|
124
|
-
properties: { data: { type: "string" } },
|
|
125
|
-
required: ["data"],
|
|
126
|
-
}),
|
|
127
|
-
).toBe(false)
|
|
128
|
-
expect(
|
|
129
|
-
isAiEnvelopeSchema({
|
|
130
|
-
type: "object",
|
|
131
|
-
properties: {
|
|
132
|
-
data: { type: "string" },
|
|
133
|
-
description: { type: "string" },
|
|
134
|
-
},
|
|
135
|
-
required: ["data"],
|
|
136
|
-
}),
|
|
137
|
-
).toBe(false)
|
|
138
|
-
expect(
|
|
139
|
-
isAiEnvelopeSchema({
|
|
140
|
-
type: "object",
|
|
141
|
-
properties: {
|
|
142
|
-
data: { type: "string" },
|
|
143
|
-
description: { type: "number" },
|
|
144
|
-
},
|
|
145
|
-
required: ["data", "description"],
|
|
146
|
-
}),
|
|
147
|
-
).toBe(false)
|
|
148
|
-
expect(isAiEnvelopeSchema(UNDECLARED_SCHEMA)).toBe(false)
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
describe("kindPortsViolation(kind 別ポート構成)", () => {
|
|
153
|
-
it("ai は out の key 自由・複数可。in は in / instruction の2口固定(AI の複数出口)", () => {
|
|
154
|
-
const ins = [port("in", "in"), port("in", "instruction")]
|
|
155
|
-
expect(kindPortsViolation("ai", [...ins, port("out", "main")])).toBeNull()
|
|
156
|
-
expect(kindPortsViolation("ai", [...ins, port("out", "draft")])).toBeNull()
|
|
157
82
|
expect(
|
|
158
83
|
kindPortsViolation("ai", [
|
|
159
|
-
|
|
84
|
+
port("in", "task"),
|
|
85
|
+
port("in", "feedback"),
|
|
160
86
|
port("out", "spam"),
|
|
161
87
|
port("out", "sales"),
|
|
162
|
-
port("out", "support"),
|
|
163
88
|
]),
|
|
164
89
|
).toBeNull()
|
|
165
|
-
// instruction が無い・key が違うのは違反
|
|
166
|
-
expect(
|
|
167
|
-
kindPortsViolation("ai", [port("in", "in"), port("out", "main")]),
|
|
168
|
-
).toMatch(/instruction/)
|
|
169
|
-
expect(
|
|
170
|
-
kindPortsViolation("ai", [
|
|
171
|
-
port("in", "input"),
|
|
172
|
-
port("in", "instruction"),
|
|
173
|
-
port("out", "main"),
|
|
174
|
-
]),
|
|
175
|
-
).toMatch(/ai/)
|
|
176
90
|
})
|
|
177
91
|
|
|
178
92
|
it("human は in / approve / reject 固定", () => {
|
|
@@ -217,10 +131,18 @@ describe("kindPortsViolation(kind 別ポート構成)", () => {
|
|
|
217
131
|
})
|
|
218
132
|
|
|
219
133
|
describe("型伝播(導出ポートの解決)", () => {
|
|
220
|
-
|
|
134
|
+
// 伝播テスト用の任意の宣言型(中身の形に意味はない)
|
|
135
|
+
const declaredOut = {
|
|
136
|
+
type: "object",
|
|
137
|
+
properties: { text: { type: "string" } },
|
|
138
|
+
required: ["text"],
|
|
139
|
+
}
|
|
221
140
|
|
|
222
|
-
|
|
223
|
-
|
|
141
|
+
// human の in / approve / reject はビューの宣言をそのまま転写する(上流の kind は見ない)。
|
|
142
|
+
// sdk はカタログを知らないので、呼び出し元が viewPortSchemasOf で解決して渡す
|
|
143
|
+
// → docs/tasks/wip/ポート型固定の撤去とセッション再開のポート属性化.md
|
|
144
|
+
it("ai → human 直結(コピー宣言):in も approve も上流の out と同型、reject はビューの宣言型", () => {
|
|
145
|
+
const aiOut = port("out", "main", declaredOut)
|
|
224
146
|
const ai = {
|
|
225
147
|
id: uuid(),
|
|
226
148
|
kind: "ai",
|
|
@@ -237,13 +159,144 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
237
159
|
const resolved = resolvePortSchemas(
|
|
238
160
|
[ai, human],
|
|
239
161
|
[{ from_port_id: aiOut.id, to_port_id: humanIn.id }],
|
|
162
|
+
{
|
|
163
|
+
viewPortSchemasOf: () => ({
|
|
164
|
+
in: "T",
|
|
165
|
+
approve: "T",
|
|
166
|
+
reject: instructionSchema(),
|
|
167
|
+
}),
|
|
168
|
+
},
|
|
240
169
|
)
|
|
241
|
-
|
|
242
|
-
expect(resolved.get(
|
|
170
|
+
// 上流が AI でも中身を取り出さない:AI の出力形式がそのまま下流へ流れる
|
|
171
|
+
expect(resolved.get(humanIn.id)).toEqual(declaredOut)
|
|
172
|
+
expect(resolved.get(approve.id)).toEqual(declaredOut)
|
|
243
173
|
expect(resolved.get(reject.id)).toEqual(instructionSchema())
|
|
244
174
|
})
|
|
245
175
|
|
|
246
|
-
|
|
176
|
+
describe("承認ビューの宣言を human のポートへ転写する", () => {
|
|
177
|
+
const viewIn = {
|
|
178
|
+
type: "object",
|
|
179
|
+
properties: {
|
|
180
|
+
data: {
|
|
181
|
+
type: "object",
|
|
182
|
+
properties: { prs: { type: "array", items: { type: "object" } } },
|
|
183
|
+
required: ["prs"],
|
|
184
|
+
},
|
|
185
|
+
description: { type: "string" },
|
|
186
|
+
},
|
|
187
|
+
required: ["data", "description"],
|
|
188
|
+
}
|
|
189
|
+
const viewOut = {
|
|
190
|
+
type: "object",
|
|
191
|
+
properties: { prs: { type: "array", items: { type: "object" } } },
|
|
192
|
+
required: ["prs"],
|
|
193
|
+
}
|
|
194
|
+
// reject もビューの宣言(具体型のみ。コピー指示は意味を持たない)
|
|
195
|
+
const viewReject = {
|
|
196
|
+
type: "object",
|
|
197
|
+
properties: { reason: { type: "string" } },
|
|
198
|
+
required: ["reason"],
|
|
199
|
+
}
|
|
200
|
+
const build = (upstreamKind: string, upstreamOut: JsonSchema) => {
|
|
201
|
+
const out = port("out", "main", upstreamOut)
|
|
202
|
+
const upstream = {
|
|
203
|
+
id: uuid(),
|
|
204
|
+
kind: upstreamKind,
|
|
205
|
+
ports: [port("in", "in"), out],
|
|
206
|
+
}
|
|
207
|
+
const humanIn = port("in", "in")
|
|
208
|
+
const approve = port("out", "approve")
|
|
209
|
+
const reject = port("out", "reject")
|
|
210
|
+
const human = {
|
|
211
|
+
id: uuid(),
|
|
212
|
+
kind: "human",
|
|
213
|
+
ports: [humanIn, approve, reject],
|
|
214
|
+
}
|
|
215
|
+
return { upstream, human, out, humanIn, approve, reject }
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
it("宣言のあるビューは上流の kind に依らず同じ型になる", () => {
|
|
219
|
+
for (const kind of ["ai", "program"]) {
|
|
220
|
+
const { upstream, human, out, humanIn, approve, reject } = build(
|
|
221
|
+
kind,
|
|
222
|
+
declaredOut,
|
|
223
|
+
)
|
|
224
|
+
const resolved = resolvePortSchemas(
|
|
225
|
+
[upstream, human],
|
|
226
|
+
[{ from_port_id: out.id, to_port_id: humanIn.id }],
|
|
227
|
+
{
|
|
228
|
+
viewPortSchemasOf: () => ({
|
|
229
|
+
in: viewIn,
|
|
230
|
+
approve: viewOut,
|
|
231
|
+
reject: viewReject,
|
|
232
|
+
}),
|
|
233
|
+
},
|
|
234
|
+
)
|
|
235
|
+
expect(resolved.get(humanIn.id)).toEqual(viewIn)
|
|
236
|
+
expect(resolved.get(approve.id)).toEqual(viewOut)
|
|
237
|
+
expect(resolved.get(reject.id)).toEqual(viewReject)
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it("上流の out は書き換えない(逆伝播しない)", () => {
|
|
242
|
+
const { upstream, human, out, humanIn } = build("ai", declaredOut)
|
|
243
|
+
const resolved = resolvePortSchemas(
|
|
244
|
+
[upstream, human],
|
|
245
|
+
[{ from_port_id: out.id, to_port_id: humanIn.id }],
|
|
246
|
+
{
|
|
247
|
+
viewPortSchemasOf: () => ({
|
|
248
|
+
in: viewIn,
|
|
249
|
+
approve: viewOut,
|
|
250
|
+
reject: viewReject,
|
|
251
|
+
}),
|
|
252
|
+
},
|
|
253
|
+
)
|
|
254
|
+
expect(resolved.get(out.id)).toEqual(declaredOut)
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
it("コピー宣言(標準ビュー)は上流の型をそのまま in と approve へ流す", () => {
|
|
258
|
+
const { upstream, human, out, humanIn, approve } = build(
|
|
259
|
+
"ai",
|
|
260
|
+
declaredOut,
|
|
261
|
+
)
|
|
262
|
+
const resolved = resolvePortSchemas(
|
|
263
|
+
[upstream, human],
|
|
264
|
+
[{ from_port_id: out.id, to_port_id: humanIn.id }],
|
|
265
|
+
{
|
|
266
|
+
viewPortSchemasOf: () => ({
|
|
267
|
+
in: "T",
|
|
268
|
+
approve: "T",
|
|
269
|
+
reject: viewReject,
|
|
270
|
+
}),
|
|
271
|
+
},
|
|
272
|
+
)
|
|
273
|
+
expect(resolved.get(humanIn.id)).toEqual(declaredOut)
|
|
274
|
+
expect(resolved.get(approve.id)).toEqual(declaredOut)
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it("未接続でも宣言で固定される", () => {
|
|
278
|
+
const humanIn = port("in", "in")
|
|
279
|
+
const approve = port("out", "approve")
|
|
280
|
+
const reject = port("out", "reject")
|
|
281
|
+
const human = {
|
|
282
|
+
id: uuid(),
|
|
283
|
+
kind: "human",
|
|
284
|
+
ports: [humanIn, approve, reject],
|
|
285
|
+
}
|
|
286
|
+
const resolved = resolvePortSchemas([human], [], {
|
|
287
|
+
viewPortSchemasOf: () => ({
|
|
288
|
+
in: viewIn,
|
|
289
|
+
approve: viewOut,
|
|
290
|
+
reject: viewReject,
|
|
291
|
+
}),
|
|
292
|
+
})
|
|
293
|
+
expect(resolved.get(humanIn.id)).toEqual(viewIn)
|
|
294
|
+
expect(resolved.get(approve.id)).toEqual(viewOut)
|
|
295
|
+
expect(resolved.get(reject.id)).toEqual(viewReject)
|
|
296
|
+
})
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
it("ai → wait → human:素通しで上流の宣言型が伝播し、reject はビュー宣言が無ければ未宣言", () => {
|
|
247
300
|
// ai の in は宣言型(nodes/ai/<dir>/config.json の inputs.in 由来。実行repoの構造見直し)
|
|
248
301
|
const aiInSchema = {
|
|
249
302
|
type: "object",
|
|
@@ -251,7 +304,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
251
304
|
required: ["inquiry"],
|
|
252
305
|
}
|
|
253
306
|
const aiIn = port("in", "in", aiInSchema)
|
|
254
|
-
const aiOut = port("out", "main",
|
|
307
|
+
const aiOut = port("out", "main", declaredOut)
|
|
255
308
|
const waitIn = port("in", "in")
|
|
256
309
|
const waitOut = port("out", "main")
|
|
257
310
|
const humanIn = port("in", "in")
|
|
@@ -273,16 +326,41 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
273
326
|
{ from_port_id: waitOut.id, to_port_id: humanIn.id },
|
|
274
327
|
]
|
|
275
328
|
const resolved = resolvePortSchemas([ai, wait, human], conns)
|
|
276
|
-
expect(resolved.get(waitIn.id)).toEqual(
|
|
277
|
-
expect(resolved.get(waitOut.id)).toEqual(
|
|
278
|
-
expect(resolved.get(humanIn.id)).toEqual(
|
|
279
|
-
//
|
|
280
|
-
expect(resolved.get(approve.id)).toEqual(
|
|
281
|
-
|
|
329
|
+
expect(resolved.get(waitIn.id)).toEqual(declaredOut)
|
|
330
|
+
expect(resolved.get(waitOut.id)).toEqual(declaredOut)
|
|
331
|
+
expect(resolved.get(humanIn.id)).toEqual(declaredOut)
|
|
332
|
+
// approve は in と同型(上流の kind による中身の取り出しはしない)
|
|
333
|
+
expect(resolved.get(approve.id)).toEqual(declaredOut)
|
|
334
|
+
// reject はビューの宣言でのみ決まる(sdk 単体=カタログ無しでは未宣言。型固定は廃止)
|
|
335
|
+
expect(resolved.get(reject.id)).toEqual(UNDECLARED_SCHEMA)
|
|
282
336
|
// ai の in は宣言型がそのまま残る(const 扱いは廃止)
|
|
283
337
|
expect(resolved.get(aiIn.id)).toEqual(aiInSchema)
|
|
284
338
|
})
|
|
285
339
|
|
|
340
|
+
it("ai の in はどの口も接続鏡映される(instruction の特別扱い=型固定は廃止)", () => {
|
|
341
|
+
const progOut = port("out", "main", declaredOut)
|
|
342
|
+
const program = {
|
|
343
|
+
id: uuid(),
|
|
344
|
+
kind: "program",
|
|
345
|
+
ports: [port("in", "in"), progOut],
|
|
346
|
+
}
|
|
347
|
+
// 宣言はデフォルトの指示型。接続すると接続元の型に同期される(他の in と同じ)
|
|
348
|
+
const instruction = port("in", "instruction", instructionSchema())
|
|
349
|
+
const ai = {
|
|
350
|
+
id: uuid(),
|
|
351
|
+
kind: "ai",
|
|
352
|
+
ports: [port("in", "in"), instruction, port("out", "main")],
|
|
353
|
+
}
|
|
354
|
+
const resolved = resolvePortSchemas(
|
|
355
|
+
[program, ai],
|
|
356
|
+
[{ from_port_id: progOut.id, to_port_id: instruction.id }],
|
|
357
|
+
)
|
|
358
|
+
expect(resolved.get(instruction.id)).toEqual(declaredOut)
|
|
359
|
+
// 未接続なら宣言(デフォルト型)を維持する
|
|
360
|
+
const kept = resolvePortSchemas([ai], [])
|
|
361
|
+
expect(kept.get(instruction.id)).toEqual(instructionSchema())
|
|
362
|
+
})
|
|
363
|
+
|
|
286
364
|
it("未接続の導出ポート・純パラメトリック閉路は any", () => {
|
|
287
365
|
const in1 = port("in", "in")
|
|
288
366
|
const out1 = port("out", "main")
|
|
@@ -308,7 +386,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
308
386
|
properties: { inquiry: { type: "string" } },
|
|
309
387
|
required: ["inquiry"],
|
|
310
388
|
}
|
|
311
|
-
const aiOut = port("out", "main",
|
|
389
|
+
const aiOut = port("out", "main", declaredOut)
|
|
312
390
|
const ai = {
|
|
313
391
|
id: uuid(),
|
|
314
392
|
kind: "ai",
|
|
@@ -324,7 +402,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
324
402
|
[ai, program],
|
|
325
403
|
[{ from_port_id: aiOut.id, to_port_id: progIn.id }],
|
|
326
404
|
)
|
|
327
|
-
expect(resolved.get(progIn.id)).toEqual(
|
|
405
|
+
expect(resolved.get(progIn.id)).toEqual(declaredOut)
|
|
328
406
|
})
|
|
329
407
|
|
|
330
408
|
it("ai の in も接続鏡映(sticky):具体型の接続元だけ上書きする", () => {
|
|
@@ -332,7 +410,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
332
410
|
type: "object",
|
|
333
411
|
properties: { topic: { type: "string" } },
|
|
334
412
|
}
|
|
335
|
-
const progOut = port("out", "main",
|
|
413
|
+
const progOut = port("out", "main", declaredOut)
|
|
336
414
|
const program = {
|
|
337
415
|
id: uuid(),
|
|
338
416
|
kind: "program",
|
|
@@ -349,7 +427,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
349
427
|
[program, ai],
|
|
350
428
|
[{ from_port_id: progOut.id, to_port_id: aiIn.id }],
|
|
351
429
|
)
|
|
352
|
-
expect(resolved.get(aiIn.id)).toEqual(
|
|
430
|
+
expect(resolved.get(aiIn.id)).toEqual(declaredOut)
|
|
353
431
|
// 接続元が any(源泉の無い wait)→ 宣言を維持
|
|
354
432
|
const waitOut = port("out", "main")
|
|
355
433
|
const wait = {
|
|
@@ -401,7 +479,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
401
479
|
})
|
|
402
480
|
|
|
403
481
|
it("program の in:wait 越しでも具体型が鏡映される(固定点反復)", () => {
|
|
404
|
-
const aiOut = port("out", "main",
|
|
482
|
+
const aiOut = port("out", "main", declaredOut)
|
|
405
483
|
const ai = {
|
|
406
484
|
id: uuid(),
|
|
407
485
|
kind: "ai",
|
|
@@ -423,7 +501,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
423
501
|
{ from_port_id: waitOut.id, to_port_id: progIn.id },
|
|
424
502
|
],
|
|
425
503
|
)
|
|
426
|
-
expect(resolved.get(progIn.id)).toEqual(
|
|
504
|
+
expect(resolved.get(progIn.id)).toEqual(declaredOut)
|
|
427
505
|
})
|
|
428
506
|
|
|
429
507
|
// start の run 入力契約は接続先から導出する
|
|
@@ -534,7 +612,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
534
612
|
})
|
|
535
613
|
|
|
536
614
|
it("propagateDerivedPorts:schema を書き戻し、変化のないノードは同じ参照を返す", () => {
|
|
537
|
-
const progOut = port("out", "main",
|
|
615
|
+
const progOut = port("out", "main", declaredOut)
|
|
538
616
|
const program = {
|
|
539
617
|
id: uuid(),
|
|
540
618
|
kind: "program",
|
|
@@ -551,7 +629,10 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
551
629
|
[{ from_port_id: progOut.id, to_port_id: waitIn.id }],
|
|
552
630
|
)
|
|
553
631
|
expect(next[0]).toBe(program) // 宣言のみ=無変更
|
|
554
|
-
expect(next[1]?.ports.map((p) => p.schema)).toEqual([
|
|
632
|
+
expect(next[1]?.ports.map((p) => p.schema)).toEqual([
|
|
633
|
+
declaredOut,
|
|
634
|
+
declaredOut,
|
|
635
|
+
])
|
|
555
636
|
// 接続を消すと any に戻る
|
|
556
637
|
const cleared = propagateDerivedPorts(next, [])
|
|
557
638
|
expect(cleared[1]?.ports.map((p) => p.schema)).toEqual([
|
|
@@ -562,7 +643,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
562
643
|
|
|
563
644
|
it("propagateDerivedPorts:side / offset(表示位置)を落とさない", () => {
|
|
564
645
|
const progOut = {
|
|
565
|
-
...port("out", "main",
|
|
646
|
+
...port("out", "main", declaredOut),
|
|
566
647
|
side: "top" as const,
|
|
567
648
|
offset: 0.3,
|
|
568
649
|
}
|