@trucore/openclaw-atf 0.1.0 → 0.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/LICENSE +21 -0
- package/README.md +226 -12
- package/examples/README.md +134 -0
- package/examples/disable-plugin.json +3 -0
- package/examples/full-config.json +12 -0
- package/examples/minimal-enable.json +5 -0
- package/examples/prefer-api.json +8 -0
- package/examples/prefer-cli.json +7 -0
- package/openclaw.plugin.json +2 -1
- package/package.json +11 -2
- package/src/adoption_advisor.mjs +425 -0
- package/src/backend.mjs +230 -0
- package/src/billing_claim.mjs +630 -0
- package/src/config.mjs +317 -0
- package/src/contracts/deny_codes.mjs +217 -0
- package/src/contracts/index.mjs +52 -0
- package/src/contracts/result_builder.mjs +132 -0
- package/src/contracts/schemas.mjs +402 -0
- package/src/contracts/status_codes.mjs +148 -0
- package/src/doctor.mjs +207 -0
- package/src/index.mjs +1168 -70
- package/src/tool_response.mjs +181 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* result_builder.mjs — Universal ATF result builder
|
|
3
|
+
*
|
|
4
|
+
* Builds platform-agnostic result objects for ATF tool responses.
|
|
5
|
+
* This is the UNIVERSAL layer — adapters wrap these results in their
|
|
6
|
+
* transport-specific envelopes.
|
|
7
|
+
*
|
|
8
|
+
* Separation of concerns:
|
|
9
|
+
* - result_builder.mjs → universal result shape (this file)
|
|
10
|
+
* - tool_response.mjs → OpenClaw-specific envelope wrapping
|
|
11
|
+
* - future CLI adapter → stdout JSON formatting
|
|
12
|
+
* - future API adapter → HTTP response mapping
|
|
13
|
+
*
|
|
14
|
+
* Exports:
|
|
15
|
+
* - buildResult(toolName, status, result, meta?) → UniversalResult
|
|
16
|
+
* - buildErrorResult(toolName, message, opts?) → UniversalErrorResult
|
|
17
|
+
* - buildMeta(toolName, opts?) → ResultMeta
|
|
18
|
+
*
|
|
19
|
+
* No dependencies beyond sibling status_codes. No side effects.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { RESPONSE_STATUS } from "./status_codes.mjs";
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Constants — canonical identity
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
/** Canonical product identity. */
|
|
29
|
+
const PRODUCT_ID = "trucore-atf";
|
|
30
|
+
|
|
31
|
+
/** Product version — kept in sync by version consistency tests. */
|
|
32
|
+
const PRODUCT_VERSION = "0.2.0";
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Meta builder
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Build standard metadata for a tool result.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} toolName Name of the tool producing the result.
|
|
42
|
+
* @param {object} [opts] Optional metadata overrides.
|
|
43
|
+
* @param {object} [opts.backend] Backend resolution info.
|
|
44
|
+
* @param {string[]} [opts.warnings] Warnings for operator.
|
|
45
|
+
* @returns {{ product_id: string, product_version: string, tool: string, ts: string, backend?: object, warnings?: string[] }}
|
|
46
|
+
*/
|
|
47
|
+
export function buildMeta(toolName, opts = {}) {
|
|
48
|
+
const meta = {
|
|
49
|
+
product_id: PRODUCT_ID,
|
|
50
|
+
product_version: PRODUCT_VERSION,
|
|
51
|
+
tool: toolName,
|
|
52
|
+
ts: new Date().toISOString(),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (opts.backend && typeof opts.backend === "object") {
|
|
56
|
+
meta.backend = {
|
|
57
|
+
preferred: opts.backend.preferred_backend ?? opts.backend.preferred ?? "unknown",
|
|
58
|
+
effective: opts.backend.effective_backend ?? opts.backend.effective ?? "unknown",
|
|
59
|
+
fallback_occurred: opts.backend.fallback_occurred ?? false,
|
|
60
|
+
fallback_reason: opts.backend.fallback_reason ?? null,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (Array.isArray(opts.warnings) && opts.warnings.length > 0) {
|
|
65
|
+
meta.warnings = [...opts.warnings];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return meta;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Success result builder
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Build a universal ATF success result.
|
|
77
|
+
*
|
|
78
|
+
* This is the platform-agnostic result object. Adapters wrap this in
|
|
79
|
+
* their own envelope format.
|
|
80
|
+
*
|
|
81
|
+
* Universal result shape:
|
|
82
|
+
* { status, summary, result, _meta }
|
|
83
|
+
*
|
|
84
|
+
* @param {string} toolName Name of the tool.
|
|
85
|
+
* @param {string} summary Human-readable summary.
|
|
86
|
+
* @param {object} result Tool-specific result data.
|
|
87
|
+
* @param {object} [opts] Optional overrides.
|
|
88
|
+
* @param {string} [opts.status] RESPONSE_STATUS value (default: "ok").
|
|
89
|
+
* @param {object} [opts.backend] Backend resolution info.
|
|
90
|
+
* @param {string[]} [opts.warnings] Warnings.
|
|
91
|
+
* @returns {{ status: string, summary: string, result: object, _meta: object }}
|
|
92
|
+
*/
|
|
93
|
+
export function buildResult(toolName, summary, result, opts = {}) {
|
|
94
|
+
return {
|
|
95
|
+
status: opts.status ?? RESPONSE_STATUS.OK,
|
|
96
|
+
summary,
|
|
97
|
+
result: result ?? {},
|
|
98
|
+
_meta: buildMeta(toolName, opts),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Error result builder
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Build a universal ATF error result.
|
|
108
|
+
*
|
|
109
|
+
* Universal error shape:
|
|
110
|
+
* { status: "error", error, remediation?, _meta }
|
|
111
|
+
*
|
|
112
|
+
* @param {string} toolName Name of the tool.
|
|
113
|
+
* @param {string} message Error message.
|
|
114
|
+
* @param {object} [opts] Optional overrides.
|
|
115
|
+
* @param {object} [opts.backend] Backend resolution info.
|
|
116
|
+
* @param {string[]} [opts.warnings] Warnings.
|
|
117
|
+
* @param {string[]} [opts.remediation] Fix instructions.
|
|
118
|
+
* @returns {{ status: string, error: string, remediation?: string[], _meta: object }}
|
|
119
|
+
*/
|
|
120
|
+
export function buildErrorResult(toolName, message, opts = {}) {
|
|
121
|
+
const payload = {
|
|
122
|
+
status: RESPONSE_STATUS.ERROR,
|
|
123
|
+
error: message,
|
|
124
|
+
_meta: buildMeta(toolName, opts),
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
if (Array.isArray(opts.remediation) && opts.remediation.length > 0) {
|
|
128
|
+
payload.remediation = [...opts.remediation];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return payload;
|
|
132
|
+
}
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* schemas.mjs — Universal ATF contract family definitions
|
|
3
|
+
*
|
|
4
|
+
* Defines the canonical request/response shapes for each ATF contract
|
|
5
|
+
* family. These are platform-agnostic — any adapter (OpenClaw, CLI, API,
|
|
6
|
+
* SDK, future UI) can map to/from these shapes.
|
|
7
|
+
*
|
|
8
|
+
* This module defines STRUCTURE, not runtime logic. Think of it as
|
|
9
|
+
* the "interface declarations" for ATF contracts.
|
|
10
|
+
*
|
|
11
|
+
* Contract families:
|
|
12
|
+
* 1. READINESS — health, doctor, preflight
|
|
13
|
+
* 2. ADVISORY — adoption advisor, bot preflight
|
|
14
|
+
* 3. EXPLANATION — tx_explain
|
|
15
|
+
* 4. BILLING — billing_info, billing_claim
|
|
16
|
+
* 5. DISCOVERY — discover, bootstrap_plan
|
|
17
|
+
* 6. PROTECTION — protect_intent, verify_receipt, report_savings
|
|
18
|
+
*
|
|
19
|
+
* Exports:
|
|
20
|
+
* - CONTRACT_FAMILIES — frozen family metadata
|
|
21
|
+
* - UNIVERSAL_RESULT_FIELDS — fields present in every universal result
|
|
22
|
+
* - ADAPTER_ENVELOPE_FIELDS — fields added by adapters (not universal)
|
|
23
|
+
* - TOOL_FAMILY_MAP — maps each tool to its contract family
|
|
24
|
+
*
|
|
25
|
+
* No dependencies. No side effects. Pure constants.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Contract families
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Canonical ATF contract families.
|
|
34
|
+
*
|
|
35
|
+
* Each family groups tools that share similar request/response patterns.
|
|
36
|
+
* Future adapters map their transport-specific inputs/outputs to these
|
|
37
|
+
* canonical shapes.
|
|
38
|
+
*/
|
|
39
|
+
export const CONTRACT_FAMILIES = Object.freeze({
|
|
40
|
+
READINESS: Object.freeze({
|
|
41
|
+
family_id: "readiness",
|
|
42
|
+
purpose:
|
|
43
|
+
"Check ATF availability, integration health, and pre-session readiness.",
|
|
44
|
+
tools: Object.freeze([
|
|
45
|
+
"atf_health",
|
|
46
|
+
"atf_integration_doctor",
|
|
47
|
+
"atf_bot_preflight",
|
|
48
|
+
]),
|
|
49
|
+
canonical_request: Object.freeze({
|
|
50
|
+
description: "No required input. Config is read from environment.",
|
|
51
|
+
fields: Object.freeze({}),
|
|
52
|
+
}),
|
|
53
|
+
canonical_response: Object.freeze({
|
|
54
|
+
description:
|
|
55
|
+
"Structured readiness signal with backend availability, " +
|
|
56
|
+
"config validity, warnings, and remediation steps.",
|
|
57
|
+
required_fields: Object.freeze([
|
|
58
|
+
"status",
|
|
59
|
+
"warnings",
|
|
60
|
+
"remediation",
|
|
61
|
+
]),
|
|
62
|
+
optional_fields: Object.freeze([
|
|
63
|
+
"ready",
|
|
64
|
+
"healthy",
|
|
65
|
+
"backend_ready",
|
|
66
|
+
"config_valid",
|
|
67
|
+
"cli_available",
|
|
68
|
+
"api_available",
|
|
69
|
+
"native_tools_expected",
|
|
70
|
+
"native_tools_available",
|
|
71
|
+
"native_tools_missing",
|
|
72
|
+
"config_errors",
|
|
73
|
+
"config_warnings",
|
|
74
|
+
]),
|
|
75
|
+
}),
|
|
76
|
+
}),
|
|
77
|
+
|
|
78
|
+
ADVISORY: Object.freeze({
|
|
79
|
+
family_id: "advisory",
|
|
80
|
+
purpose:
|
|
81
|
+
"Evaluate signals and return deterministic adoption/installation recommendations.",
|
|
82
|
+
tools: Object.freeze(["atf_adoption_advisor"]),
|
|
83
|
+
canonical_request: Object.freeze({
|
|
84
|
+
description:
|
|
85
|
+
"Map of trigger_id → boolean signals indicating bot capabilities.",
|
|
86
|
+
fields: Object.freeze({
|
|
87
|
+
signals: {
|
|
88
|
+
type: "object",
|
|
89
|
+
required: false,
|
|
90
|
+
description:
|
|
91
|
+
"Map of trigger_id to boolean. Omit for no-trigger evaluation.",
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
}),
|
|
95
|
+
canonical_response: Object.freeze({
|
|
96
|
+
description:
|
|
97
|
+
"Deterministic adoption recommendation with matched triggers, " +
|
|
98
|
+
"severity, tier, call sequence, and install guidance.",
|
|
99
|
+
required_fields: Object.freeze([
|
|
100
|
+
"install_needed",
|
|
101
|
+
"recommended_tier",
|
|
102
|
+
"highest_severity",
|
|
103
|
+
"matched_triggers",
|
|
104
|
+
]),
|
|
105
|
+
optional_fields: Object.freeze([
|
|
106
|
+
"unmatched_triggers",
|
|
107
|
+
"call_sequence",
|
|
108
|
+
"install_guidance",
|
|
109
|
+
"next_actions",
|
|
110
|
+
]),
|
|
111
|
+
}),
|
|
112
|
+
}),
|
|
113
|
+
|
|
114
|
+
EXPLANATION: Object.freeze({
|
|
115
|
+
family_id: "explanation",
|
|
116
|
+
purpose:
|
|
117
|
+
"Explain deny decisions and reason codes in human-readable terms.",
|
|
118
|
+
tools: Object.freeze(["atf_tx_explain"]),
|
|
119
|
+
canonical_request: Object.freeze({
|
|
120
|
+
description:
|
|
121
|
+
"Either an array of reason codes or a receipt/decision object.",
|
|
122
|
+
fields: Object.freeze({
|
|
123
|
+
reasonCodes: {
|
|
124
|
+
type: "string[]",
|
|
125
|
+
required: false,
|
|
126
|
+
description: "Array of ATF reason codes to explain.",
|
|
127
|
+
},
|
|
128
|
+
receipt: {
|
|
129
|
+
type: "object",
|
|
130
|
+
required: false,
|
|
131
|
+
description:
|
|
132
|
+
"ATF receipt or decision object with reason_codes field.",
|
|
133
|
+
},
|
|
134
|
+
}),
|
|
135
|
+
}),
|
|
136
|
+
canonical_response: Object.freeze({
|
|
137
|
+
description:
|
|
138
|
+
"Structured explanations for each reason code with category " +
|
|
139
|
+
"and remediation.",
|
|
140
|
+
required_fields: Object.freeze([
|
|
141
|
+
"reason_codes",
|
|
142
|
+
"explanations",
|
|
143
|
+
]),
|
|
144
|
+
optional_fields: Object.freeze([
|
|
145
|
+
"decision",
|
|
146
|
+
"receipt_meta",
|
|
147
|
+
]),
|
|
148
|
+
}),
|
|
149
|
+
}),
|
|
150
|
+
|
|
151
|
+
BILLING: Object.freeze({
|
|
152
|
+
family_id: "billing",
|
|
153
|
+
purpose:
|
|
154
|
+
"Discover pricing/package metadata and verify on-chain payment claims.",
|
|
155
|
+
tools: Object.freeze(["atf_billing_info", "atf_billing_claim"]),
|
|
156
|
+
canonical_request: Object.freeze({
|
|
157
|
+
description: "For info: optional packageId filter. " +
|
|
158
|
+
"For claim: tx_signature, wallet, package_id required.",
|
|
159
|
+
fields: Object.freeze({
|
|
160
|
+
packageId: {
|
|
161
|
+
type: "string",
|
|
162
|
+
required: false,
|
|
163
|
+
description: "Filter to a specific package (billing_info).",
|
|
164
|
+
},
|
|
165
|
+
tx_signature: {
|
|
166
|
+
type: "string",
|
|
167
|
+
required: "claim_only",
|
|
168
|
+
description: "Solana transaction signature (billing_claim).",
|
|
169
|
+
},
|
|
170
|
+
wallet: {
|
|
171
|
+
type: "string",
|
|
172
|
+
required: "claim_only",
|
|
173
|
+
description: "Claimant wallet address (billing_claim).",
|
|
174
|
+
},
|
|
175
|
+
package_id: {
|
|
176
|
+
type: "string",
|
|
177
|
+
required: "claim_only",
|
|
178
|
+
description: "Package being claimed (billing_claim).",
|
|
179
|
+
},
|
|
180
|
+
asset_symbol: {
|
|
181
|
+
type: "string",
|
|
182
|
+
required: false,
|
|
183
|
+
description: "Optional asset hint: USDC or SOL.",
|
|
184
|
+
},
|
|
185
|
+
cluster: {
|
|
186
|
+
type: "string",
|
|
187
|
+
required: false,
|
|
188
|
+
description: "Solana cluster (default: mainnet-beta).",
|
|
189
|
+
},
|
|
190
|
+
}),
|
|
191
|
+
}),
|
|
192
|
+
canonical_response: Object.freeze({
|
|
193
|
+
description:
|
|
194
|
+
"For info: package/pricing/payment metadata. " +
|
|
195
|
+
"For claim: deterministic verification result.",
|
|
196
|
+
required_fields: Object.freeze([
|
|
197
|
+
"claim_status|packages",
|
|
198
|
+
]),
|
|
199
|
+
optional_fields: Object.freeze([
|
|
200
|
+
"deny_code",
|
|
201
|
+
"payment_rails",
|
|
202
|
+
"activation",
|
|
203
|
+
"warnings",
|
|
204
|
+
"remediation",
|
|
205
|
+
"amount_received",
|
|
206
|
+
"asset_symbol",
|
|
207
|
+
"treasury_verified",
|
|
208
|
+
"payment_verified",
|
|
209
|
+
"entitlement_status",
|
|
210
|
+
"free_vs_advanced",
|
|
211
|
+
]),
|
|
212
|
+
}),
|
|
213
|
+
}),
|
|
214
|
+
|
|
215
|
+
DISCOVERY: Object.freeze({
|
|
216
|
+
family_id: "discovery",
|
|
217
|
+
purpose:
|
|
218
|
+
"Discover ATF capabilities, manifest, bootstrap recipes, and toolcard.",
|
|
219
|
+
tools: Object.freeze([
|
|
220
|
+
"atf_discover",
|
|
221
|
+
"atf_bootstrap_plan",
|
|
222
|
+
"atf_bootstrap_execute_safe",
|
|
223
|
+
]),
|
|
224
|
+
canonical_request: Object.freeze({
|
|
225
|
+
description: "Optional recipe ID or manifest URL override.",
|
|
226
|
+
fields: Object.freeze({
|
|
227
|
+
recipe: {
|
|
228
|
+
type: "string",
|
|
229
|
+
required: false,
|
|
230
|
+
description: "Bootstrap recipe ID.",
|
|
231
|
+
},
|
|
232
|
+
manifestUrl: {
|
|
233
|
+
type: "string",
|
|
234
|
+
required: false,
|
|
235
|
+
description: "Override manifest fetch URL.",
|
|
236
|
+
},
|
|
237
|
+
dryRun: {
|
|
238
|
+
type: "boolean",
|
|
239
|
+
required: false,
|
|
240
|
+
description: "Preview steps without executing (execute_safe).",
|
|
241
|
+
},
|
|
242
|
+
}),
|
|
243
|
+
}),
|
|
244
|
+
canonical_response: Object.freeze({
|
|
245
|
+
description:
|
|
246
|
+
"Manifest summary, bootstrap steps, or execution results.",
|
|
247
|
+
required_fields: Object.freeze(["status"]),
|
|
248
|
+
optional_fields: Object.freeze([
|
|
249
|
+
"id",
|
|
250
|
+
"version",
|
|
251
|
+
"capabilities",
|
|
252
|
+
"recipe_ids",
|
|
253
|
+
"steps",
|
|
254
|
+
"exitCode",
|
|
255
|
+
]),
|
|
256
|
+
}),
|
|
257
|
+
}),
|
|
258
|
+
|
|
259
|
+
PROTECTION: Object.freeze({
|
|
260
|
+
family_id: "protection",
|
|
261
|
+
purpose:
|
|
262
|
+
"Evaluate intents against policy, verify receipts, report savings.",
|
|
263
|
+
tools: Object.freeze([
|
|
264
|
+
"atf_protect_intent",
|
|
265
|
+
"atf_verify_receipt",
|
|
266
|
+
"atf_report_savings",
|
|
267
|
+
]),
|
|
268
|
+
canonical_request: Object.freeze({
|
|
269
|
+
description:
|
|
270
|
+
"For protect: intent object. For verify: receipt. " +
|
|
271
|
+
"For savings: optional receipt count/dir.",
|
|
272
|
+
fields: Object.freeze({
|
|
273
|
+
intentJson: {
|
|
274
|
+
type: "object",
|
|
275
|
+
required: "protect_only",
|
|
276
|
+
description: "ATF ExecutionRequest or intent object.",
|
|
277
|
+
},
|
|
278
|
+
exposureHints: {
|
|
279
|
+
type: "object",
|
|
280
|
+
required: false,
|
|
281
|
+
description: "Optional exposure hints for savings estimates.",
|
|
282
|
+
},
|
|
283
|
+
receipt: {
|
|
284
|
+
type: "object|string",
|
|
285
|
+
required: "verify_only",
|
|
286
|
+
description: "Receipt JSON, string, or file path.",
|
|
287
|
+
},
|
|
288
|
+
last: {
|
|
289
|
+
type: "integer",
|
|
290
|
+
required: false,
|
|
291
|
+
description: "Number of recent receipts (report_savings).",
|
|
292
|
+
},
|
|
293
|
+
receiptsDir: {
|
|
294
|
+
type: "string",
|
|
295
|
+
required: false,
|
|
296
|
+
description: "Directory containing receipt files.",
|
|
297
|
+
},
|
|
298
|
+
}),
|
|
299
|
+
}),
|
|
300
|
+
canonical_response: Object.freeze({
|
|
301
|
+
description:
|
|
302
|
+
"Allow/deny decision with reason codes, receipt verification, " +
|
|
303
|
+
"or savings summary.",
|
|
304
|
+
required_fields: Object.freeze(["status"]),
|
|
305
|
+
optional_fields: Object.freeze([
|
|
306
|
+
"allow",
|
|
307
|
+
"reason_codes",
|
|
308
|
+
"receipt",
|
|
309
|
+
"verified",
|
|
310
|
+
"content_hash",
|
|
311
|
+
"intent_hash",
|
|
312
|
+
"total_denied",
|
|
313
|
+
"by_reason_code",
|
|
314
|
+
"evidence",
|
|
315
|
+
"savings_estimate_usd",
|
|
316
|
+
]),
|
|
317
|
+
}),
|
|
318
|
+
}),
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// ---------------------------------------------------------------------------
|
|
322
|
+
// Universal result fields — present in every ATF tool result
|
|
323
|
+
// ---------------------------------------------------------------------------
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Fields present in every universal ATF tool result.
|
|
327
|
+
* These are the CORE contract — adapters must preserve them.
|
|
328
|
+
*/
|
|
329
|
+
export const UNIVERSAL_RESULT_FIELDS = Object.freeze([
|
|
330
|
+
"status", // RESPONSE_STATUS value
|
|
331
|
+
"result", // tool-specific payload
|
|
332
|
+
]);
|
|
333
|
+
|
|
334
|
+
// ---------------------------------------------------------------------------
|
|
335
|
+
// Adapter envelope fields — added by transport adapters
|
|
336
|
+
// ---------------------------------------------------------------------------
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Fields added by transport-specific adapters (NOT part of universal contract).
|
|
340
|
+
*
|
|
341
|
+
* For example, the OpenClaw adapter wraps results in:
|
|
342
|
+
* { content: [{type: "text", text}, {type: "json", json: universalResult}] }
|
|
343
|
+
*
|
|
344
|
+
* A CLI adapter might instead output JSON directly.
|
|
345
|
+
* An API adapter might wrap in HTTP response headers + JSON body.
|
|
346
|
+
*/
|
|
347
|
+
export const ADAPTER_ENVELOPE_FIELDS = Object.freeze({
|
|
348
|
+
OPENCLAW: Object.freeze({
|
|
349
|
+
description:
|
|
350
|
+
"OpenClaw wraps the universal result in a content array with " +
|
|
351
|
+
"text + json items. Error responses add isError: true.",
|
|
352
|
+
wrapper_fields: Object.freeze(["content", "isError"]),
|
|
353
|
+
content_item_types: Object.freeze(["text", "json"]),
|
|
354
|
+
}),
|
|
355
|
+
CLI: Object.freeze({
|
|
356
|
+
description:
|
|
357
|
+
"CLI adapter outputs the universal result as formatted JSON to stdout. " +
|
|
358
|
+
"Exit code 0 = success, non-zero = error.",
|
|
359
|
+
wrapper_fields: Object.freeze(["exitCode"]),
|
|
360
|
+
}),
|
|
361
|
+
API: Object.freeze({
|
|
362
|
+
description:
|
|
363
|
+
"API adapter returns the universal result as HTTP JSON response body. " +
|
|
364
|
+
"HTTP status code maps to RESPONSE_STATUS.",
|
|
365
|
+
wrapper_fields: Object.freeze(["httpStatus", "headers"]),
|
|
366
|
+
}),
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// ---------------------------------------------------------------------------
|
|
370
|
+
// Tool → family map
|
|
371
|
+
// ---------------------------------------------------------------------------
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Maps each ATF tool name to its contract family ID.
|
|
375
|
+
*/
|
|
376
|
+
export const TOOL_FAMILY_MAP = Object.freeze({
|
|
377
|
+
atf_health: "readiness",
|
|
378
|
+
atf_integration_doctor: "readiness",
|
|
379
|
+
atf_bot_preflight: "readiness",
|
|
380
|
+
atf_adoption_advisor: "advisory",
|
|
381
|
+
atf_tx_explain: "explanation",
|
|
382
|
+
atf_billing_info: "billing",
|
|
383
|
+
atf_billing_claim: "billing",
|
|
384
|
+
atf_discover: "discovery",
|
|
385
|
+
atf_bootstrap_plan: "discovery",
|
|
386
|
+
atf_bootstrap_execute_safe: "discovery",
|
|
387
|
+
atf_protect_intent: "protection",
|
|
388
|
+
atf_verify_receipt: "protection",
|
|
389
|
+
atf_report_savings: "protection",
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* All 13 canonical tool names, frozen.
|
|
394
|
+
*/
|
|
395
|
+
export const CANONICAL_TOOLS = Object.freeze(
|
|
396
|
+
Object.keys(TOOL_FAMILY_MAP),
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Number of canonical tools. Used by tests for tool count assertions.
|
|
401
|
+
*/
|
|
402
|
+
export const CANONICAL_TOOL_COUNT = CANONICAL_TOOLS.length;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* status_codes.mjs — Universal ATF status code vocabularies
|
|
3
|
+
*
|
|
4
|
+
* Platform-agnostic status enums used across all ATF surfaces:
|
|
5
|
+
* CLI, API, SDK, OpenClaw plugin, future human-dev UIs.
|
|
6
|
+
*
|
|
7
|
+
* These are the CANONICAL source of truth for status values.
|
|
8
|
+
* Adapters (OpenClaw, CLI, etc.) import from here — never duplicate.
|
|
9
|
+
*
|
|
10
|
+
* Exports:
|
|
11
|
+
* - RESPONSE_STATUS — tool response status enum
|
|
12
|
+
* - DOCTOR_STATUS — integration doctor status enum
|
|
13
|
+
* - CLAIM_STATUS — billing claim result status enum
|
|
14
|
+
* - BACKEND_STATUS — backend availability status enum
|
|
15
|
+
* - PREFLIGHT_STATUS — preflight go/no-go signal enum
|
|
16
|
+
* - ADOPTION_TIER — adoption recommendation tier enum
|
|
17
|
+
* - SEVERITY — trigger severity enum
|
|
18
|
+
*
|
|
19
|
+
* No dependencies. No side effects. Pure constants.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Response status — used by all tool responses
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Deterministic status values for tool responses.
|
|
28
|
+
* Every ATF tool response carries one of these.
|
|
29
|
+
*/
|
|
30
|
+
export const RESPONSE_STATUS = Object.freeze({
|
|
31
|
+
/** Tool executed successfully, full capability. */
|
|
32
|
+
OK: "ok",
|
|
33
|
+
/** Tool executed but with reduced capability (e.g. fallback backend). */
|
|
34
|
+
DEGRADED: "degraded",
|
|
35
|
+
/** Tool execution failed — see error and remediation fields. */
|
|
36
|
+
ERROR: "error",
|
|
37
|
+
/** Backend completely unreachable — tool cannot operate. */
|
|
38
|
+
UNAVAILABLE: "unavailable",
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Doctor status — integration readiness check
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Overall integration doctor status. Stable finite set.
|
|
47
|
+
*/
|
|
48
|
+
export const DOCTOR_STATUS = Object.freeze({
|
|
49
|
+
/** Integration healthy. All systems operational. */
|
|
50
|
+
OK: "ok",
|
|
51
|
+
/** Integration degraded. Some capabilities limited. */
|
|
52
|
+
DEGRADED: "degraded",
|
|
53
|
+
/** Integration misconfigured. Check warnings and remediation. */
|
|
54
|
+
MISCONFIGURED: "misconfigured",
|
|
55
|
+
/** Integration unavailable. No ATF backend reachable. */
|
|
56
|
+
UNAVAILABLE: "unavailable",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Claim status — billing claim verification result
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Deterministic claim result statuses.
|
|
65
|
+
*/
|
|
66
|
+
export const CLAIM_STATUS = Object.freeze({
|
|
67
|
+
/** Payment verified, claim approved. */
|
|
68
|
+
VERIFIED: "verified",
|
|
69
|
+
/** Payment verification failed — see deny_code. */
|
|
70
|
+
DENIED: "denied",
|
|
71
|
+
/** Infrastructure error during verification. */
|
|
72
|
+
ERROR: "error",
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Backend status — backend availability
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Backend availability status.
|
|
81
|
+
*/
|
|
82
|
+
export const BACKEND_STATUS = Object.freeze({
|
|
83
|
+
/** Backend healthy and available. */
|
|
84
|
+
OK: "ok",
|
|
85
|
+
/** Backend available but degraded (fallback). */
|
|
86
|
+
DEGRADED: "degraded",
|
|
87
|
+
/** Backend misconfigured. */
|
|
88
|
+
MISCONFIGURED: "misconfigured",
|
|
89
|
+
/** Backend unavailable. */
|
|
90
|
+
UNAVAILABLE: "unavailable",
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Preflight status — pre-session readiness signal
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Preflight go/no-go signal.
|
|
99
|
+
*/
|
|
100
|
+
export const PREFLIGHT_STATUS = Object.freeze({
|
|
101
|
+
/** Ready to protect intents. */
|
|
102
|
+
READY: "ready",
|
|
103
|
+
/** Degraded but operational. */
|
|
104
|
+
DEGRADED: "degraded",
|
|
105
|
+
/** Not ready — see remediation. */
|
|
106
|
+
NOT_READY: "not_ready",
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
// Adoption tier — adoption recommendation tiers
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Adoption recommendation tiers for the adoption advisor.
|
|
115
|
+
*/
|
|
116
|
+
export const ADOPTION_TIER = Object.freeze({
|
|
117
|
+
/** Free core: all enforcement tools, no payment. */
|
|
118
|
+
FREE_CORE: "free_core",
|
|
119
|
+
/** Advanced bot: premium support + operator controls. */
|
|
120
|
+
ADVANCED_BOT: "advanced_bot",
|
|
121
|
+
/** No adoption needed at this time. */
|
|
122
|
+
NONE: "none",
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Severity — trigger severity levels
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Trigger severity levels (ordered: critical > high > medium > low).
|
|
131
|
+
*/
|
|
132
|
+
export const SEVERITY = Object.freeze({
|
|
133
|
+
CRITICAL: "critical",
|
|
134
|
+
HIGH: "high",
|
|
135
|
+
MEDIUM: "medium",
|
|
136
|
+
LOW: "low",
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Severity ordering for comparison.
|
|
141
|
+
* Higher number = more severe.
|
|
142
|
+
*/
|
|
143
|
+
export const SEVERITY_RANK = Object.freeze({
|
|
144
|
+
[SEVERITY.CRITICAL]: 4,
|
|
145
|
+
[SEVERITY.HIGH]: 3,
|
|
146
|
+
[SEVERITY.MEDIUM]: 2,
|
|
147
|
+
[SEVERITY.LOW]: 1,
|
|
148
|
+
});
|