@perkos/agent-sdk 0.7.0 → 0.8.0-rc.1
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 +74 -0
- package/README.md +98 -44
- package/dist/builders.d.ts +5 -1
- package/dist/builders.d.ts.map +1 -1
- package/dist/builders.js +155 -11
- package/dist/builders.js.map +1 -1
- package/dist/client.d.ts +8 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +168 -26
- package/dist/client.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +6 -4
- package/dist/constants.js.map +1 -1
- package/dist/custody/backend.d.ts +4 -0
- package/dist/custody/backend.d.ts.map +1 -0
- package/dist/custody/backend.js +149 -0
- package/dist/custody/backend.js.map +1 -0
- package/dist/custody/cli.d.ts +3 -0
- package/dist/custody/cli.d.ts.map +1 -0
- package/dist/custody/cli.js +43 -0
- package/dist/custody/cli.js.map +1 -0
- package/dist/custody/engine.d.ts +54 -0
- package/dist/custody/engine.d.ts.map +1 -0
- package/dist/custody/engine.js +115 -0
- package/dist/custody/engine.js.map +1 -0
- package/dist/custody/ledger.d.ts +24 -0
- package/dist/custody/ledger.d.ts.map +1 -0
- package/dist/custody/ledger.js +122 -0
- package/dist/custody/ledger.js.map +1 -0
- package/dist/custody/permit.d.ts +42 -0
- package/dist/custody/permit.d.ts.map +1 -0
- package/dist/custody/permit.js +91 -0
- package/dist/custody/permit.js.map +1 -0
- package/dist/custody/socket.d.ts +11 -0
- package/dist/custody/socket.d.ts.map +1 -0
- package/dist/custody/socket.js +118 -0
- package/dist/custody/socket.js.map +1 -0
- package/dist/evaluation-commitments.d.ts +47 -0
- package/dist/evaluation-commitments.d.ts.map +1 -0
- package/dist/evaluation-commitments.js +96 -0
- package/dist/evaluation-commitments.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/cli.d.ts +3 -0
- package/dist/mcp/cli.d.ts.map +1 -0
- package/dist/mcp/cli.js +36 -0
- package/dist/mcp/cli.js.map +1 -0
- package/dist/mcp/evaluation.d.ts +33 -0
- package/dist/mcp/evaluation.d.ts.map +1 -0
- package/dist/mcp/evaluation.js +141 -0
- package/dist/mcp/evaluation.js.map +1 -0
- package/dist/mcp/server.d.ts +27 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +207 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +7 -2
- package/dist/policy.js.map +1 -1
- package/dist/service-fees.d.ts +15 -0
- package/dist/service-fees.d.ts.map +1 -0
- package/dist/service-fees.js +109 -0
- package/dist/service-fees.js.map +1 -0
- package/dist/types.d.ts +66 -2
- package/dist/types.d.ts.map +1 -1
- package/docs/ARCHITECTURE.md +31 -15
- package/docs/EXISTING_AGENT.md +123 -0
- package/docs/HERMES_BUYER.md +91 -0
- package/docs/HERMES_CHECKPOINTS.md +88 -0
- package/docs/HERMES_CUSTODY.md +164 -0
- package/docs/HERMES_MCP.md +157 -0
- package/docs/HERMES_PROVIDER.md +98 -0
- package/docs/RELEASE_0.8.0_RC1.md +60 -0
- package/docs/SERVICE_FEES.md +108 -0
- package/docs/TESTNET_QUICKSTART.md +123 -0
- package/docs/VALIDATION_AND_RELEASE.md +82 -0
- package/docs/WALLET_SIGNER_SETUP.md +52 -0
- package/examples/service-fees.ts +36 -0
- package/examples/testnet-journal.ts +57 -0
- package/examples/testnet-lifecycle.ts +188 -294
- package/examples/testnet.env.example +12 -14
- package/package.json +7 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Role-separated agent onboarding — QA candidate
|
|
2
|
+
|
|
3
|
+
This guide describes the QA candidate, not a published npm release. The role-separated
|
|
4
|
+
SDK/committed-evaluation flow has completed controlled STX and sBTC testnet jobs; this
|
|
5
|
+
does not certify a live Hermes installation or external adoption.
|
|
6
|
+
Use Node.js 22 and the reviewed QA commit. Do not point it at mainnet.
|
|
7
|
+
The app's default deployments, production and the published package are unchanged.
|
|
8
|
+
|
|
9
|
+
## Roles and custody
|
|
10
|
+
|
|
11
|
+
- Buyer: owns criteria, creates the job, sets its budget, funds escrow and assigns a provider.
|
|
12
|
+
- Provider: owns its wallet, performs the work and submits the committed evidence manifest.
|
|
13
|
+
- Evaluator service: verifies chain state and downloaded evidence, then records its decision.
|
|
14
|
+
- Human appeal authority: handles disputes; it is not installed in either participant agent.
|
|
15
|
+
|
|
16
|
+
Create separate testnet wallets with your custody provider. Keep each key in its own signer
|
|
17
|
+
boundary, fund only the required test tokens and STX gas, and never share the evaluator key.
|
|
18
|
+
The example imports an **operator-selected absolute module path** exporting a `PerkOSSigner`
|
|
19
|
+
named `signer`. Do not let an LLM or external job select that module. Its implementation must
|
|
20
|
+
restrict network, contracts, operation, nonce and gas fees and durably account for wallet spending.
|
|
21
|
+
SDK spending policies are per process and do not replace persistent custody limits.
|
|
22
|
+
The separate [Hermes MCP adapter](HERMES_MCP.md) defaults to read/prepare only. Optional
|
|
23
|
+
[bounded custody delegation](HERMES_CUSTODY.md) is a QA source candidate for wallet-enabled
|
|
24
|
+
actions; it still requires review, deployment, Linux isolation and actual Hermes E2E validation.
|
|
25
|
+
Provider MCP may additionally opt into public QA evaluation admission after its confirmed
|
|
26
|
+
submission; see [the exact tools and operator flag](HERMES_MCP.md#optional-provider-evaluation-admission).
|
|
27
|
+
The CLI walkthrough below remains a separate operator-driven example, not proof of Hermes autonomy.
|
|
28
|
+
|
|
29
|
+
## Install and preview
|
|
30
|
+
|
|
31
|
+
From the reviewed SDK source checkout:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm ci
|
|
35
|
+
npm run verify
|
|
36
|
+
npm run quickstart:testnet
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The last command defaults to offline preview; it does not load a signer or call a network.
|
|
40
|
+
For clean-consumer testing, build and pack the candidate, then install that tarball in a
|
|
41
|
+
separate project with Node 22 and `tsx`. Do not publish or overwrite npm 0.7.1.
|
|
42
|
+
|
|
43
|
+
## Supply real job inputs
|
|
44
|
+
|
|
45
|
+
Keep a JSON config **outside Git**, with one copy for each role. Required fields:
|
|
46
|
+
|
|
47
|
+
| Field | Value |
|
|
48
|
+
|---|---|
|
|
49
|
+
| network / asset | `testnet` / `stx` or `sbtc` |
|
|
50
|
+
| role | `client` or `provider` |
|
|
51
|
+
| client / provider / evaluator / treasury | Four distinct real testnet principals; evaluator and treasury must match QA policy |
|
|
52
|
+
| amount | Decimal string in micro-STX or satoshis; example cap 100000 or 1000 respectively |
|
|
53
|
+
| expiredAt | Future **Stacks block height**, not burn height or Unix time |
|
|
54
|
+
| description | Real ASCII work description, at most 428 characters |
|
|
55
|
+
| acceptanceCriteria | Array of `{ id, requirement, verification }` fixed by the buyer before creation |
|
|
56
|
+
| jobId | Confirmed job ID, required after creation |
|
|
57
|
+
| evidence | Provider's real `{ id, uri, sha256, mediaType, sizeBytes }` manifest |
|
|
58
|
+
| agentName | Optional real participant name |
|
|
59
|
+
|
|
60
|
+
Use the configured QA evaluator's evidence origin allowlist. Automatic review initially supports
|
|
61
|
+
up to five HTTPS UTF-8 text/plain or application/json files, 8192 bytes per file, 16000 bytes total.
|
|
62
|
+
Hash the exact downloaded bytes; no fake URLs or invented deliverables. Public manifests and
|
|
63
|
+
chain commitments must never contain secrets. Preserve the original criteria file for both roles.
|
|
64
|
+
|
|
65
|
+
## Run one step at a time
|
|
66
|
+
|
|
67
|
+
Set `PERKOS_RUN_CONFIG`, `PERKOS_JOURNAL` and `PERKOS_SIGNER_MODULE` to absolute paths outside Git.
|
|
68
|
+
Use a dedicated journal per role and run. Enable `PERKOS_CONFIRM_TESTNET_BROADCAST=yes` only for
|
|
69
|
+
the intended operation. Funding and submission also require
|
|
70
|
+
`PERKOS_ACCEPT_SERVICE_FEE=200bps-net-after-evaluation`.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
PERKOS_ACTION=register npm run quickstart:testnet
|
|
74
|
+
PERKOS_ACTION=create npm run quickstart:testnet
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Both participants register using their own process. Only the buyer creates. Copy the confirmed
|
|
78
|
+
`(ok uN)` job ID from creation into both role configs, then execute separately:
|
|
79
|
+
|
|
80
|
+
1. Buyer: `set-budget`, then `fund`, then `assign`.
|
|
81
|
+
2. Provider: do the actual work, prepare the real evidence manifest, then `submit`.
|
|
82
|
+
3. Either role: `evaluate` against an explicitly configured `PERKOS_EVALUATOR_URL` QA origin.
|
|
83
|
+
4. Either role: `status`. It is read-only and needs no signer or broadcast opt-in.
|
|
84
|
+
5. Buyer: `finalize` only after decision-pending, no appeal, and current burn height strictly
|
|
85
|
+
greater than the appeal deadline. Disputes require the appeal workflow, not bypassing this gate.
|
|
86
|
+
|
|
87
|
+
A `202` response means admitted, not approved. Poll the returned evaluation ID at
|
|
88
|
+
`GET /v1/evaluations/{id}` and inspect the on-chain job. A recorded decision does not transfer
|
|
89
|
+
escrow. On finalization, independently verify the 98/2 provider/treasury split (or evaluated
|
|
90
|
+
rejection refund), zero escrow and reputation sync. Gas is additional, paid by each transaction signer.
|
|
91
|
+
The 2% fee is earned on evaluation and stays in escrow until settlement; no extra appeal fee is added.
|
|
92
|
+
|
|
93
|
+
## Commitments without new contracts
|
|
94
|
+
|
|
95
|
+
`prepareEvaluationJob(input)` returns the description plus a versioned SHA-256 criteria marker.
|
|
96
|
+
`prepareEvaluationSubmission(input)` returns a 36-byte deliverable: ASCII `ny1:` and the raw
|
|
97
|
+
32-byte evidence digest, fitting existing `(buff 64)` contracts.
|
|
98
|
+
|
|
99
|
+
Both use fixed projected JSON fields, lexicographically sorted keys, ordered arrays, UTF-8 and
|
|
100
|
+
distinct hash domains. Criteria bind network/asset/contract/client/evaluator/description.
|
|
101
|
+
Evidence additionally binds job ID, provider and criteria hash. Do not reorder arrays, normalize
|
|
102
|
+
text or change manifests after signing. `evaluationJobId` derives a deterministic job-scoped
|
|
103
|
+
request identifier; it is **not** a credential.
|
|
104
|
+
|
|
105
|
+
Hashes protect manifest integrity, not evidence truth. Only the on-chain client can commit the
|
|
106
|
+
criteria and only the assigned provider can submit the evidence. Public HTTP callers may trigger
|
|
107
|
+
verification of those exact commitments, but cannot change criteria, spend participant wallets
|
|
108
|
+
or force the evaluator to approve.
|
|
109
|
+
|
|
110
|
+
## Recovery and limitations
|
|
111
|
+
|
|
112
|
+
The append-only mode-600 journal records an attempt before signing and stores the txid before
|
|
113
|
+
confirmation. Repeating an identical invocation confirms that txid instead of signing again.
|
|
114
|
+
Changed action inputs, a stale lock, malformed journal or ambiguous attempt fail closed.
|
|
115
|
+
Never delete checkpoints to force a retry: reconcile the wallet nonce and transaction history first.
|
|
116
|
+
Ambiguous signing failures require operator reconciliation; no exactly-once
|
|
117
|
+
network guarantee is claimed. A dry preview is not an on-chain E2E test.
|
|
118
|
+
|
|
119
|
+
The evaluator public writer defaults off; controlled QA has enabled bounded admission and
|
|
120
|
+
passed database/restart and two-role STX/sBTC E2E gates. Isolated live Hermes integration,
|
|
121
|
+
x402-protected API walkthrough and recorded demo remain separate gates.
|
|
122
|
+
The existing x402/MPP clients are separate from this escrow evaluation trigger;
|
|
123
|
+
this route does not introduce another payment or imply x402 coverage was tested here.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Hermes validation and release boundary
|
|
2
|
+
|
|
3
|
+
## What was verified
|
|
4
|
+
|
|
5
|
+
On 2026-09-08 UTC, one **internal, operator-supervised Stacks testnet** sBTC job completed
|
|
6
|
+
using real Hermes participants, the SDK/MCP tools, isolated policy signers and Nayori's evaluator.
|
|
7
|
+
This is evidence for one scenario, not certification of all workflows or external onboarding.
|
|
8
|
+
|
|
9
|
+
| Check | Observed result |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| SDK source | `fc0537477fda819fa9cce8e74e543be0d49ea3a4` on QA |
|
|
12
|
+
| Contract / job | `ST16EWRC01S1SFWGBP63MW47VY8P3AYFA8VGEBGE5.sbtc-commerce-v5`, job 14 |
|
|
13
|
+
| Participants | Existing registered agents, separate buyer/provider/evaluator roles |
|
|
14
|
+
| Workflow | Create → budget → fund → assign → actual work → submit → evaluate → finalize |
|
|
15
|
+
| Work | Compute 23 + 19 and explain; actual result 42 with an explanation |
|
|
16
|
+
| Outcome | Completed; zero escrow; exactly 980 atomic sBTC to provider and 20 to treasury |
|
|
17
|
+
| Reputation | One completed job, no disputed job; no pending synchronization |
|
|
18
|
+
| Confirmation | Finalization in burn 14234; six-burn custody gate passed at 14240 |
|
|
19
|
+
|
|
20
|
+
Public chain evidence:
|
|
21
|
+
|
|
22
|
+
- [Submission](https://explorer.hiro.so/txid/0x8c99de7f560e82da0483875677ab2de3370403e2a617dff445a77cff40f0da31?chain=testnet)
|
|
23
|
+
- [Evaluator approval](https://explorer.hiro.so/txid/0x2806cebb488794c6a8ff63bf9f437978dc7e492254974c3f06d400381b7a1f27?chain=testnet)
|
|
24
|
+
- [Final settlement, Stacks block 288396](https://explorer.hiro.so/txid/0x382e05645560acbd822f573cab6e32579ad1d8ad3d1598916f132b28b86cce4c?chain=testnet)
|
|
25
|
+
|
|
26
|
+
No new registration was performed in this cycle: existing records were verified and reused.
|
|
27
|
+
New developers must still follow [registration](EXISTING_AGENT.md); do not repeat registration
|
|
28
|
+
for an already active identity simply to match a video. Use your own agent, LLM and signer.
|
|
29
|
+
Do not send funds to the addresses in this historical evidence.
|
|
30
|
+
|
|
31
|
+
## Published package versus tested source
|
|
32
|
+
|
|
33
|
+
| Distribution | Boundary |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| npm `@perkos/agent-sdk@0.7.1` | Published v5/v4 baseline; does not include the local QA Hermes/custody/fee additions |
|
|
36
|
+
| Reviewed QA source above | Tested v6/v5 opt-in fee path, local Hermes MCP, custody and evaluation admission |
|
|
37
|
+
| Historical QA tarball used in the lifecycle | Reports version 0.7.1; source commit and artifact integrity distinguish it from npm |
|
|
38
|
+
| Current source candidate | 0.8.0-rc.1, not published; see [candidate notes](RELEASE_0.8.0_RC1.md) |
|
|
39
|
+
|
|
40
|
+
Do not publish the candidate over 0.7.1 or describe it as an npm-only installation test. Use
|
|
41
|
+
the [exact-artifact installation procedure](HERMES_MCP.md), never an unpinned financial `npx`.
|
|
42
|
+
|
|
43
|
+
Before external distribution: review and merge the release changes, assign a new package version,
|
|
44
|
+
run the SDK gate, pack and inspect its allowlisted contents, then install that exact artifact in
|
|
45
|
+
a clean consumer. Verify imports, binaries and both role guides. Publish only after separate
|
|
46
|
+
release approval; verify registry integrity and repeat clean installation from the published
|
|
47
|
+
version. A QA merge, npm publication and production deployment are separate events.
|
|
48
|
+
|
|
49
|
+
## Report three independent outcomes
|
|
50
|
+
|
|
51
|
+
1. **Conversation:** Hermes must explicitly report `completed=true`; a `type: result` envelope
|
|
52
|
+
alone is insufficient. A tool may have executed even when the conversation stopped at its limit.
|
|
53
|
+
2. **Operation:** preserve the actual intent, txid and journal; query the existing operation after
|
|
54
|
+
timeout or interruption. Never re-sign merely because the conversation did not complete.
|
|
55
|
+
3. **Economics:** independently verify canonical success, confirmation depth, terminal job state,
|
|
56
|
+
zero escrow, exact unique transfers and reputation. Evaluator approval is not payment.
|
|
57
|
+
|
|
58
|
+
Count persisted LLM attempts separately from received responses. Missing usage means **unknown**,
|
|
59
|
+
not zero. Track buyer, provider and evaluator independently; a configured maximum is a bound,
|
|
60
|
+
not an observed call count or bill. This cycle observed 26 Hermes calls; evaluator usage is bounded
|
|
61
|
+
by four calls but its exact count is not established by this report.
|
|
62
|
+
|
|
63
|
+
## Two different evidence hashes
|
|
64
|
+
|
|
65
|
+
The evaluator artifact/decision uses SHA-256 of the canonical evidence list. The SDK's versioned
|
|
66
|
+
submission commitment additionally binds domain, network, contract, job, roles and criteria.
|
|
67
|
+
These hashes are intentionally different. Recompute each from its own input: compare the
|
|
68
|
+
SDK commitment to `submit-work`/the job deliverable and the manifest hash to the evaluator
|
|
69
|
+
artifact/`record-decision`. Verify the public explanation digest and fetched evidence bytes too.
|
|
70
|
+
Never accept a mismatched hash by copying the expected value from the response under test.
|
|
71
|
+
|
|
72
|
+
## Still outside this proof
|
|
73
|
+
|
|
74
|
+
- Fresh npm-only installation, new-agent registration in this cycle, and the developer video.
|
|
75
|
+
- Autonomous operation from one instruction without the operator's staged gates.
|
|
76
|
+
- The separate x402/MPP resource-purchase workflow; local QA MCP does not purchase x402.
|
|
77
|
+
- Other assets, rejection/appeal/recovery scenarios, or production fee activation.
|
|
78
|
+
- External security review or independent adoption: these participants are team-operated testnet actors.
|
|
79
|
+
|
|
80
|
+
Continue with the [buyer](HERMES_BUYER.md), [provider](HERMES_PROVIDER.md) and
|
|
81
|
+
[checkpoint](HERMES_CHECKPOINTS.md) manuals. Every new funded scenario requires its own reviewed
|
|
82
|
+
permissions and budget; never reuse this completed job's authorization.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Operator-owned wallet and signer preparation
|
|
2
|
+
|
|
3
|
+
This is a separate operator checklist, **not a Nayori wallet-generation or custody service**.
|
|
4
|
+
Your existing agent and LLM are already running. Return to [agent onboarding](EXISTING_AGENT.md)
|
|
5
|
+
after preparing a signer. Nayori never needs your private key or model-provider credentials.
|
|
6
|
+
|
|
7
|
+
## Existing wallet or new wallet
|
|
8
|
+
|
|
9
|
+
Reuse a dedicated testnet signer if it meets these controls. Otherwise create a dedicated wallet
|
|
10
|
+
using your reviewed Stacks-compatible wallet tooling or a separately maintained Stacks.js operator
|
|
11
|
+
utility. Verify the dependency/version and network; do not ask an LLM to invent a key or use a
|
|
12
|
+
public test fixture. Keep generation and recovery outside the Nayori SDK and agent's tool set.
|
|
13
|
+
|
|
14
|
+
1. Store the key in your own protected signer storage, outside repositories and agent-readable
|
|
15
|
+
files. Encrypt backups under operator control. A mode-0600 file alone is not an encrypted backup.
|
|
16
|
+
2. Verify restoration derives the same public testnet address before funding. Never show the key
|
|
17
|
+
or recovery phrase in tickets, prompts, logs, terminal recordings or documentation.
|
|
18
|
+
3. Give each independently operated buyer/provider a separate identity and signer boundary.
|
|
19
|
+
Keep transaction sender and the intended registered metadata wallet aligned; registry ownership
|
|
20
|
+
follows `creator` (transaction sender), not an arbitrary metadata wallet.
|
|
21
|
+
4. Fund only the test assets and STX network fees needed for the authorized test. Do not send
|
|
22
|
+
mainnet assets to an example/fixture or assume a displayed testnet balance is spendable mainnet value.
|
|
23
|
+
|
|
24
|
+
## Human-approved or autonomous signatures
|
|
25
|
+
|
|
26
|
+
- A browser wallet can request human approval through the SDK's browser signer interface.
|
|
27
|
+
- An autonomous agent requests a bounded operation from **your own signer service**. An
|
|
28
|
+
operator-maintained Stacks.js implementation can validate, construct and sign transactions.
|
|
29
|
+
This library option is not a turnkey managed signing service supplied by Nayori.
|
|
30
|
+
- Integrate your signer through the documented `PerkOSSigner` interface or the reviewed QA
|
|
31
|
+
custody bridge. A callback that loads a key in the LLM's process is not an isolation boundary.
|
|
32
|
+
|
|
33
|
+
Before enabling autonomous signing, enforce:
|
|
34
|
+
|
|
35
|
+
- Authenticated caller and role; allowed network, contracts, functions and recipients.
|
|
36
|
+
- Explicit per-operation amount, total budget, expiry, asset and STX gas caps.
|
|
37
|
+
- Exact arguments/post-conditions; no arbitrary transaction bytes or module paths selected by an LLM.
|
|
38
|
+
- Separate OS identity/process and private mounts; no shared key access, sudo or Docker socket.
|
|
39
|
+
- Durable intent/nonce/txid journal and serialized use of one wallet across workers.
|
|
40
|
+
- Stop on ambiguous signing/broadcast; inspect chain/mempool before retrying, never delete the journal.
|
|
41
|
+
- An operator-controlled disable switch; test denied actions with signing off first.
|
|
42
|
+
|
|
43
|
+
SDK spending policies are per-process checks, not a replacement for persistent signer-side
|
|
44
|
+
authorization. The candidate [custody guide](HERMES_CUSTODY.md) documents a restricted QA example;
|
|
45
|
+
it is not a general-purpose production custody service or externally audited wallet manager.
|
|
46
|
+
|
|
47
|
+
## Safe handoff to the agent
|
|
48
|
+
|
|
49
|
+
Provide only public network/identity/configuration and the restricted tool or authenticated IPC
|
|
50
|
+
entry point. Keep signer credentials out of prompts and tool arguments. Prove that an allowed
|
|
51
|
+
testnet registration can be requested, a forbidden role/action is denied and the agent cannot
|
|
52
|
+
read key material. Then continue with [registration and confirmation](EXISTING_AGENT.md#4-register-and-verify-the-agent).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PerkOSClient,
|
|
3
|
+
quoteServiceFee,
|
|
4
|
+
type AmountLike,
|
|
5
|
+
type PaymentAsset,
|
|
6
|
+
} from "../src/index.js";
|
|
7
|
+
|
|
8
|
+
/** Signer-free report. It neither grants consent nor broadcasts a transaction. */
|
|
9
|
+
export async function inspectEarnedServiceFee(
|
|
10
|
+
client: PerkOSClient,
|
|
11
|
+
asset: PaymentAsset,
|
|
12
|
+
jobId: AmountLike
|
|
13
|
+
) {
|
|
14
|
+
if (!client.supportsServiceFees(asset))
|
|
15
|
+
return { kind: "no-service-fee-generation" as const };
|
|
16
|
+
const job = await client.getJob(asset, jobId);
|
|
17
|
+
if (!job) throw new Error("Job not found");
|
|
18
|
+
const fees = await client.getJobServiceFee(asset, jobId);
|
|
19
|
+
const quote = quoteServiceFee(job.budget);
|
|
20
|
+
return {
|
|
21
|
+
kind: "earned-service-fee" as const,
|
|
22
|
+
asset,
|
|
23
|
+
jobId: job.id.toString(),
|
|
24
|
+
gross: quote.gross.toString(),
|
|
25
|
+
potentialFee: quote.fee.toString(),
|
|
26
|
+
netIfEvaluated: (fees.waiver ? quote.gross : quote.net).toString(),
|
|
27
|
+
treasury: fees.treasury,
|
|
28
|
+
chargedFee: (fees.settlement?.chargedFee ?? 0n).toString(),
|
|
29
|
+
refundedFee: (fees.settlement?.refundedFee ?? 0n).toString(),
|
|
30
|
+
refundOutstanding:
|
|
31
|
+
!!fees.waiver &&
|
|
32
|
+
!!fees.settlement &&
|
|
33
|
+
fees.settlement.chargedFee > fees.settlement.refundedFee,
|
|
34
|
+
gas: "Separate STX network fee",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { closeSync, constants, fstatSync, fsyncSync, openSync, readFileSync, writeSync } from "node:fs";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { isAbsolute } from "node:path";
|
|
4
|
+
|
|
5
|
+
type Entry = { key: string; intent: string; state: "attempting" | "broadcast"; txid?: string };
|
|
6
|
+
|
|
7
|
+
/** Append-only journal; caller must hold its exclusive lock. Keep outside Git. */
|
|
8
|
+
export class QuickstartJournal {
|
|
9
|
+
private readonly fd: number;
|
|
10
|
+
private readonly entries: Entry[];
|
|
11
|
+
constructor(path: string) {
|
|
12
|
+
if (!isAbsolute(path)) throw new Error("journal_absolute_path_required");
|
|
13
|
+
this.fd = openSync(path, constants.O_RDWR | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW, 0o600);
|
|
14
|
+
const stat = fstatSync(this.fd);
|
|
15
|
+
if (!stat.isFile() || (stat.mode & 0o777) !== 0o600 || stat.nlink !== 1 || stat.size > 1_048_576 ||
|
|
16
|
+
(process.getuid && stat.uid !== process.getuid())) {
|
|
17
|
+
closeSync(this.fd); throw new Error("unsafe_journal");
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
this.entries = readFileSync(this.fd, "utf8").split("\n").filter(Boolean).map(line => JSON.parse(line) as Entry);
|
|
21
|
+
if (this.entries.some(item => !item || typeof item.key !== "string" || !/^[0-9a-f]{64}$/.test(item.intent) ||
|
|
22
|
+
!["attempting", "broadcast"].includes(item.state) ||
|
|
23
|
+
(item.state === "broadcast" && !/^0x[0-9a-f]{64}$/.test(item.txid ?? "")))) throw new Error("invalid_journal");
|
|
24
|
+
} catch { closeSync(this.fd); throw new Error("journal_requires_reconciliation"); }
|
|
25
|
+
}
|
|
26
|
+
close() { closeSync(this.fd); }
|
|
27
|
+
lookup(key: string, intent: string): Entry | undefined {
|
|
28
|
+
const entries = this.entries.filter(item => item.key === key);
|
|
29
|
+
if (entries.some(item => item.intent !== intent)) throw new Error("journal_intent_mismatch");
|
|
30
|
+
return entries.at(-1);
|
|
31
|
+
}
|
|
32
|
+
append(entry: Entry) {
|
|
33
|
+
const bytes = Buffer.from(JSON.stringify(entry) + "\n");
|
|
34
|
+
let offset = 0;
|
|
35
|
+
while (offset < bytes.length) offset += writeSync(this.fd, bytes, offset);
|
|
36
|
+
fsyncSync(this.fd); this.entries.push(entry);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function intentHash(value: unknown): string {
|
|
40
|
+
return createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
41
|
+
}
|
|
42
|
+
export async function checkpointedTransaction(
|
|
43
|
+
journal: QuickstartJournal, key: string, intent: string, send: () => Promise<string>,
|
|
44
|
+
): Promise<string> {
|
|
45
|
+
const prior = journal.lookup(key, intent);
|
|
46
|
+
if (prior) {
|
|
47
|
+
if (prior.state !== "broadcast" || !/^0x[0-9a-f]{64}$/.test(prior.txid ?? "")) {
|
|
48
|
+
throw new Error("ambiguous_attempt_requires_reconciliation");
|
|
49
|
+
}
|
|
50
|
+
return prior.txid!;
|
|
51
|
+
}
|
|
52
|
+
journal.append({ key, intent, state: "attempting" });
|
|
53
|
+
const txid = await send();
|
|
54
|
+
if (!/^0x[0-9a-f]{64}$/.test(txid)) throw new Error("invalid_txid_requires_reconciliation");
|
|
55
|
+
journal.append({ key, intent, state: "broadcast", txid });
|
|
56
|
+
return txid;
|
|
57
|
+
}
|