@ccdd/core 3.3.0 → 4.0.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/README.md +69 -62
- package/dist/src/artifact-scope.d.ts +6 -0
- package/dist/src/artifact-scope.js +27 -0
- package/dist/src/artifact-scope.js.map +1 -0
- package/dist/src/definitions.d.ts +33 -23
- package/dist/src/sdk.d.ts +3 -8
- package/dist/src/sdk.js +2 -3
- package/dist/src/sdk.js.map +1 -1
- package/dist/src/tools/contracts.d.ts +34 -78
- package/examples/artifact-folders/README.md +18 -0
- package/examples/artifact-folders/coding-style/ccdd.json +128 -0
- package/examples/artifact-folders/coding-style/style.md +3 -0
- package/examples/artifact-folders/explosion/blind-pair.mjs +19 -0
- package/examples/artifact-folders/explosion/ccdd.json +220 -0
- package/examples/artifact-folders/explosion/effect/ccdd.json +128 -0
- package/examples/artifact-folders/explosion/preview/ccdd.json +142 -0
- package/examples/artifact-folders/theme-image/ccdd.json +128 -0
- package/examples/artifact-folders/theme-image/theme.png +0 -0
- package/examples/computed-views/README.md +12 -0
- package/examples/computed-views/checkout/ccdd.json +133 -0
- package/examples/computed-views/search/ccdd.json +133 -0
- package/examples/computed-views/view.mjs +13 -0
- package/examples/custom-text-reader/README.md +7 -19
- package/examples/custom-text-reader/spec/ccdd.json +60 -0
- package/examples/custom-text-reader/view.mjs +20 -0
- package/examples/custom-text-reader/why/ccdd.json +46 -0
- package/package.json +21 -7
- package/examples/artifact-groups/README.md +0 -60
- package/examples/artifact-groups/ccdd.config.ts +0 -37
- package/examples/custom-text-reader/ccdd.config.ts +0 -64
- package/examples/generated-artifacts/README.md +0 -55
- package/examples/generated-artifacts/ccdd.config.ts +0 -86
- /package/examples/{artifact-groups → artifact-folders/explosion/effect}/effect.md +0 -0
- /package/examples/{artifact-groups → artifact-folders/explosion/preview}/preview.png +0 -0
- /package/examples/{generated-artifacts/scenarios/checkout.json → computed-views/checkout/scenario.json} +0 -0
- /package/examples/{generated-artifacts/scenarios/search.json → computed-views/search/scenario.json} +0 -0
- /package/examples/custom-text-reader/{spec.md → spec/spec.md} +0 -0
- /package/examples/custom-text-reader/{why.md → why/why.md} +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "checkout",
|
|
3
|
+
"views": {
|
|
4
|
+
"agentTools": {
|
|
5
|
+
"overview": {
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "Inspect {artifactName} with overview.",
|
|
8
|
+
"inputSchema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {},
|
|
11
|
+
"additionalProperties": false
|
|
12
|
+
},
|
|
13
|
+
"resultKinds": [
|
|
14
|
+
"json"
|
|
15
|
+
],
|
|
16
|
+
"observation": "content",
|
|
17
|
+
"executionPaths": [
|
|
18
|
+
"view.mjs"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"script": {
|
|
22
|
+
"command": "node",
|
|
23
|
+
"args": [
|
|
24
|
+
"../view.mjs",
|
|
25
|
+
"overview"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"detail": {
|
|
30
|
+
"metadata": {
|
|
31
|
+
"description": "Inspect {artifactName} with detail.",
|
|
32
|
+
"inputSchema": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"id": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"minLength": 1
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"additionalProperties": false,
|
|
41
|
+
"required": [
|
|
42
|
+
"id"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"resultKinds": [
|
|
46
|
+
"json"
|
|
47
|
+
],
|
|
48
|
+
"observation": "content",
|
|
49
|
+
"executionPaths": [
|
|
50
|
+
"view.mjs"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"script": {
|
|
54
|
+
"command": "node",
|
|
55
|
+
"args": [
|
|
56
|
+
"../view.mjs",
|
|
57
|
+
"detail"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"humanTools": {
|
|
63
|
+
"overview": {
|
|
64
|
+
"metadata": {
|
|
65
|
+
"description": "Inspect {artifactName} with overview.",
|
|
66
|
+
"inputSchema": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"properties": {},
|
|
69
|
+
"additionalProperties": false
|
|
70
|
+
},
|
|
71
|
+
"resultKinds": [
|
|
72
|
+
"json"
|
|
73
|
+
],
|
|
74
|
+
"observation": "content",
|
|
75
|
+
"executionPaths": [
|
|
76
|
+
"view.mjs"
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
"script": {
|
|
80
|
+
"command": "node",
|
|
81
|
+
"args": [
|
|
82
|
+
"../view.mjs",
|
|
83
|
+
"overview"
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"detail": {
|
|
88
|
+
"metadata": {
|
|
89
|
+
"description": "Inspect {artifactName} with detail.",
|
|
90
|
+
"inputSchema": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"properties": {
|
|
93
|
+
"id": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"minLength": 1
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"additionalProperties": false,
|
|
99
|
+
"required": [
|
|
100
|
+
"id"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
"resultKinds": [
|
|
104
|
+
"json"
|
|
105
|
+
],
|
|
106
|
+
"observation": "content",
|
|
107
|
+
"executionPaths": [
|
|
108
|
+
"view.mjs"
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
"script": {
|
|
112
|
+
"command": "node",
|
|
113
|
+
"args": [
|
|
114
|
+
"../view.mjs",
|
|
115
|
+
"detail"
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"critics": [
|
|
122
|
+
{
|
|
123
|
+
"id": "review",
|
|
124
|
+
"title": "Review the checkout scenario",
|
|
125
|
+
"profile": {
|
|
126
|
+
"kind": "human"
|
|
127
|
+
},
|
|
128
|
+
"payload": {
|
|
129
|
+
"instruction": "Read the overview of {checkout}, then inspect every listed detail. Decide whether observations satisfy each criterion. Cite detail IDs and explain missing or contradictory evidence."
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "search",
|
|
3
|
+
"views": {
|
|
4
|
+
"agentTools": {
|
|
5
|
+
"overview": {
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "Inspect {artifactName} with overview.",
|
|
8
|
+
"inputSchema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {},
|
|
11
|
+
"additionalProperties": false
|
|
12
|
+
},
|
|
13
|
+
"resultKinds": [
|
|
14
|
+
"json"
|
|
15
|
+
],
|
|
16
|
+
"observation": "content",
|
|
17
|
+
"executionPaths": [
|
|
18
|
+
"view.mjs"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"script": {
|
|
22
|
+
"command": "node",
|
|
23
|
+
"args": [
|
|
24
|
+
"../view.mjs",
|
|
25
|
+
"overview"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"detail": {
|
|
30
|
+
"metadata": {
|
|
31
|
+
"description": "Inspect {artifactName} with detail.",
|
|
32
|
+
"inputSchema": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"id": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"minLength": 1
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"additionalProperties": false,
|
|
41
|
+
"required": [
|
|
42
|
+
"id"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"resultKinds": [
|
|
46
|
+
"json"
|
|
47
|
+
],
|
|
48
|
+
"observation": "content",
|
|
49
|
+
"executionPaths": [
|
|
50
|
+
"view.mjs"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"script": {
|
|
54
|
+
"command": "node",
|
|
55
|
+
"args": [
|
|
56
|
+
"../view.mjs",
|
|
57
|
+
"detail"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"humanTools": {
|
|
63
|
+
"overview": {
|
|
64
|
+
"metadata": {
|
|
65
|
+
"description": "Inspect {artifactName} with overview.",
|
|
66
|
+
"inputSchema": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"properties": {},
|
|
69
|
+
"additionalProperties": false
|
|
70
|
+
},
|
|
71
|
+
"resultKinds": [
|
|
72
|
+
"json"
|
|
73
|
+
],
|
|
74
|
+
"observation": "content",
|
|
75
|
+
"executionPaths": [
|
|
76
|
+
"view.mjs"
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
"script": {
|
|
80
|
+
"command": "node",
|
|
81
|
+
"args": [
|
|
82
|
+
"../view.mjs",
|
|
83
|
+
"overview"
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"detail": {
|
|
88
|
+
"metadata": {
|
|
89
|
+
"description": "Inspect {artifactName} with detail.",
|
|
90
|
+
"inputSchema": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"properties": {
|
|
93
|
+
"id": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"minLength": 1
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"additionalProperties": false,
|
|
99
|
+
"required": [
|
|
100
|
+
"id"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
"resultKinds": [
|
|
104
|
+
"json"
|
|
105
|
+
],
|
|
106
|
+
"observation": "content",
|
|
107
|
+
"executionPaths": [
|
|
108
|
+
"view.mjs"
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
"script": {
|
|
112
|
+
"command": "node",
|
|
113
|
+
"args": [
|
|
114
|
+
"../view.mjs",
|
|
115
|
+
"detail"
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"critics": [
|
|
122
|
+
{
|
|
123
|
+
"id": "review",
|
|
124
|
+
"title": "Review the search scenario",
|
|
125
|
+
"profile": {
|
|
126
|
+
"kind": "human"
|
|
127
|
+
},
|
|
128
|
+
"payload": {
|
|
129
|
+
"instruction": "Read the overview of {search}, then inspect every listed detail. Decide whether observations satisfy each criterion. Cite detail IDs and explain missing or contradictory evidence."
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
let text = '';
|
|
4
|
+
for await (const chunk of process.stdin) text += chunk;
|
|
5
|
+
const { version, context, args } = JSON.parse(text);
|
|
6
|
+
if (version !== 1) throw new Error('Unsupported request version.');
|
|
7
|
+
const scenario = JSON.parse(await readFile(join(context.artifactPath, 'scenario.json'), 'utf8'));
|
|
8
|
+
if (!Array.isArray(scenario.details) || !Array.isArray(scenario.criteria)) throw new Error('Invalid scenario.');
|
|
9
|
+
const data = process.argv[2] === 'overview'
|
|
10
|
+
? { name: scenario.name, objective: scenario.objective, criteria: scenario.criteria, detailIds: scenario.details.map(item => item.id) }
|
|
11
|
+
: scenario.details.find(item => item.id === args.id);
|
|
12
|
+
if (!data) throw new Error('Unknown scenario detail.');
|
|
13
|
+
process.stdout.write(JSON.stringify({ content: [{ type: 'json', data }], observation: { kind: 'content' } }));
|
|
@@ -1,25 +1,13 @@
|
|
|
1
|
-
# Custom
|
|
1
|
+
# Custom text reader
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`why/ccdd.json` declares an explicit basis. `spec/ccdd.json` owns its alignment Critic and reader. The instruction `{why}` derives the dependency; no `target`, `deps`, type registry or config factory is needed.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Install `@ccdd/core` and `@ccdd/project` in this example directory. The custom `view.mjs` requires only Node; default tools are optional.
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
npm init -y
|
|
12
|
-
npm pkg set type=module
|
|
13
|
-
npm install --ignore-scripts @ccdd/core@3.1.0 @ccdd/project@3.1.0
|
|
14
|
-
npx ccdd tools check --artifact spec --for agent --tool read
|
|
15
|
-
npx ccdd tools check --artifact spec --for agent --tool read --execute --args '{"startLine":1,"lineCount":20}'
|
|
16
|
-
npx ccdd run --copy --critic spec-why --codex-auth-file "$HOME/.codex/auth.json" --wait
|
|
8
|
+
ccdd-project config check
|
|
9
|
+
ccdd-project tools check --artifact spec --for agent --tool read --execute --args '{"startLine":1,"lineCount":20}'
|
|
10
|
+
ccdd-project verify spec --recursive --wait
|
|
17
11
|
```
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
The tool omits `preflight`. The default check distinguishes confirmed registration from unverified execution; `--execute` actually reads the file. Agent review requires valid Provider authentication.
|
|
22
|
-
|
|
23
|
-
This Reader is a small implementation illustrating the structure. It reads the file into memory before checking the 1MiB limit and limits returned text to 64KiB. A streaming reader is more appropriate for large files. It preserves UTF-8, CRLF, and the final newline, and distinguishes an empty file from a read past EOF. It returns an observation receipt only when actual content or an empty file was observed.
|
|
24
|
-
|
|
25
|
-
There is no Human duplicate of the Agent Reader. This type has no Human tools, so a Human Critic cannot use it. To add human viewing, write a custom tool that opens a desktop application or explicitly register `human.desktop.open()` from `@ccdd/default-tools`.
|
|
13
|
+
The last command makes a real Agent request and needs configured Provider credentials outside this workspace. `view.mjs` receives the standard JSON request on stdin and returns one `ToolResult` on stdout. The fixed filename is an argv value from each Artifact's declaration. The shared script is explicitly fingerprinted by `executionPaths`.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "spec",
|
|
3
|
+
"views": {
|
|
4
|
+
"agentTools": {
|
|
5
|
+
"read": {
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "Inspect {artifactName} with read.",
|
|
8
|
+
"inputSchema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"startLine": {
|
|
12
|
+
"type": "integer",
|
|
13
|
+
"minimum": 1
|
|
14
|
+
},
|
|
15
|
+
"lineCount": {
|
|
16
|
+
"type": "integer",
|
|
17
|
+
"minimum": 1,
|
|
18
|
+
"maximum": 80
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"required": [
|
|
23
|
+
"startLine",
|
|
24
|
+
"lineCount"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"resultKinds": [
|
|
28
|
+
"json"
|
|
29
|
+
],
|
|
30
|
+
"observation": "content",
|
|
31
|
+
"executionPaths": [
|
|
32
|
+
"view.mjs"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"script": {
|
|
36
|
+
"command": "node",
|
|
37
|
+
"args": [
|
|
38
|
+
"../view.mjs",
|
|
39
|
+
"spec.md"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"critics": [
|
|
46
|
+
{
|
|
47
|
+
"id": "alignment",
|
|
48
|
+
"title": "Does Spec match Why?",
|
|
49
|
+
"profile": {
|
|
50
|
+
"kind": "agent",
|
|
51
|
+
"provider": "openai-codex",
|
|
52
|
+
"model": "gpt-6-astra",
|
|
53
|
+
"reasoning": "medium"
|
|
54
|
+
},
|
|
55
|
+
"payload": {
|
|
56
|
+
"instruction": "Read {spec} and {why}; decide whether Spec satisfies the maximum task count in Why."
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
// A small standard-protocol script with no SDK or Provider dependency.
|
|
5
|
+
let input = '';
|
|
6
|
+
for await (const chunk of process.stdin) input += chunk;
|
|
7
|
+
const { version, context, args } = JSON.parse(input);
|
|
8
|
+
if (version !== 1) throw new Error('Unsupported request version.');
|
|
9
|
+
const bytes = await readFile(join(context.artifactPath, process.argv[2]));
|
|
10
|
+
if (bytes.length > 1024 * 1024) throw new Error('This example accepts files up to 1 MiB.');
|
|
11
|
+
const text = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
12
|
+
if (text.includes('\0')) throw new Error('This example accepts text, not binary data.');
|
|
13
|
+
const lines = text.match(/[^\n]*\n|[^\n]+$/g) ?? [];
|
|
14
|
+
const selected = lines.slice(args.startLine - 1, args.startLine - 1 + args.lineCount);
|
|
15
|
+
const content = selected.join('');
|
|
16
|
+
if (Buffer.byteLength(content) > 64 * 1024) throw new Error('Select a smaller line range.');
|
|
17
|
+
process.stdout.write(JSON.stringify({
|
|
18
|
+
content: [{ type: 'json', data: { content, startLine: args.startLine, lineCount: selected.length, totalLines: lines.length } }],
|
|
19
|
+
...(selected.length ? { observation: { kind: 'content' } } : lines.length === 0 ? { observation: { kind: 'empty' } } : {}),
|
|
20
|
+
}));
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "why",
|
|
3
|
+
"views": {
|
|
4
|
+
"agentTools": {
|
|
5
|
+
"read": {
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "Inspect {artifactName} with read.",
|
|
8
|
+
"inputSchema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"startLine": {
|
|
12
|
+
"type": "integer",
|
|
13
|
+
"minimum": 1
|
|
14
|
+
},
|
|
15
|
+
"lineCount": {
|
|
16
|
+
"type": "integer",
|
|
17
|
+
"minimum": 1,
|
|
18
|
+
"maximum": 80
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"required": [
|
|
23
|
+
"startLine",
|
|
24
|
+
"lineCount"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"resultKinds": [
|
|
28
|
+
"json"
|
|
29
|
+
],
|
|
30
|
+
"observation": "content",
|
|
31
|
+
"executionPaths": [
|
|
32
|
+
"view.mjs"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"script": {
|
|
36
|
+
"command": "node",
|
|
37
|
+
"args": [
|
|
38
|
+
"../view.mjs",
|
|
39
|
+
"why.md"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"basis": true
|
|
46
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ccdd/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"publishConfig": {
|
|
6
|
-
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public",
|
|
7
|
+
"registry": "https://registry.npmjs.org/"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/lhj6102/ccdd.git"
|
|
12
|
+
},
|
|
7
13
|
"description": "Artifact, Critic, relationship and tool definitions for CCDD",
|
|
8
14
|
"type": "module",
|
|
9
15
|
"types": "./dist/src/sdk.d.ts",
|
|
10
|
-
"exports": {
|
|
11
|
-
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/src/sdk.d.ts",
|
|
19
|
+
"import": "./dist/src/sdk.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"workspaces": [
|
|
23
|
+
"packages/default-tools",
|
|
24
|
+
"packages/project"
|
|
25
|
+
],
|
|
12
26
|
"engines": {
|
|
13
27
|
"node": "^22.19.0"
|
|
14
28
|
},
|
|
@@ -27,13 +41,13 @@
|
|
|
27
41
|
"release": "node scripts/local-release.mjs",
|
|
28
42
|
"release:npm": "node scripts/local-release.mjs --npm",
|
|
29
43
|
"release:npm:check": "node scripts/check-npm.mjs",
|
|
30
|
-
"demo:prepare": "npm run build && node dist/src/cli.js prepare-demo"
|
|
31
|
-
"demo": "npm run build && node dist/src/cli.js run --demo --copy --wait"
|
|
44
|
+
"demo:prepare": "npm run build && node dist/src/cli.js prepare-demo"
|
|
32
45
|
},
|
|
33
46
|
"files": [
|
|
34
47
|
"dist/src/sdk.*",
|
|
35
48
|
"dist/src/definitions.*",
|
|
36
49
|
"dist/src/tools/contracts.*",
|
|
50
|
+
"dist/src/artifact-scope.*",
|
|
37
51
|
"LICENSE",
|
|
38
52
|
"README.md",
|
|
39
53
|
"examples/"
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# Default image tool and Artifact groups
|
|
2
|
-
|
|
3
|
-
The `effect` document and `preview` image are independent Artifacts. `explosion` is a group referencing both IDs, with no path or type. Tools for the document and image are explicitly registered. This example is a static sample, not an actual VFX asset.
|
|
4
|
-
|
|
5
|
-
- `preview-review`: Evaluates one image. Only `view_image_preview` is supplied.
|
|
6
|
-
- `explosion-review`: Evaluates the group. `read_effect` and `view_image_preview` are supplied. Tools are not duplicated when `preview` is both a member and a dependency.
|
|
7
|
-
- `explosion-human`: Opens the group's document and image in desktop applications, then accepts a submitted verdict.
|
|
8
|
-
|
|
9
|
-
In a full Run, both group Critics must wait for the image review to pass because of explicit `deps: ['preview']`. Membership alone does not require prior evaluation. Once both group Critics are GREEN, `explosion` is GREEN while `effect` remains unreviewed.
|
|
10
|
-
|
|
11
|
-
## Running the example
|
|
12
|
-
|
|
13
|
-
Install the three v3.1.0 packages on Node 22 LTS (22.19.0 or later). The following command works after npm publication; before that, use the local source build below. Start in the CCDD source repository and copy the example into a new project outside it.
|
|
14
|
-
|
|
15
|
-
```sh
|
|
16
|
-
CCDD_EXAMPLE_ROOT=$(mktemp -d /tmp/ccdd-groups.XXXXXX)
|
|
17
|
-
cp -R examples/artifact-groups "$CCDD_EXAMPLE_ROOT/project"
|
|
18
|
-
cd "$CCDD_EXAMPLE_ROOT/project"
|
|
19
|
-
npm init -y
|
|
20
|
-
npm pkg set type=module
|
|
21
|
-
npm install --ignore-scripts @ccdd/core@3.1.0 @ccdd/project@3.1.0 @ccdd/default-tools@3.1.0
|
|
22
|
-
|
|
23
|
-
# Check group member tool readiness without calling a Provider.
|
|
24
|
-
npx ccdd tools check --artifact explosion --for agent
|
|
25
|
-
# Select an individual Artifact for actual image reading.
|
|
26
|
-
npx ccdd tools check --artifact preview --for agent --tool view_image --execute
|
|
27
|
-
|
|
28
|
-
# Review one Critic; this legacy command skips waiting for prerequisite verdicts.
|
|
29
|
-
npx ccdd run --copy --critic explosion-review --codex-auth-file "$HOME/.codex/auth.json" --wait
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Actual Agent review requires authentication and access to a model supporting image input. See the [reviewer guide](../../docs/reviewers.md) for authentication methods. Tool checks do not call a model. The `--execute` output above includes actual image blocks in base64.
|
|
33
|
-
|
|
34
|
-
If core is already installed, change the first `cp` source to `node_modules/@ccdd/core/examples/artifact-groups`.
|
|
35
|
-
|
|
36
|
-
Start a full Run with Human review by registering a local notification:
|
|
37
|
-
|
|
38
|
-
```sh
|
|
39
|
-
npx ccdd run --copy --human-inbox --codex-auth-file "$HOME/.codex/auth.json"
|
|
40
|
-
npx ccdd monitor
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Select a project and Run in the monitor, then click the group node in Graph to inspect its members. Claim the Human request, click `{explosion}`, execute each member's `open` tool, and submit a verdict with evidence. Default desktop opening targets macOS; explicitly register an executable on other operating systems.
|
|
44
|
-
|
|
45
|
-
`view_image` reuses Pi `read` image results. It detects PNG/JPEG/WebP from file content, with a 4MiB limit. GIF, BMP, animated PNG, and text results fail; no automatic conversion or resizing occurs. When registered on a directory Artifact, pass an internal path such as `{"path":"frames/preview.png"}`.
|
|
46
|
-
|
|
47
|
-
## Using a local source build
|
|
48
|
-
|
|
49
|
-
To test modified source, prepare three tarballs in the CCDD repository:
|
|
50
|
-
|
|
51
|
-
```sh
|
|
52
|
-
npm ci
|
|
53
|
-
npm run build
|
|
54
|
-
CCDD_LOCAL_PACKAGES=$(mktemp -d /tmp/ccdd-group-packages.XXXXXX)
|
|
55
|
-
npm pack --ignore-scripts --pack-destination "$CCDD_LOCAL_PACKAGES"
|
|
56
|
-
npm pack --ignore-scripts --workspace @ccdd/project --pack-destination "$CCDD_LOCAL_PACKAGES"
|
|
57
|
-
npm pack --ignore-scripts --workspace @ccdd/default-tools --pack-destination "$CCDD_LOCAL_PACKAGES"
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
In the same shell, create the new example project from the steps above, then replace the npm version installation with `npm install --ignore-scripts "$CCDD_LOCAL_PACKAGES"/*.tgz`. Subsequent tool checks and review commands are the same. To also run the full test suite and separate installation checks on source fixed to a commit, use `--dry-run` with the [local Release command](../../docs/releases.md#releasing-a-specific-commit-locally).
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from '@ccdd/core';
|
|
2
|
-
import { agent, human } from '@ccdd/default-tools';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
artifacts: {
|
|
6
|
-
effect: { type: 'markdown', path: 'effect.md' },
|
|
7
|
-
preview: { type: 'image', path: 'preview.png' },
|
|
8
|
-
explosion: { kind: 'group', members: ['effect', 'preview'] },
|
|
9
|
-
},
|
|
10
|
-
artifactTypes: {
|
|
11
|
-
markdown: {
|
|
12
|
-
agentTools: { read: agent.text.read() },
|
|
13
|
-
humanTools: { open: human.desktop.open() },
|
|
14
|
-
},
|
|
15
|
-
image: {
|
|
16
|
-
agentTools: { view_image: agent.image.view() },
|
|
17
|
-
humanTools: { open: human.desktop.open() },
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
critics: [
|
|
21
|
-
{
|
|
22
|
-
id: 'preview-review', title: 'Image visibility', target: 'preview', deps: [],
|
|
23
|
-
profile: { kind: 'agent', provider: 'openai-codex', model: 'gpt-6-astra', reasoning: 'medium' },
|
|
24
|
-
payload: { instruction: 'Check whether {preview} has a bright center and an orange ring distinguishable from the dark background. Review the image itself; matching the effect specification is outside this review.' },
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
id: 'explosion-review', title: 'Match the effect description and preview', target: 'explosion', deps: ['preview'],
|
|
28
|
-
profile: { kind: 'agent', provider: 'openai-codex', model: 'gpt-6-astra', reasoning: 'medium' },
|
|
29
|
-
payload: { instruction: 'Observe every member of {explosion} and evaluate whether {preview} matches the static appearance specified in {effect}. Animation timing and actual VFX runtime behavior are outside the scope of this static example.' },
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
id: 'explosion-human', title: 'Review the group on the desktop', target: 'explosion', deps: ['preview'],
|
|
33
|
-
profile: { kind: 'human' },
|
|
34
|
-
payload: { instruction: 'Open the document and image in {explosion} with their desktop programs, compare them, and submit your verdict.' },
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { defineConfig, defineTool } from '@ccdd/core';
|
|
3
|
-
|
|
4
|
-
// This factory defines a tool. It does not read the Artifact or execute an app.
|
|
5
|
-
function customTextReader() {
|
|
6
|
-
return defineTool({
|
|
7
|
-
metadata: {
|
|
8
|
-
description: 'Read the specified line range from {artifactName}.',
|
|
9
|
-
inputSchema: {
|
|
10
|
-
type: 'object',
|
|
11
|
-
properties: {
|
|
12
|
-
startLine: { type: 'integer', minimum: 1 },
|
|
13
|
-
lineCount: { type: 'integer', minimum: 1, maximum: 80 },
|
|
14
|
-
},
|
|
15
|
-
required: ['startLine', 'lineCount'],
|
|
16
|
-
additionalProperties: false,
|
|
17
|
-
} as const,
|
|
18
|
-
resultKinds: ['json'],
|
|
19
|
-
observation: 'content',
|
|
20
|
-
artifactKind: 'file',
|
|
21
|
-
},
|
|
22
|
-
async execute(context, args) {
|
|
23
|
-
// Deliberately small teaching example: it accepts files up to 1 MiB.
|
|
24
|
-
const file = await context.resolvePath();
|
|
25
|
-
const bytes = await readFile(file, { signal: context.signal });
|
|
26
|
-
if (bytes.length > 1024 * 1024) throw new Error('This example reader supports files up to 1 MiB.');
|
|
27
|
-
const text = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
28
|
-
if (text.includes('\0')) throw new Error('This example reader accepts text, not binary data.');
|
|
29
|
-
const lines = text.match(/[^\n]*\n|[^\n]+$/g) ?? [];
|
|
30
|
-
const offset = args.startLine - 1;
|
|
31
|
-
const selected = lines.slice(offset, offset + args.lineCount);
|
|
32
|
-
const content = selected.join('');
|
|
33
|
-
if (Buffer.byteLength(content) > 64 * 1024) throw new Error('Select a smaller line range.');
|
|
34
|
-
const nextOffset = offset + selected.length;
|
|
35
|
-
return {
|
|
36
|
-
content: [{ type: 'json', data: {
|
|
37
|
-
content,
|
|
38
|
-
startLine: args.startLine,
|
|
39
|
-
endLine: selected.length ? nextOffset : null,
|
|
40
|
-
lineCount: selected.length,
|
|
41
|
-
totalLines: lines.length,
|
|
42
|
-
nextStartLine: nextOffset < lines.length ? nextOffset + 1 : null,
|
|
43
|
-
} }],
|
|
44
|
-
...(selected.length ? { observation: { kind: 'content' as const } }
|
|
45
|
-
: lines.length === 0 ? { observation: { kind: 'empty' as const } } : {}),
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export default defineConfig(() => ({
|
|
52
|
-
artifactTypes: {
|
|
53
|
-
document: { agentTools: { read: customTextReader() } },
|
|
54
|
-
},
|
|
55
|
-
artifacts: {
|
|
56
|
-
why: { type: 'document', path: 'why.md', basis: true },
|
|
57
|
-
spec: { type: 'document', path: 'spec.md' },
|
|
58
|
-
},
|
|
59
|
-
critics: [{
|
|
60
|
-
id: 'spec-why', title: 'Does Spec match Why?', target: 'spec', deps: ['why'],
|
|
61
|
-
profile: { kind: 'agent', provider: 'openai-codex', model: 'gpt-6-astra', reasoning: 'medium' },
|
|
62
|
-
payload: { instruction: 'Read both documents and evaluate whether Spec satisfies the maximum task count in Why.' },
|
|
63
|
-
}],
|
|
64
|
-
}));
|