@thirdfy/agent-cli 0.2.7 → 0.2.8
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/CHANGELOG.md +10 -0
- package/README.md +4 -4
- package/package.json +1 -1
- package/src/core/earnclawAttribution.mjs +7 -0
- package/src/core/executionContext.mjs +50 -0
- package/src/core/http.mjs +18 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.2.8] - 2026-06-13
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- EarnClaw runtime attribution on all API POSTs: reads `THIRDFY_EXECUTION_RUNTIME_ID` / `THIRDFY_EXECUTION_ORG_ID` (with `EARNCLAW_*` fallback) and sends `executionContext` plus `x-thirdfy-execution-*` headers on execute paths. Pairs with Thirdfy API v3.4.55+ for per-runtime credit debits.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- `apiPost` resolves execution context headers from the request body, not env only.
|
|
16
|
+
|
|
7
17
|
## [0.2.7] - 2026-06-08
|
|
8
18
|
|
|
9
19
|
### Added
|
package/README.md
CHANGED
|
@@ -40,11 +40,11 @@ Run without global install:
|
|
|
40
40
|
npx @thirdfy/agent-cli --help
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
## What's new in v0.2.
|
|
43
|
+
## What's new in v0.2.8
|
|
44
44
|
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
45
|
+
- Hosted runtimes can set `THIRDFY_EXECUTION_RUNTIME_ID` and `THIRDFY_EXECUTION_ORG_ID` in machine env (EarnClaw also sets legacy `EARNCLAW_*` aliases). The CLI forwards neutral `executionContext` on Thirdfy API POSTs.
|
|
46
|
+
- Attribution uses `x-thirdfy-execution-runtime-id`, `x-thirdfy-execution-org-id`, and `executionContext` on execute payloads.
|
|
47
|
+
- Pairs with Thirdfy API v3.4.55+ and EarnClaw cost sync `attribution=strict`.
|
|
48
48
|
|
|
49
49
|
Older versions: [CHANGELOG.md](./CHANGELOG.md) and [GitHub Releases](https://github.com/thirdfy/agent-cli/releases).
|
|
50
50
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** @deprecated Import from executionContext.mjs instead. */
|
|
2
|
+
export {
|
|
3
|
+
resolveExecutionContextFromEnv as resolveEarnClawAttributionFromEnv,
|
|
4
|
+
resolveExecutionContextFromInput as resolveEarnClawAttributionFromInput,
|
|
5
|
+
buildExecutionContextHeaders as buildEarnClawAttributionHeaders,
|
|
6
|
+
mergeExecutionContext as mergeEarnClawContext,
|
|
7
|
+
} from './executionContext.mjs';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
function readUuid(value) {
|
|
2
|
+
const trimmed = String(value || '').trim();
|
|
3
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(trimmed)
|
|
4
|
+
? trimmed
|
|
5
|
+
: undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function resolveExecutionContextFromEnv() {
|
|
9
|
+
const runtimeId = readUuid(process.env.THIRDFY_EXECUTION_RUNTIME_ID)
|
|
10
|
+
|| readUuid(process.env.EARNCLAW_RUNTIME_ID);
|
|
11
|
+
const orgId = readUuid(process.env.THIRDFY_EXECUTION_ORG_ID)
|
|
12
|
+
|| readUuid(process.env.EARNCLAW_ORG_ID);
|
|
13
|
+
return { runtimeId, orgId };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resolveExecutionContextFromInput(input = {}) {
|
|
17
|
+
const env = resolveExecutionContextFromEnv();
|
|
18
|
+
const executionContext = input.executionContext && typeof input.executionContext === 'object'
|
|
19
|
+
? input.executionContext
|
|
20
|
+
: {};
|
|
21
|
+
const context = input.context && typeof input.context === 'object' ? input.context : {};
|
|
22
|
+
const runtimeId = readUuid(input.runtimeId)
|
|
23
|
+
|| readUuid(executionContext.runtimeId)
|
|
24
|
+
|| readUuid(context.runtimeId)
|
|
25
|
+
|| env.runtimeId;
|
|
26
|
+
const orgId = readUuid(input.orgId)
|
|
27
|
+
|| readUuid(executionContext.orgId)
|
|
28
|
+
|| readUuid(context.orgId)
|
|
29
|
+
|| env.orgId;
|
|
30
|
+
return { runtimeId, orgId };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function buildExecutionContextHeaders(attribution) {
|
|
34
|
+
const headers = {};
|
|
35
|
+
if (attribution.runtimeId) headers['x-thirdfy-execution-runtime-id'] = attribution.runtimeId;
|
|
36
|
+
if (attribution.orgId) headers['x-thirdfy-execution-org-id'] = attribution.orgId;
|
|
37
|
+
return headers;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function mergeExecutionContext(body) {
|
|
41
|
+
const attribution = resolveExecutionContextFromInput(body);
|
|
42
|
+
if (!attribution.runtimeId && !attribution.orgId) return body;
|
|
43
|
+
const executionContext = body.executionContext && typeof body.executionContext === 'object'
|
|
44
|
+
? { ...body.executionContext }
|
|
45
|
+
: {};
|
|
46
|
+
if (attribution.runtimeId && !executionContext.runtimeId) executionContext.runtimeId = attribution.runtimeId;
|
|
47
|
+
if (attribution.orgId && !executionContext.orgId) executionContext.orgId = attribution.orgId;
|
|
48
|
+
if (!executionContext.source) executionContext.source = 'hosted_runtime';
|
|
49
|
+
return { ...body, executionContext };
|
|
50
|
+
}
|
package/src/core/http.mjs
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildExecutionContextHeaders,
|
|
3
|
+
mergeExecutionContext,
|
|
4
|
+
resolveExecutionContextFromInput,
|
|
5
|
+
} from './executionContext.mjs';
|
|
6
|
+
|
|
1
7
|
export async function apiGet(ctx, route, headers = {}) {
|
|
2
|
-
return requestJson(ctx, route, { method: 'GET', headers });
|
|
8
|
+
return requestJson(ctx, route, { method: 'GET', headers: mergeExecutionContextHeaders(headers) });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function mergeExecutionContextHeaders(headers = {}, body = {}) {
|
|
12
|
+
return {
|
|
13
|
+
...buildExecutionContextHeaders(resolveExecutionContextFromInput(body)),
|
|
14
|
+
...headers,
|
|
15
|
+
};
|
|
3
16
|
}
|
|
4
17
|
|
|
5
18
|
export async function apiPost(ctx, route, body, headers = {}) {
|
|
19
|
+
const normalizedBody = body && typeof body === 'object' ? body : {};
|
|
20
|
+
const mergedBody = mergeExecutionContext(normalizedBody);
|
|
6
21
|
return requestJson(ctx, route, {
|
|
7
22
|
method: 'POST',
|
|
8
23
|
headers: {
|
|
9
24
|
'content-type': 'application/json',
|
|
10
|
-
...headers,
|
|
25
|
+
...mergeExecutionContextHeaders(headers, normalizedBody),
|
|
11
26
|
},
|
|
12
|
-
body: JSON.stringify(
|
|
27
|
+
body: JSON.stringify(mergedBody),
|
|
13
28
|
});
|
|
14
29
|
}
|
|
15
30
|
|