agentxchain 0.8.8 → 2.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/README.md +136 -136
- package/bin/agentxchain.js +186 -5
- package/dashboard/app.js +305 -0
- package/dashboard/components/blocked.js +145 -0
- package/dashboard/components/cross-repo.js +126 -0
- package/dashboard/components/gate.js +311 -0
- package/dashboard/components/hooks.js +177 -0
- package/dashboard/components/initiative.js +147 -0
- package/dashboard/components/ledger.js +165 -0
- package/dashboard/components/timeline.js +222 -0
- package/dashboard/index.html +352 -0
- package/package.json +14 -6
- package/scripts/live-api-proxy-preflight-smoke.sh +531 -0
- package/scripts/publish-from-tag.sh +88 -0
- package/scripts/release-postflight.sh +231 -0
- package/scripts/release-preflight.sh +167 -0
- package/src/commands/accept-turn.js +160 -0
- package/src/commands/approve-completion.js +80 -0
- package/src/commands/approve-transition.js +85 -0
- package/src/commands/dashboard.js +70 -0
- package/src/commands/init.js +516 -0
- package/src/commands/migrate.js +348 -0
- package/src/commands/multi.js +549 -0
- package/src/commands/plugin.js +157 -0
- package/src/commands/reject-turn.js +204 -0
- package/src/commands/resume.js +389 -0
- package/src/commands/status.js +196 -3
- package/src/commands/step.js +947 -0
- package/src/commands/template-list.js +33 -0
- package/src/commands/template-set.js +279 -0
- package/src/commands/validate.js +20 -11
- package/src/commands/verify.js +71 -0
- package/src/lib/adapters/api-proxy-adapter.js +1076 -0
- package/src/lib/adapters/local-cli-adapter.js +337 -0
- package/src/lib/adapters/manual-adapter.js +169 -0
- package/src/lib/blocked-state.js +94 -0
- package/src/lib/config.js +97 -1
- package/src/lib/context-compressor.js +121 -0
- package/src/lib/context-section-parser.js +220 -0
- package/src/lib/coordinator-acceptance.js +428 -0
- package/src/lib/coordinator-config.js +461 -0
- package/src/lib/coordinator-dispatch.js +276 -0
- package/src/lib/coordinator-gates.js +487 -0
- package/src/lib/coordinator-hooks.js +239 -0
- package/src/lib/coordinator-recovery.js +523 -0
- package/src/lib/coordinator-state.js +365 -0
- package/src/lib/cross-repo-context.js +247 -0
- package/src/lib/dashboard/bridge-server.js +284 -0
- package/src/lib/dashboard/file-watcher.js +93 -0
- package/src/lib/dashboard/state-reader.js +96 -0
- package/src/lib/dispatch-bundle.js +568 -0
- package/src/lib/dispatch-manifest.js +252 -0
- package/src/lib/gate-evaluator.js +285 -0
- package/src/lib/governed-state.js +2139 -0
- package/src/lib/governed-templates.js +145 -0
- package/src/lib/hook-runner.js +788 -0
- package/src/lib/normalized-config.js +539 -0
- package/src/lib/plugin-config-schema.js +192 -0
- package/src/lib/plugins.js +692 -0
- package/src/lib/protocol-conformance.js +291 -0
- package/src/lib/reference-conformance-adapter.js +858 -0
- package/src/lib/repo-observer.js +597 -0
- package/src/lib/repo.js +0 -31
- package/src/lib/schema.js +121 -0
- package/src/lib/schemas/turn-result.schema.json +205 -0
- package/src/lib/token-budget.js +206 -0
- package/src/lib/token-counter.js +27 -0
- package/src/lib/turn-paths.js +67 -0
- package/src/lib/turn-result-validator.js +496 -0
- package/src/lib/validation.js +137 -0
- package/src/templates/governed/api-service.json +31 -0
- package/src/templates/governed/cli-tool.json +30 -0
- package/src/templates/governed/generic.json +10 -0
- package/src/templates/governed/web-app.json +30 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
+
|
|
3
|
+
function isPlainObject(value) {
|
|
4
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function formatPath(path) {
|
|
8
|
+
return path || 'config';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function typeMatches(expected, value) {
|
|
12
|
+
switch (expected) {
|
|
13
|
+
case 'object':
|
|
14
|
+
return isPlainObject(value);
|
|
15
|
+
case 'array':
|
|
16
|
+
return Array.isArray(value);
|
|
17
|
+
case 'string':
|
|
18
|
+
return typeof value === 'string';
|
|
19
|
+
case 'number':
|
|
20
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
21
|
+
case 'integer':
|
|
22
|
+
return Number.isInteger(value);
|
|
23
|
+
case 'boolean':
|
|
24
|
+
return typeof value === 'boolean';
|
|
25
|
+
case 'null':
|
|
26
|
+
return value === null;
|
|
27
|
+
default:
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function validateAgainstSchema(schema, value, path, errors) {
|
|
33
|
+
if (!isPlainObject(schema)) {
|
|
34
|
+
errors.push(`${formatPath(path)}: schema must be an object`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const expectedTypes = Array.isArray(schema.type)
|
|
39
|
+
? schema.type
|
|
40
|
+
: schema.type === undefined
|
|
41
|
+
? []
|
|
42
|
+
: [schema.type];
|
|
43
|
+
|
|
44
|
+
if (expectedTypes.length > 0) {
|
|
45
|
+
const validTypes = new Set(['object', 'array', 'string', 'number', 'integer', 'boolean', 'null']);
|
|
46
|
+
const invalidType = expectedTypes.find((type) => !validTypes.has(type));
|
|
47
|
+
if (invalidType) {
|
|
48
|
+
errors.push(`${formatPath(path)}: unsupported schema type "${invalidType}"`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const matched = expectedTypes.some((type) => typeMatches(type, value));
|
|
53
|
+
if (!matched) {
|
|
54
|
+
errors.push(
|
|
55
|
+
`${formatPath(path)}: expected ${expectedTypes.join(' | ')}, got ${Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value}`,
|
|
56
|
+
);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (Array.isArray(schema.enum) && !schema.enum.some((candidate) => isDeepStrictEqual(candidate, value))) {
|
|
62
|
+
errors.push(`${formatPath(path)}: must match one of the configured enum values`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if ('const' in schema && !isDeepStrictEqual(schema.const, value)) {
|
|
66
|
+
errors.push(`${formatPath(path)}: must equal the configured constant value`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (typeof value === 'string') {
|
|
70
|
+
if (Number.isInteger(schema.minLength) && value.length < schema.minLength) {
|
|
71
|
+
errors.push(`${formatPath(path)}: must be at least ${schema.minLength} characters`);
|
|
72
|
+
}
|
|
73
|
+
if (Number.isInteger(schema.maxLength) && value.length > schema.maxLength) {
|
|
74
|
+
errors.push(`${formatPath(path)}: must be at most ${schema.maxLength} characters`);
|
|
75
|
+
}
|
|
76
|
+
if (typeof schema.pattern === 'string') {
|
|
77
|
+
try {
|
|
78
|
+
if (!(new RegExp(schema.pattern).test(value))) {
|
|
79
|
+
errors.push(`${formatPath(path)}: must match pattern ${schema.pattern}`);
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
errors.push(`${formatPath(path)}: schema pattern is invalid`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
88
|
+
if (typeof schema.minimum === 'number' && value < schema.minimum) {
|
|
89
|
+
errors.push(`${formatPath(path)}: must be >= ${schema.minimum}`);
|
|
90
|
+
}
|
|
91
|
+
if (typeof schema.maximum === 'number' && value > schema.maximum) {
|
|
92
|
+
errors.push(`${formatPath(path)}: must be <= ${schema.maximum}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (Array.isArray(value)) {
|
|
97
|
+
if (Number.isInteger(schema.minItems) && value.length < schema.minItems) {
|
|
98
|
+
errors.push(`${formatPath(path)}: must contain at least ${schema.minItems} items`);
|
|
99
|
+
}
|
|
100
|
+
if (Number.isInteger(schema.maxItems) && value.length > schema.maxItems) {
|
|
101
|
+
errors.push(`${formatPath(path)}: must contain at most ${schema.maxItems} items`);
|
|
102
|
+
}
|
|
103
|
+
if ('items' in schema) {
|
|
104
|
+
for (let i = 0; i < value.length; i++) {
|
|
105
|
+
validateAgainstSchema(schema.items, value[i], `${formatPath(path)}[${i}]`, errors);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (isPlainObject(value)) {
|
|
111
|
+
const properties = isPlainObject(schema.properties) ? schema.properties : {};
|
|
112
|
+
const required = Array.isArray(schema.required) ? schema.required : [];
|
|
113
|
+
|
|
114
|
+
for (const key of required) {
|
|
115
|
+
if (!(key in value)) {
|
|
116
|
+
errors.push(`${formatPath(path)}.${key}: is required`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
for (const [key, childSchema] of Object.entries(properties)) {
|
|
121
|
+
if (key in value) {
|
|
122
|
+
validateAgainstSchema(childSchema, value[key], `${formatPath(path)}.${key}`, errors);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const extraKeys = Object.keys(value).filter((key) => !(key in properties));
|
|
127
|
+
if (schema.additionalProperties === false && extraKeys.length > 0) {
|
|
128
|
+
for (const key of extraKeys) {
|
|
129
|
+
errors.push(`${formatPath(path)}.${key}: additional property is not allowed`);
|
|
130
|
+
}
|
|
131
|
+
} else if (isPlainObject(schema.additionalProperties)) {
|
|
132
|
+
for (const key of extraKeys) {
|
|
133
|
+
validateAgainstSchema(schema.additionalProperties, value[key], `${formatPath(path)}.${key}`, errors);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function validatePluginConfigAgainstSchema(schema, config, path = 'config') {
|
|
140
|
+
const errors = [];
|
|
141
|
+
validateAgainstSchema(schema, config, path, errors);
|
|
142
|
+
return errors;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function validatePluginConfigInput(schema, config, label = 'plugin config') {
|
|
146
|
+
if (schema === null || schema === undefined) {
|
|
147
|
+
if (config === undefined) {
|
|
148
|
+
return { ok: true, value: undefined, errors: [] };
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
ok: false,
|
|
152
|
+
value: undefined,
|
|
153
|
+
errors: [`${label}: config provided but plugin does not declare config_schema`],
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const candidate = config === undefined ? {} : config;
|
|
158
|
+
const errors = validatePluginConfigAgainstSchema(schema, candidate, label);
|
|
159
|
+
return {
|
|
160
|
+
ok: errors.length === 0,
|
|
161
|
+
value: candidate,
|
|
162
|
+
errors,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function validateInstalledPluginConfigs(rawConfig) {
|
|
167
|
+
const errors = [];
|
|
168
|
+
const plugins = isPlainObject(rawConfig?.plugins) ? rawConfig.plugins : {};
|
|
169
|
+
|
|
170
|
+
for (const [name, meta] of Object.entries(plugins)) {
|
|
171
|
+
if (!isPlainObject(meta)) {
|
|
172
|
+
errors.push(`plugins.${name}: metadata must be an object`);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if ('config' in meta && meta.config !== undefined && !('config_schema' in meta)) {
|
|
177
|
+
errors.push(`plugins.${name}.config: present but plugin metadata is missing config_schema`);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if ('config_schema' in meta && meta.config_schema !== undefined) {
|
|
182
|
+
const validation = validatePluginConfigInput(
|
|
183
|
+
meta.config_schema,
|
|
184
|
+
meta.config,
|
|
185
|
+
`plugins.${name}.config`,
|
|
186
|
+
);
|
|
187
|
+
errors.push(...validation.errors);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return { ok: errors.length === 0, errors };
|
|
192
|
+
}
|