@cr1992/agentkit 1.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.
Files changed (104) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +107 -0
  4. package/README.md +103 -0
  5. package/bin/agentkit.mjs +4 -0
  6. package/bin/cli.mjs +273 -0
  7. package/core/atomic-fs.mjs +23 -0
  8. package/core/cli-help.mjs +54 -0
  9. package/core/content-digest.mjs +66 -0
  10. package/core/digest.mjs +67 -0
  11. package/core/json-schema-lite.mjs +60 -0
  12. package/core/legacy-entry.mjs +37 -0
  13. package/core/reflection.mjs +142 -0
  14. package/core/runtime-bundle.mjs +101 -0
  15. package/docs/loop/embedded-review-adapter.md +41 -0
  16. package/docs/loop/loop-state-machine.md +43 -0
  17. package/docs/loop/recovery-and-fuses.md +34 -0
  18. package/docs/orchestrate/dispatch-contract.md +92 -0
  19. package/docs/orchestrate/failure-routing-and-recovery.md +46 -0
  20. package/docs/orchestrate/host-capability-cache.md +170 -0
  21. package/docs/orchestrate/isolation-fallback.md +18 -0
  22. package/docs/orchestrate/model-routing-config.md +186 -0
  23. package/docs/orchestrate/orchestration-runtime.md +261 -0
  24. package/docs/orchestrate/review-budget.md +90 -0
  25. package/docs/orchestrate/task-playbooks.md +85 -0
  26. package/docs/orchestrate/user-facing-reporting.md +14 -0
  27. package/docs/verify/evidence-schema.md +167 -0
  28. package/docs/verify/input-preparation.md +44 -0
  29. package/docs/verify/verification-protocol.md +76 -0
  30. package/docs/worktree/batch-integration.md +176 -0
  31. package/docs/worktree/delivery-identity.md +41 -0
  32. package/docs/worktree/profile.md +107 -0
  33. package/docs/worktree/reclaim-and-watch.md +96 -0
  34. package/docs/worktree/review-lifecycle.md +92 -0
  35. package/docs/worktree/spawn-and-stack.md +74 -0
  36. package/domains/loop/loop-runtime.mjs +1056 -0
  37. package/domains/orchestrate/contract-tool.mjs +169 -0
  38. package/domains/orchestrate/host_capability_cache.mjs +437 -0
  39. package/domains/orchestrate/orchestration-ledger.mjs +332 -0
  40. package/domains/orchestrate/orchestration-metadata.mjs +4 -0
  41. package/domains/orchestrate/orchestration-reflection.mjs +119 -0
  42. package/domains/orchestrate/resolve_model_policy.mjs +311 -0
  43. package/domains/orchestrate/review-budget.mjs +162 -0
  44. package/domains/orchestrate/worker-capability-preflight.mjs +227 -0
  45. package/domains/verify/verification-runtime.mjs +1638 -0
  46. package/domains/worktree/worktree-archive.mjs +135 -0
  47. package/domains/worktree/worktree-artifact.mjs +123 -0
  48. package/domains/worktree/worktree-batch-integrate.mjs +713 -0
  49. package/domains/worktree/worktree-batch-plan.mjs +198 -0
  50. package/domains/worktree/worktree-batch-result.mjs +241 -0
  51. package/domains/worktree/worktree-core.mjs +908 -0
  52. package/domains/worktree/worktree-doctor.mjs +493 -0
  53. package/domains/worktree/worktree-history.mjs +377 -0
  54. package/domains/worktree/worktree-learning.mjs +110 -0
  55. package/domains/worktree/worktree-lifecycle.mjs +786 -0
  56. package/domains/worktree/worktree-merge-preview.mjs +409 -0
  57. package/domains/worktree/worktree-mgr.mjs +261 -0
  58. package/domains/worktree/worktree-process.mjs +55 -0
  59. package/domains/worktree/worktree-profile.mjs +800 -0
  60. package/domains/worktree/worktree-provider-gitlab.mjs +59 -0
  61. package/domains/worktree/worktree-reclaim.mjs +683 -0
  62. package/domains/worktree/worktree-review-refresh.mjs +574 -0
  63. package/domains/worktree/worktree-review-watch.mjs +661 -0
  64. package/domains/worktree/worktree-scan.mjs +510 -0
  65. package/domains/worktree/worktree-trace-test-worker.mjs +23 -0
  66. package/domains/worktree/worktree-trace.mjs +478 -0
  67. package/manage-worktrees/SKILL.md +87 -0
  68. package/manage-worktrees/agents/openai.yaml +4 -0
  69. package/manage-worktrees/scripts/worktree-mgr.mjs +10 -0
  70. package/manage-worktrees/scripts/worktree-scan.mjs +10 -0
  71. package/orchestrate-subagents/SKILL.md +173 -0
  72. package/orchestrate-subagents/agents/openai.yaml +4 -0
  73. package/orchestrate-subagents/scripts/contract-tool.mjs +10 -0
  74. package/orchestrate-subagents/scripts/host_capability_cache.mjs +10 -0
  75. package/orchestrate-subagents/scripts/orchestration-ledger.mjs +10 -0
  76. package/orchestrate-subagents/scripts/orchestration-reflection.mjs +10 -0
  77. package/orchestrate-subagents/scripts/resolve_model_policy.mjs +10 -0
  78. package/orchestrate-subagents/scripts/review-budget.mjs +10 -0
  79. package/orchestrate-subagents/scripts/worker-capability-preflight.mjs +10 -0
  80. package/package.json +48 -0
  81. package/run-agent-verify-loop/SKILL.md +127 -0
  82. package/run-agent-verify-loop/agents/openai.yaml +4 -0
  83. package/run-agent-verify-loop/scripts/loop-runtime.mjs +10 -0
  84. package/schemas/artifact-ref-v1.schema.json +23 -0
  85. package/schemas/batch-result-v1.schema.json +138 -0
  86. package/schemas/controller-recheck-record-v1.schema.json +22 -0
  87. package/schemas/convergence-report-v1.schema.json +9 -0
  88. package/schemas/effective-worker-capability-v1.schema.json +36 -0
  89. package/schemas/embedded-verification-record-v1.schema.json +32 -0
  90. package/schemas/evidence-package-v1.schema.json +41 -0
  91. package/schemas/improvement-proposal-v1.schema.json +18 -0
  92. package/schemas/loop-state-v1.schema.json +34 -0
  93. package/schemas/model-policy-resolution-v1.schema.json +41 -0
  94. package/schemas/orchestration-ledger-v1.schema.json +110 -0
  95. package/schemas/reflection-record-v1.schema.json +24 -0
  96. package/schemas/review-result-v1.schema.json +37 -0
  97. package/schemas/task-contract-v1.schema.json +83 -0
  98. package/schemas/verification-profile-v1.schema.json +60 -0
  99. package/schemas/worker-capability-requirements-v1.schema.json +21 -0
  100. package/schemas/worktree-binding-v1.schema.json +14 -0
  101. package/shell-manifest.json +79 -0
  102. package/verify-agent-output/SKILL.md +119 -0
  103. package/verify-agent-output/agents/openai.yaml +4 -0
  104. package/verify-agent-output/scripts/verification-runtime.mjs +10 -0
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env node
2
+ // @ts-check
3
+
4
+ import { readFileSync, realpathSync } from 'node:fs';
5
+ import { resolve as resolvePath } from 'node:path';
6
+ import { fileURLToPath, pathToFileURL } from 'node:url';
7
+ import { parseJsonStrict } from './contract-tool.mjs';
8
+ import { allOptionNames, isHelpRequest, renderCliHelp } from '../../core/cli-help.mjs';
9
+ import { ORCHESTRATION_PROTOCOL_VERSION } from './orchestration-metadata.mjs';
10
+
11
+ // CLI 命令与参数的唯一真源:选项白名单、`--help` 清单和命令错误信息都从这里推导。
12
+ const CLI_SPEC = {
13
+ capabilities: {},
14
+ normalize: { required: ['input'] },
15
+ check: { required: ['requirements'], optional: ['effective'] },
16
+ };
17
+ const CLI_OPTIONS = allOptionNames(CLI_SPEC);
18
+ const CLI_NOTES = [
19
+ 'requirements.required 里的能力键必须以 worker. 开头,例如 worker.read.cwd;其他前缀一律拒绝。',
20
+ 'required 为空数组时无需 --effective,check 直接返回 not_required 形态的 ready。',
21
+ ];
22
+ const SCHEMA_VERSION = 1;
23
+ const RUNTIME_VERSION = '1.0.0';
24
+ const DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/u;
25
+ const HOST_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/u;
26
+ const PROFILE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
27
+ const CAPABILITY_PATTERN = /^worker\.[a-z][a-z0-9_.-]{0,63}$/u;
28
+ const SESSION_BINDING_PATTERN = /^session:[A-Za-z0-9._-]{1,128}$/u;
29
+ const CONFIG_BINDING_PATTERN = /^config:sha256:[0-9a-f]{64}$/u;
30
+ const ISO_TZ_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})$/u;
31
+ const OUTCOMES = new Set(['allowed', 'denied_by_policy', 'unavailable_or_unproven', 'approval_channel_fault', 'execution_fault']);
32
+ const EFFECTIVE_KEYS = new Set(['schema_version', 'host', 'worker_profile', 'capability_fingerprint', 'binding', 'observed_at', 'expires_at', 'outcomes', 'evidence_refs']);
33
+ const REQUIREMENT_KEYS = new Set(['schema_version', 'host', 'worker_profile', 'capability_fingerprint', 'binding', 'required']);
34
+ const EVIDENCE_KEYS = new Set(['type', 'id', 'digest']);
35
+ const EVIDENCE_TYPES = new Set(['probe', 'schema', 'observation']);
36
+
37
+ export class WorkerCapabilityError extends Error {}
38
+
39
+ function checkKeys(value, allowed, label) {
40
+ const unknown = Object.keys(value).filter((key) => !allowed.has(key)).sort();
41
+ if (unknown.length) throw new WorkerCapabilityError(`${label} has unknown keys: ${unknown.join(', ')}`);
42
+ }
43
+
44
+ function object(value, label) {
45
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new WorkerCapabilityError(`${label} must be a JSON object`);
46
+ return value;
47
+ }
48
+
49
+ function timestamp(value, label) {
50
+ if (typeof value !== 'string' || !ISO_TZ_PATTERN.test(value) || Number.isNaN(Date.parse(value))) {
51
+ throw new WorkerCapabilityError(`${label} must be an ISO-8601 timestamp with timezone`);
52
+ }
53
+ return new Date(value);
54
+ }
55
+
56
+ function binding(value) {
57
+ if (typeof value !== 'string' || (!SESSION_BINDING_PATTERN.test(value) && !CONFIG_BINDING_PATTERN.test(value))) {
58
+ throw new WorkerCapabilityError('binding must be session:<opaque> or config:sha256:<64 hex>');
59
+ }
60
+ return value;
61
+ }
62
+
63
+ function metadata(value, label) {
64
+ if (!HOST_PATTERN.test(String(value.host ?? ''))) throw new WorkerCapabilityError(`${label}.host is invalid`);
65
+ if (!PROFILE_PATTERN.test(String(value.worker_profile ?? ''))) throw new WorkerCapabilityError(`${label}.worker_profile is invalid`);
66
+ if (!DIGEST_PATTERN.test(String(value.capability_fingerprint ?? ''))) throw new WorkerCapabilityError(`${label}.capability_fingerprint is invalid`);
67
+ return {
68
+ host: value.host,
69
+ worker_profile: value.worker_profile,
70
+ capability_fingerprint: value.capability_fingerprint,
71
+ binding: binding(value.binding),
72
+ };
73
+ }
74
+
75
+ function capabilityList(value, label) {
76
+ if (!Array.isArray(value) || value.some((item) => typeof item !== 'string' || !CAPABILITY_PATTERN.test(item))) {
77
+ throw new WorkerCapabilityError(`${label} must be an array of worker.* capability keys (required prefix: "worker.", e.g. "worker.read.cwd"); other prefixes are rejected`);
78
+ }
79
+ return [...new Set(value)].sort();
80
+ }
81
+
82
+ export function normalizeEffective(value) {
83
+ object(value, 'effective capability descriptor');
84
+ checkKeys(value, EFFECTIVE_KEYS, 'effective capability descriptor');
85
+ if (value.schema_version !== SCHEMA_VERSION) throw new WorkerCapabilityError(`effective capability descriptor must declare schema_version ${SCHEMA_VERSION}`);
86
+ const common = metadata(value, 'effective capability descriptor');
87
+ const observedAt = timestamp(value.observed_at, 'observed_at');
88
+ const expiresAt = timestamp(value.expires_at, 'expires_at');
89
+ const maxHours = common.binding.startsWith('session:') ? 24 : 168;
90
+ if (expiresAt.getTime() <= observedAt.getTime() || expiresAt.getTime() - observedAt.getTime() > maxHours * 3600 * 1000) {
91
+ throw new WorkerCapabilityError(`effective capability validity must be within ${maxHours} hours`);
92
+ }
93
+ object(value.outcomes, 'outcomes');
94
+ const outcomes = {};
95
+ for (const key of Object.keys(value.outcomes).sort()) {
96
+ if (!CAPABILITY_PATTERN.test(key) || !OUTCOMES.has(value.outcomes[key])) throw new WorkerCapabilityError(`outcomes.${key} is invalid`);
97
+ outcomes[key] = value.outcomes[key];
98
+ }
99
+ if (!Array.isArray(value.evidence_refs)) throw new WorkerCapabilityError('evidence_refs must be an array');
100
+ const evidenceRefs = value.evidence_refs.map((item, index) => {
101
+ object(item, `evidence_refs[${index}]`);
102
+ checkKeys(item, EVIDENCE_KEYS, `evidence_refs[${index}]`);
103
+ if (!EVIDENCE_TYPES.has(item.type) || typeof item.id !== 'string' || !item.id || !DIGEST_PATTERN.test(String(item.digest ?? ''))) {
104
+ throw new WorkerCapabilityError(`evidence_refs[${index}] is invalid`);
105
+ }
106
+ return { type: item.type, id: item.id, digest: item.digest };
107
+ });
108
+ if (Object.values(outcomes).some((outcome) => outcome !== 'unavailable_or_unproven') && evidenceRefs.length === 0) {
109
+ throw new WorkerCapabilityError('proven effective outcomes require at least one evidence ref');
110
+ }
111
+ return {
112
+ schema_version: SCHEMA_VERSION,
113
+ ...common,
114
+ observed_at: observedAt.toISOString(),
115
+ expires_at: expiresAt.toISOString(),
116
+ outcomes,
117
+ evidence_refs: evidenceRefs,
118
+ };
119
+ }
120
+
121
+ export function normalizeRequirements(value) {
122
+ object(value, 'capability requirements');
123
+ checkKeys(value, REQUIREMENT_KEYS, 'capability requirements');
124
+ if (value.schema_version !== SCHEMA_VERSION) throw new WorkerCapabilityError(`capability requirements must declare schema_version ${SCHEMA_VERSION}`);
125
+ return { schema_version: SCHEMA_VERSION, ...metadata(value, 'capability requirements'), required: capabilityList(value.required, 'required') };
126
+ }
127
+
128
+ export function checkCapabilities(effectiveValue, requirementValue, now = new Date()) {
129
+ const requirements = normalizeRequirements(requirementValue);
130
+ if (requirements.required.length === 0) {
131
+ return { ready: true, required: [], allowed: [], blocked: [], action: 'dispatch', effective_status: effectiveValue ? 'not-required' : 'absent-not-required' };
132
+ }
133
+ if (!effectiveValue) {
134
+ return {
135
+ ready: false,
136
+ required: requirements.required,
137
+ allowed: [],
138
+ blocked: requirements.required.map((capability) => ({ capability, outcome: 'unavailable_or_unproven' })),
139
+ action: 'scoped_probe_or_replan',
140
+ effective_status: 'absent',
141
+ };
142
+ }
143
+ const effective = normalizeEffective(effectiveValue);
144
+ const mismatches = ['host', 'worker_profile', 'capability_fingerprint', 'binding'].filter((key) => effective[key] !== requirements[key]);
145
+ if (mismatches.length) {
146
+ return {
147
+ ready: false,
148
+ required: requirements.required,
149
+ allowed: [],
150
+ blocked: requirements.required.map((capability) => ({ capability, outcome: 'unavailable_or_unproven' })),
151
+ action: 'refresh_effective_profile',
152
+ effective_status: 'binding-mismatch',
153
+ reasons: mismatches.map((key) => `${key}-mismatch`),
154
+ };
155
+ }
156
+ const observedAt = new Date(effective.observed_at);
157
+ const expiresAt = new Date(effective.expires_at);
158
+ if (observedAt.getTime() > now.getTime() + 5 * 60 * 1000 || expiresAt.getTime() <= now.getTime()) {
159
+ return {
160
+ ready: false,
161
+ required: requirements.required,
162
+ allowed: [],
163
+ blocked: requirements.required.map((capability) => ({ capability, outcome: 'unavailable_or_unproven' })),
164
+ action: 'refresh_effective_profile',
165
+ effective_status: 'stale',
166
+ };
167
+ }
168
+ const allowed = [];
169
+ const blocked = [];
170
+ for (const capability of requirements.required) {
171
+ const outcome = effective.outcomes[capability] ?? 'unavailable_or_unproven';
172
+ if (outcome === 'allowed') allowed.push(capability);
173
+ else blocked.push({ capability, outcome });
174
+ }
175
+ let action = 'dispatch';
176
+ if (blocked.some((item) => item.outcome === 'approval_channel_fault')) action = 'stop_same_class_and_escalate';
177
+ else if (blocked.some((item) => item.outcome === 'execution_fault')) action = 'stop_same_class_and_diagnose';
178
+ else if (blocked.some((item) => item.outcome === 'denied_by_policy')) action = 'replan_or_controller';
179
+ else if (blocked.length) action = 'scoped_probe_or_replan';
180
+ return { ready: blocked.length === 0, required: requirements.required, allowed, blocked, action, effective_status: 'fresh' };
181
+ }
182
+
183
+ function readJson(path) {
184
+ return parseJsonStrict(readFileSync(resolvePath(path), 'utf8'));
185
+ }
186
+
187
+ export function main(argv = process.argv.slice(2)) {
188
+ if (isHelpRequest(argv)) return { help: renderCliHelp('worker-capability-preflight.mjs', CLI_SPEC, CLI_NOTES) };
189
+ const command = argv[0];
190
+ if (command === 'capabilities') return { protocol_version: ORCHESTRATION_PROTOCOL_VERSION, runtime_version: RUNTIME_VERSION, schemas: { effective_worker_capability: [1], worker_capability_requirements: [1] }, outcomes: [...OUTCOMES] };
191
+ const options = {};
192
+ for (let index = 1; index < argv.length; index += 1) {
193
+ const token = argv[index];
194
+ if (!token.startsWith('--') || !CLI_OPTIONS.has(token.slice(2)) || argv[index + 1] === undefined || argv[index + 1].startsWith('--')) throw new WorkerCapabilityError(`unknown or incomplete option: ${token}`);
195
+ options[token.slice(2)] = argv[++index];
196
+ }
197
+ if (command === 'normalize') {
198
+ if (!options.input) throw new WorkerCapabilityError('normalize requires --input');
199
+ return normalizeEffective(readJson(options.input));
200
+ }
201
+ if (command === 'check') {
202
+ if (!options.requirements) throw new WorkerCapabilityError('check requires --requirements');
203
+ return checkCapabilities(options.effective ? readJson(options.effective) : null, readJson(options.requirements));
204
+ }
205
+ throw new WorkerCapabilityError(`command must be one of: ${Object.keys(CLI_SPEC).join(', ')}`);
206
+ }
207
+
208
+ function entry() {
209
+ try {
210
+ return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
211
+ } catch {
212
+ return pathToFileURL(resolvePath(process.argv[1] ?? '')).href === import.meta.url;
213
+ }
214
+ }
215
+
216
+ export function runCli(argv = process.argv.slice(2)) {
217
+ try {
218
+ const result = main(argv);
219
+ process.stdout.write(typeof result?.help === 'string' ? result.help : `${JSON.stringify(result, null, 2)}\n`);
220
+ return 0;
221
+ } catch (error) {
222
+ process.stderr.write(`worker capability preflight error: ${error.message}\n`);
223
+ return error instanceof WorkerCapabilityError ? 2 : 3;
224
+ }
225
+ }
226
+
227
+ if (entry()) process.exitCode = runCli();