@mawaru/sdk 0.40.0 → 0.41.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/_schemas/graph.ts +0 -5
- package/_schemas/human-manifest.test.ts +39 -101
- package/_schemas/human-manifest.ts +25 -152
- package/_schemas/port-spec.test.ts +33 -92
- package/_schemas/port-spec.ts +35 -44
- package/dist/_cli/login.js +15 -1
- package/dist/_cli/previewApi.d.ts +1 -1
- package/dist/_cli/previewCommand.d.ts +0 -8
- package/dist/_cli/previewCommand.js +37 -95
- package/dist/_cli/previewFiles.d.ts +1 -2
- package/dist/_cli/previewFiles.js +18 -42
- package/dist/_schemas/graph.d.ts +0 -15
- package/dist/_schemas/graph.js +0 -5
- package/dist/_schemas/human-manifest.d.ts +6 -24
- package/dist/_schemas/human-manifest.js +24 -116
- package/dist/_schemas/port-spec.d.ts +1 -4
- package/dist/_schemas/port-spec.js +25 -34
- package/dist/cli.js +1 -2
- package/dist/typegen.d.ts +2 -2
- package/dist/typegen.js +21 -21
- package/dist/validate.js +9 -7
- package/dist/views/_humanProps.d.ts +10 -0
- package/dist/views/_humanProps.js +11 -0
- package/dist/views/{index.d.ts → components.d.ts} +0 -1
- package/dist/views/components.js +12 -0
- package/dist/views/host.d.ts +8 -3
- package/dist/views/host.js +5 -5
- package/dist/views/human.d.ts +49 -68
- package/dist/views/human.js +5 -6
- package/dist/views/protocol.d.ts +13 -3
- package/dist/views/protocol.js +2 -2
- package/dist/views/runtime.d.ts +2 -3
- package/dist/views/runtime.js +24 -24
- package/dist/views/sample.d.ts +22 -0
- package/dist/views/sample.js +38 -0
- package/docs/development.md +30 -31
- package/package.json +5 -1
- package/skills/create-loop/SKILL.md +3 -2
- package/templates/CLAUDE.md +2 -0
- package/views/_humanProps.ts +27 -0
- package/views/components.ts +16 -0
- package/views/host.ts +9 -5
- package/views/human.ts +71 -79
- package/views/protocol.ts +29 -6
- package/views/runtime.tsx +36 -45
- package/views/sample.tsx +94 -0
- package/dist/_cli/openBrowser.d.ts +0 -1
- package/dist/_cli/openBrowser.js +0 -15
- package/dist/views/_approval/ApprovalBar.d.ts +0 -20
- package/dist/views/_approval/ApprovalBar.js +0 -74
- package/dist/views/_approvalActions.d.ts +0 -18
- package/dist/views/_approvalActions.js +0 -10
- package/dist/views/index.js +0 -12
- package/views/_approval/ApprovalBar.tsx +0 -239
- package/views/_approvalActions.tsx +0 -31
- package/views/index.ts +0 -16
package/_schemas/graph.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { z } from "zod"
|
|
2
|
-
import { humanDeclarationSchema } from "./human-manifest.js"
|
|
3
2
|
import {
|
|
4
3
|
graphPortSchema,
|
|
5
4
|
jsonSchemaSchema,
|
|
@@ -170,10 +169,6 @@ export const humanConfigSchema = z.object({
|
|
|
170
169
|
.optional(),
|
|
171
170
|
// 読むブランチ(省略時はデフォルトブランチ)。publish でその先頭の commit に固定する
|
|
172
171
|
ref: z.string().min(1).optional(),
|
|
173
|
-
// 宣言の写し(in / approve / reject の型)。伝播はこれを読む。human_dir を選んだときに
|
|
174
|
-
// 一覧 API(GET /tenants/:id/github/humans)の宣言を入れる。省略すると保存時に mawaru が repo の
|
|
175
|
-
// config.json から読む(下書きに同じ human_dir の同じノードがあればその写しを保つ)
|
|
176
|
-
declaration: humanDeclarationSchema.optional(),
|
|
177
172
|
assignment: z
|
|
178
173
|
.object({
|
|
179
174
|
strategy: z.enum(["fixed", "round_robin"]).default("fixed"),
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest"
|
|
2
|
-
import {
|
|
3
|
-
humanDeclarationOfManifest,
|
|
4
|
-
humanDeclarationSchema,
|
|
5
|
-
humanManifestSchema,
|
|
6
|
-
STANDARD_HUMAN_DECLARATION,
|
|
7
|
-
} from "./human-manifest.js"
|
|
2
|
+
import { humanManifestSchema } from "./human-manifest.js"
|
|
8
3
|
import { fileSchema, instructionSchema } from "./port-spec.js"
|
|
9
4
|
|
|
10
5
|
const pr = {
|
|
@@ -12,118 +7,61 @@ const pr = {
|
|
|
12
7
|
properties: {
|
|
13
8
|
title: { type: "string", description: "PR のタイトル" },
|
|
14
9
|
gifs: { type: "array", items: fileSchema() },
|
|
15
|
-
count: { type: "integer" },
|
|
16
10
|
},
|
|
17
11
|
required: ["title"],
|
|
18
12
|
}
|
|
19
13
|
|
|
20
|
-
const
|
|
21
|
-
const parsed =
|
|
22
|
-
return parsed.success
|
|
23
|
-
? []
|
|
24
|
-
: parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
14
|
+
const messagesOf = (value: unknown) => {
|
|
15
|
+
const parsed = humanManifestSchema.safeParse(value)
|
|
16
|
+
return parsed.success ? [] : parsed.error.issues.map((i) => i.message)
|
|
25
17
|
}
|
|
26
18
|
|
|
27
|
-
describe("
|
|
28
|
-
it("
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// 未宣言({})も宣言の1つ(スキーマ未定義)
|
|
34
|
-
expect(issuesOf({ in: {}, approve: "T", reject: {} })).toEqual([])
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it("type の配列(nullable)は場所つきで弾く", () => {
|
|
38
|
-
expect(
|
|
39
|
-
issuesOf({
|
|
40
|
-
in: {
|
|
41
|
-
type: "object",
|
|
42
|
-
properties: { summary: { type: ["string", "null"] } },
|
|
43
|
-
},
|
|
44
|
-
approve: "T",
|
|
19
|
+
describe("humanManifestSchema(nodes/human/<dir>/config.json)", () => {
|
|
20
|
+
it("in・approve・reject を書いた宣言を通す(追加の出口も書ける)", () => {
|
|
21
|
+
const config = {
|
|
22
|
+
inputs: { in: { schema: pr } },
|
|
23
|
+
outputs: {
|
|
24
|
+
approve: { type: "array", items: pr },
|
|
45
25
|
reject: instructionSchema(),
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
26
|
+
notion: pr,
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
// refs はエディタが転写する生成物なので、無ければ空になる
|
|
30
|
+
expect(humanManifestSchema.parse(config)).toEqual({ ...config, refs: {} })
|
|
50
31
|
})
|
|
51
32
|
|
|
52
|
-
it("
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}),
|
|
63
|
-
).toEqual([
|
|
64
|
-
"in.type: type は object / array / string / number / integer / boolean のどれかにしてください(strin)",
|
|
65
|
-
"approve.properties: properties はオブジェクトで書いてください",
|
|
66
|
-
"reject.properties.list.items: items はスキーマ(オブジェクト)で書いてください",
|
|
67
|
-
"reject.required: required は文字列の配列で書いてください",
|
|
33
|
+
it("in・approve・reject のどれかが無ければ弾く(省略したときの決まりは無い)", () => {
|
|
34
|
+
const full = {
|
|
35
|
+
inputs: { in: { schema: pr } },
|
|
36
|
+
outputs: { approve: pr, reject: instructionSchema() },
|
|
37
|
+
}
|
|
38
|
+
const violation =
|
|
39
|
+
"human のポート構成は in(in) と out(approve / reject) が必須です(out は追加できます)"
|
|
40
|
+
expect(messagesOf({ ...full, inputs: {} })).toEqual([violation])
|
|
41
|
+
expect(messagesOf({ ...full, outputs: { approve: pr } })).toEqual([
|
|
42
|
+
violation,
|
|
68
43
|
])
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it("type の無い構造(properties / items だけ)を弾く", () => {
|
|
72
44
|
expect(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
reject: instructionSchema(),
|
|
77
|
-
}),
|
|
78
|
-
).toEqual([
|
|
79
|
-
"in.type: properties / items を書くときは type も書いてください",
|
|
80
|
-
])
|
|
45
|
+
messagesOf({ ...full, outputs: { reject: instructionSchema() } }),
|
|
46
|
+
).toEqual([violation])
|
|
47
|
+
expect(humanManifestSchema.safeParse({}).success).toBe(false)
|
|
81
48
|
})
|
|
82
49
|
|
|
83
|
-
it(
|
|
84
|
-
expect(issuesOf({ in: "T", approve: "T", reject: "T" })).not.toEqual([])
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
describe("humanManifestSchema(nodes/human/<dir>/config.json)", () => {
|
|
89
|
-
it("省略した口は上流のコピー(in)・in と同型(approve)・標準の差し戻し(reject)になる", () => {
|
|
90
|
-
const config = humanManifestSchema.parse({})
|
|
91
|
-
expect(humanDeclarationOfManifest(config)).toEqual(
|
|
92
|
-
STANDARD_HUMAN_DECLARATION,
|
|
93
|
-
)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it("書いた口の型をそのまま宣言にする", () => {
|
|
97
|
-
const config = humanManifestSchema.parse({
|
|
98
|
-
inputs: { in: { schema: pr } },
|
|
99
|
-
outputs: { approve: { type: "array", items: pr }, reject: pr },
|
|
100
|
-
})
|
|
101
|
-
expect(humanDeclarationOfManifest(config)).toEqual({
|
|
102
|
-
in: pr,
|
|
103
|
-
approve: { type: "array", items: pr },
|
|
104
|
-
reject: pr,
|
|
105
|
-
})
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it("in / approve / reject 以外の口・知らないキーは弾く", () => {
|
|
109
|
-
expect(
|
|
110
|
-
humanManifestSchema.safeParse({ inputs: { instruction: {} } }).success,
|
|
111
|
-
).toBe(false)
|
|
50
|
+
it("in 以外の入口は弾く", () => {
|
|
112
51
|
expect(
|
|
113
|
-
humanManifestSchema.safeParse({
|
|
52
|
+
humanManifestSchema.safeParse({
|
|
53
|
+
inputs: { in: { schema: pr }, instruction: { schema: pr } },
|
|
54
|
+
outputs: { approve: pr, reject: instructionSchema() },
|
|
55
|
+
}).success,
|
|
114
56
|
).toBe(false)
|
|
115
|
-
expect(humanManifestSchema.safeParse({ name: "x" }).success).toBe(false)
|
|
116
57
|
})
|
|
117
58
|
|
|
118
|
-
it("
|
|
119
|
-
const parsed = humanManifestSchema.safeParse({
|
|
120
|
-
inputs: { in: { schema: { type: ["string", "null"] } } },
|
|
121
|
-
})
|
|
122
|
-
expect(parsed.success).toBe(false)
|
|
59
|
+
it('上流のコピー("T")は書けない(型は具体的に書く)', () => {
|
|
123
60
|
expect(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
61
|
+
humanManifestSchema.safeParse({
|
|
62
|
+
inputs: { in: { schema: "T" } },
|
|
63
|
+
outputs: { approve: "T", reject: instructionSchema() },
|
|
64
|
+
}).success,
|
|
65
|
+
).toBe(false)
|
|
128
66
|
})
|
|
129
67
|
})
|
|
@@ -1,158 +1,31 @@
|
|
|
1
1
|
import { z } from "zod"
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
// 正は実装を持つ側(顧客 repo の nodes/human/<dir>/config.json。実装を指さないノードは標準の宣言)。
|
|
11
|
-
// human ノードは実装を選んだ時点の写し(node_humans.declaration)を持ち、伝播はそれを読む
|
|
12
|
-
// (docs/tasks/wip/承認ビューの顧客repo配置.md の「宣言(ポート型)」)。
|
|
13
|
-
// "T"(COPY_UPSTREAM_SCHEMA)は「上流の out をそのまま受ける」(in)/「in と同型」(approve)。
|
|
14
|
-
// reject は具体型だけ(上流のコピーは意味を持たない)
|
|
15
|
-
|
|
16
|
-
export type HumanDeclaration = {
|
|
17
|
-
in: DeclaredPortSchema
|
|
18
|
-
approve: DeclaredPortSchema
|
|
19
|
-
reject: JsonSchema
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 宣言に書ける type。file は x-mawaru-type マーカー付きの object
|
|
23
|
-
const DECLARED_TYPES = [
|
|
24
|
-
"object",
|
|
25
|
-
"array",
|
|
26
|
-
"string",
|
|
27
|
-
"number",
|
|
28
|
-
"integer",
|
|
29
|
-
"boolean",
|
|
30
|
-
] as const
|
|
31
|
-
|
|
32
|
-
const isPlainObject = (value: unknown): value is Record<string, unknown> =>
|
|
33
|
-
typeof value === "object" && value !== null && !Array.isArray(value)
|
|
34
|
-
|
|
35
|
-
// JSON Schema の形の崩れを場所つきで返す。接続の比較(schemaFit)が扱える形だけを通す:
|
|
36
|
-
// 顧客 repo の宣言は mawaru のレビューを通らないので、壊れた型がノードに写る前に止める
|
|
37
|
-
const schemaIssues = (
|
|
38
|
-
schema: Record<string, unknown>,
|
|
39
|
-
path: (string | number)[],
|
|
40
|
-
): { path: (string | number)[]; message: string }[] => {
|
|
41
|
-
const issues: { path: (string | number)[]; message: string }[] = []
|
|
42
|
-
const { type, properties, required, items } = schema
|
|
43
|
-
if (Array.isArray(type)) {
|
|
44
|
-
issues.push({
|
|
45
|
-
path: [...path, "type"],
|
|
46
|
-
message:
|
|
47
|
-
"配列(nullable)は使えません。任意の値は required から外してください",
|
|
48
|
-
})
|
|
49
|
-
} else if (
|
|
50
|
-
type !== undefined &&
|
|
51
|
-
!DECLARED_TYPES.includes(type as (typeof DECLARED_TYPES)[number])
|
|
52
|
-
) {
|
|
53
|
-
issues.push({
|
|
54
|
-
path: [...path, "type"],
|
|
55
|
-
message: `type は ${DECLARED_TYPES.join(" / ")} のどれかにしてください(${String(type)})`,
|
|
56
|
-
})
|
|
57
|
-
} else if (
|
|
58
|
-
type === undefined &&
|
|
59
|
-
(properties !== undefined || items !== undefined)
|
|
60
|
-
) {
|
|
61
|
-
issues.push({
|
|
62
|
-
path: [...path, "type"],
|
|
63
|
-
message: "properties / items を書くときは type も書いてください",
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
if (properties !== undefined) {
|
|
67
|
-
if (!isPlainObject(properties)) {
|
|
68
|
-
issues.push({
|
|
69
|
-
path: [...path, "properties"],
|
|
70
|
-
message: "properties はオブジェクトで書いてください",
|
|
71
|
-
})
|
|
72
|
-
} else {
|
|
73
|
-
for (const [key, child] of Object.entries(properties)) {
|
|
74
|
-
if (!isPlainObject(child)) {
|
|
75
|
-
issues.push({
|
|
76
|
-
path: [...path, "properties", key],
|
|
77
|
-
message: "スキーマはオブジェクトで書いてください",
|
|
78
|
-
})
|
|
79
|
-
continue
|
|
80
|
-
}
|
|
81
|
-
issues.push(...schemaIssues(child, [...path, "properties", key]))
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
if (
|
|
86
|
-
required !== undefined &&
|
|
87
|
-
!(Array.isArray(required) && required.every((r) => typeof r === "string"))
|
|
88
|
-
) {
|
|
89
|
-
issues.push({
|
|
90
|
-
path: [...path, "required"],
|
|
91
|
-
message: "required は文字列の配列で書いてください",
|
|
92
|
-
})
|
|
93
|
-
}
|
|
94
|
-
if (items !== undefined) {
|
|
95
|
-
if (!isPlainObject(items)) {
|
|
96
|
-
issues.push({
|
|
97
|
-
path: [...path, "items"],
|
|
98
|
-
message: "items はスキーマ(オブジェクト)で書いてください",
|
|
99
|
-
})
|
|
100
|
-
} else {
|
|
101
|
-
issues.push(...schemaIssues(items, [...path, "items"]))
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return issues
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// 宣言に書く1つの型(検査つき)
|
|
108
|
-
const checkedSchema = jsonSchemaSchema.superRefine((schema, ctx) => {
|
|
109
|
-
for (const issue of schemaIssues(schema, []))
|
|
110
|
-
ctx.addIssue({ code: "custom", ...issue })
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
const declaredPortSchema = z.union([
|
|
114
|
-
z.literal(COPY_UPSTREAM_SCHEMA),
|
|
115
|
-
checkedSchema,
|
|
116
|
-
])
|
|
117
|
-
|
|
118
|
-
export const humanDeclarationSchema = z.object({
|
|
119
|
-
in: declaredPortSchema,
|
|
120
|
-
approve: declaredPortSchema,
|
|
121
|
-
reject: checkedSchema,
|
|
122
|
-
}) satisfies z.ZodType<HumanDeclaration>
|
|
123
|
-
|
|
124
|
-
// 標準ビュー(common/standard)の宣言:上流の型をそのまま受けて出し、差し戻しは標準の指示フォーム
|
|
125
|
-
export const STANDARD_HUMAN_DECLARATION: HumanDeclaration = {
|
|
126
|
-
in: COPY_UPSTREAM_SCHEMA,
|
|
127
|
-
approve: COPY_UPSTREAM_SCHEMA,
|
|
128
|
-
reject: instructionSchema(),
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ---- 顧客 repo の nodes/human/<dir>/config.json ----
|
|
132
|
-
// 形は AI の config.json に揃える(inputs の値は { schema }、outputs の値は素の JSON Schema)。
|
|
133
|
-
// 口は in / approve / reject 固定。省略した口は STANDARD_HUMAN_DECLARATION と同じ扱い
|
|
2
|
+
import { jsonSchemaSchema, portKeySchema } from "./node.js"
|
|
3
|
+
import { kindPortsViolation } from "./port-spec.js"
|
|
4
|
+
|
|
5
|
+
// 顧客 repo の nodes/human/<dir>/config.json(human ノードの実装の入出力の宣言)。
|
|
6
|
+
// program / AI の config.json と同じく、エディタがディレクトリを選んだときに inputs / outputs から
|
|
7
|
+
// ports を起こし、ポートの編集は保存時にここへ書き戻される(実行時の正は ports テーブルのまま)。
|
|
8
|
+
// 形は AI に揃える(inputs の値は { schema }、outputs の値は素の JSON Schema)。
|
|
9
|
+
// 口の構成(in 1つ・approve / reject は必須・追加の出口は自由)は kind のポート構成の規則をそのまま使う
|
|
134
10
|
export const humanManifestSchema = z
|
|
135
11
|
.object({
|
|
136
|
-
inputs: z
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
12
|
+
inputs: z.record(z.string(), z.object({ schema: jsonSchemaSchema })),
|
|
13
|
+
outputs: z.record(z.string(), jsonSchemaSchema),
|
|
14
|
+
// refs=ループ変数の定義の転写(program と同じ。エディタのグラフ保存が一方向に書く生成物)
|
|
15
|
+
refs: z.record(portKeySchema, jsonSchemaSchema).default({}),
|
|
16
|
+
})
|
|
17
|
+
.superRefine((manifest, ctx) => {
|
|
18
|
+
const violation = kindPortsViolation("human", [
|
|
19
|
+
...Object.keys(manifest.inputs).map((key) => ({
|
|
20
|
+
io: "in" as const,
|
|
21
|
+
key,
|
|
22
|
+
})),
|
|
23
|
+
...Object.keys(manifest.outputs).map((key) => ({
|
|
24
|
+
io: "out" as const,
|
|
25
|
+
key,
|
|
26
|
+
})),
|
|
27
|
+
])
|
|
28
|
+
if (violation) ctx.addIssue({ code: "custom", message: violation })
|
|
147
29
|
})
|
|
148
|
-
.strict()
|
|
149
30
|
|
|
150
31
|
export type HumanManifest = z.infer<typeof humanManifestSchema>
|
|
151
|
-
|
|
152
|
-
export const humanDeclarationOfManifest = (
|
|
153
|
-
config: HumanManifest,
|
|
154
|
-
): HumanDeclaration => ({
|
|
155
|
-
in: config.inputs?.in?.schema ?? COPY_UPSTREAM_SCHEMA,
|
|
156
|
-
approve: config.outputs?.approve ?? COPY_UPSTREAM_SCHEMA,
|
|
157
|
-
reject: config.outputs?.reject ?? instructionSchema(),
|
|
158
|
-
})
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest"
|
|
2
|
-
import type { HumanDeclaration } from "./human-manifest.js"
|
|
3
2
|
import type { GraphPort, JsonSchema } from "./node.js"
|
|
4
3
|
import {
|
|
5
4
|
arrayOf,
|
|
@@ -154,20 +153,17 @@ describe("kindPortsViolation(kind 別ポート構成)", () => {
|
|
|
154
153
|
})
|
|
155
154
|
})
|
|
156
155
|
|
|
157
|
-
// human
|
|
158
|
-
const
|
|
159
|
-
nodes: N[],
|
|
160
|
-
declaration: HumanDeclaration,
|
|
161
|
-
) =>
|
|
156
|
+
// 実装(nodes/human/<dir>/)を指す human にする
|
|
157
|
+
const withHumanDir = <N extends { kind: string }>(nodes: N[]) =>
|
|
162
158
|
nodes.map((node) =>
|
|
163
|
-
node.kind === "human" ? { ...node, human: {
|
|
159
|
+
node.kind === "human" ? { ...node, human: { human_dir: "review" } } : node,
|
|
164
160
|
)
|
|
165
161
|
|
|
166
162
|
describe("型伝播(導出ポートの解決)", () => {
|
|
167
163
|
it.each([
|
|
168
164
|
"notion_task",
|
|
169
165
|
"main",
|
|
170
|
-
])("Humanの追加出口 %s
|
|
166
|
+
])("Humanの追加出口 %s の宣言型は伝播で上書きしない", (key) => {
|
|
171
167
|
const extra = port("out", key, {
|
|
172
168
|
type: "object",
|
|
173
169
|
properties: { title: { type: "string" } },
|
|
@@ -183,15 +179,10 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
183
179
|
extra,
|
|
184
180
|
],
|
|
185
181
|
}
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
reject: { type: "string" },
|
|
191
|
-
}),
|
|
192
|
-
[],
|
|
193
|
-
)
|
|
194
|
-
expect(resolved.get(extra.id)).toEqual(extra.schema)
|
|
182
|
+
for (const nodes of [[human], withHumanDir([human])]) {
|
|
183
|
+
const resolved = resolvePortSchemas(nodes, [])
|
|
184
|
+
expect(resolved.get(extra.id)).toEqual(extra.schema)
|
|
185
|
+
}
|
|
195
186
|
})
|
|
196
187
|
|
|
197
188
|
// 伝播テスト用の任意の宣言型(中身の形に意味はない)
|
|
@@ -201,10 +192,9 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
201
192
|
required: ["text"],
|
|
202
193
|
}
|
|
203
194
|
|
|
204
|
-
// human
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
it("ai → human 直結(コピー宣言):in も approve も上流の out と同型、reject はビューの宣言型", () => {
|
|
195
|
+
// 実装を指さない human(標準の承認画面)は wait と同じ素通し。上流の kind は見ない
|
|
196
|
+
// → docs/tasks/wip/承認ビューの顧客repo配置.md の「ポート型」
|
|
197
|
+
it("実装を指さない human:in も approve も上流の out と同型、reject は標準の差し戻し", () => {
|
|
208
198
|
const aiOut = port("out", "main", declaredOut)
|
|
209
199
|
const ai = {
|
|
210
200
|
id: uuid(),
|
|
@@ -220,11 +210,7 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
220
210
|
ports: [humanIn, approve, reject],
|
|
221
211
|
}
|
|
222
212
|
const resolved = resolvePortSchemas(
|
|
223
|
-
|
|
224
|
-
in: "T",
|
|
225
|
-
approve: "T",
|
|
226
|
-
reject: instructionSchema(),
|
|
227
|
-
}),
|
|
213
|
+
[ai, human],
|
|
228
214
|
[{ from_port_id: aiOut.id, to_port_id: humanIn.id }],
|
|
229
215
|
)
|
|
230
216
|
// 上流が AI でも中身を取り出さない:AI の出力形式がそのまま下流へ流れる
|
|
@@ -233,25 +219,17 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
233
219
|
expect(resolved.get(reject.id)).toEqual(instructionSchema())
|
|
234
220
|
})
|
|
235
221
|
|
|
236
|
-
describe("
|
|
222
|
+
describe("実装(nodes/human/<dir>/)を指す human は program / ai と同じ", () => {
|
|
237
223
|
const viewIn = {
|
|
238
224
|
type: "object",
|
|
239
|
-
properties: {
|
|
240
|
-
|
|
241
|
-
type: "object",
|
|
242
|
-
properties: { prs: { type: "array", items: { type: "object" } } },
|
|
243
|
-
required: ["prs"],
|
|
244
|
-
},
|
|
245
|
-
description: { type: "string" },
|
|
246
|
-
},
|
|
247
|
-
required: ["data", "description"],
|
|
225
|
+
properties: { prs: { type: "array", items: { type: "object" } } },
|
|
226
|
+
required: ["prs"],
|
|
248
227
|
}
|
|
249
228
|
const viewOut = {
|
|
250
229
|
type: "object",
|
|
251
|
-
properties: {
|
|
252
|
-
required: ["
|
|
230
|
+
properties: { merged: { type: "boolean" } },
|
|
231
|
+
required: ["merged"],
|
|
253
232
|
}
|
|
254
|
-
// reject もビューの宣言(具体型のみ。コピー指示は意味を持たない)
|
|
255
233
|
const viewReject = {
|
|
256
234
|
type: "object",
|
|
257
235
|
properties: { reason: { type: "string" } },
|
|
@@ -264,91 +242,54 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
264
242
|
kind: upstreamKind,
|
|
265
243
|
ports: [port("in", "in"), out],
|
|
266
244
|
}
|
|
267
|
-
const humanIn = port("in", "in")
|
|
268
|
-
const approve = port("out", "approve")
|
|
269
|
-
const reject = port("out", "reject")
|
|
245
|
+
const humanIn = port("in", "in", viewIn)
|
|
246
|
+
const approve = port("out", "approve", viewOut)
|
|
247
|
+
const reject = port("out", "reject", viewReject)
|
|
270
248
|
const human = {
|
|
271
249
|
id: uuid(),
|
|
272
250
|
kind: "human",
|
|
251
|
+
human: { human_dir: "review" },
|
|
273
252
|
ports: [humanIn, approve, reject],
|
|
274
253
|
}
|
|
275
254
|
return { upstream, human, out, humanIn, approve, reject }
|
|
276
255
|
}
|
|
277
256
|
|
|
278
|
-
it("
|
|
257
|
+
it("out(approve・reject)は宣言のまま(上流の kind に依らない)", () => {
|
|
279
258
|
for (const kind of ["ai", "program"]) {
|
|
280
259
|
const { upstream, human, out, humanIn, approve, reject } = build(
|
|
281
260
|
kind,
|
|
282
261
|
declaredOut,
|
|
283
262
|
)
|
|
284
263
|
const resolved = resolvePortSchemas(
|
|
285
|
-
|
|
286
|
-
in: viewIn,
|
|
287
|
-
approve: viewOut,
|
|
288
|
-
reject: viewReject,
|
|
289
|
-
}),
|
|
264
|
+
[upstream, human],
|
|
290
265
|
[{ from_port_id: out.id, to_port_id: humanIn.id }],
|
|
291
266
|
)
|
|
292
|
-
expect(resolved.get(humanIn.id)).toEqual(viewIn)
|
|
293
267
|
expect(resolved.get(approve.id)).toEqual(viewOut)
|
|
294
268
|
expect(resolved.get(reject.id)).toEqual(viewReject)
|
|
295
269
|
}
|
|
296
270
|
})
|
|
297
271
|
|
|
298
|
-
it("
|
|
272
|
+
it("in は上流の具体型を写す(program / ai の in と同じ鏡映)", () => {
|
|
299
273
|
const { upstream, human, out, humanIn } = build("ai", declaredOut)
|
|
300
274
|
const resolved = resolvePortSchemas(
|
|
301
|
-
|
|
302
|
-
in: viewIn,
|
|
303
|
-
approve: viewOut,
|
|
304
|
-
reject: viewReject,
|
|
305
|
-
}),
|
|
306
|
-
[{ from_port_id: out.id, to_port_id: humanIn.id }],
|
|
307
|
-
)
|
|
308
|
-
expect(resolved.get(out.id)).toEqual(declaredOut)
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
it("コピー宣言(標準ビュー)は上流の型をそのまま in と approve へ流す", () => {
|
|
312
|
-
const { upstream, human, out, humanIn, approve } = build(
|
|
313
|
-
"ai",
|
|
314
|
-
declaredOut,
|
|
315
|
-
)
|
|
316
|
-
const resolved = resolvePortSchemas(
|
|
317
|
-
withViewDeclaration([upstream, human], {
|
|
318
|
-
in: "T",
|
|
319
|
-
approve: "T",
|
|
320
|
-
reject: viewReject,
|
|
321
|
-
}),
|
|
275
|
+
[upstream, human],
|
|
322
276
|
[{ from_port_id: out.id, to_port_id: humanIn.id }],
|
|
323
277
|
)
|
|
324
278
|
expect(resolved.get(humanIn.id)).toEqual(declaredOut)
|
|
325
|
-
|
|
279
|
+
// 上流の out は書き換えない(逆伝播しない)
|
|
280
|
+
expect(resolved.get(out.id)).toEqual(declaredOut)
|
|
326
281
|
})
|
|
327
282
|
|
|
328
|
-
it("
|
|
329
|
-
const humanIn =
|
|
330
|
-
const
|
|
331
|
-
const reject = port("out", "reject")
|
|
332
|
-
const human = {
|
|
333
|
-
id: uuid(),
|
|
334
|
-
kind: "human",
|
|
335
|
-
ports: [humanIn, approve, reject],
|
|
336
|
-
}
|
|
337
|
-
const resolved = resolvePortSchemas(
|
|
338
|
-
withViewDeclaration([human], {
|
|
339
|
-
in: viewIn,
|
|
340
|
-
approve: viewOut,
|
|
341
|
-
reject: viewReject,
|
|
342
|
-
}),
|
|
343
|
-
[],
|
|
344
|
-
)
|
|
283
|
+
it("未接続の in は宣言のまま", () => {
|
|
284
|
+
const { human, humanIn, approve, reject } = build("ai", declaredOut)
|
|
285
|
+
const resolved = resolvePortSchemas([human], [])
|
|
345
286
|
expect(resolved.get(humanIn.id)).toEqual(viewIn)
|
|
346
287
|
expect(resolved.get(approve.id)).toEqual(viewOut)
|
|
347
288
|
expect(resolved.get(reject.id)).toEqual(viewReject)
|
|
348
289
|
})
|
|
349
290
|
})
|
|
350
291
|
|
|
351
|
-
it("ai → wait → human:素通しで上流の宣言型が伝播し、reject
|
|
292
|
+
it("ai → wait → human:素通しで上流の宣言型が伝播し、reject は標準の差し戻し", () => {
|
|
352
293
|
// ai の in は宣言型(nodes/ai/<dir>/config.json の inputs.in 由来。実行repoの構造見直し)
|
|
353
294
|
const aiInSchema = {
|
|
354
295
|
type: "object",
|
|
@@ -383,8 +324,8 @@ describe("型伝播(導出ポートの解決)", () => {
|
|
|
383
324
|
expect(resolved.get(humanIn.id)).toEqual(declaredOut)
|
|
384
325
|
// approve は in と同型(上流の kind による中身の取り出しはしない)
|
|
385
326
|
expect(resolved.get(approve.id)).toEqual(declaredOut)
|
|
386
|
-
// reject
|
|
387
|
-
expect(resolved.get(reject.id)).toEqual(
|
|
327
|
+
// reject は標準の承認画面の差し戻し(指示+参考ファイル)
|
|
328
|
+
expect(resolved.get(reject.id)).toEqual(instructionSchema())
|
|
388
329
|
// ai の in は宣言型がそのまま残る(const 扱いは廃止)
|
|
389
330
|
expect(resolved.get(aiIn.id)).toEqual(aiInSchema)
|
|
390
331
|
})
|