archal 0.9.8 → 0.9.10
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 +163 -93
- package/bin/archal.cjs +3 -3
- package/dist/index.cjs +82467 -0
- package/dist/index.d.cts +1 -0
- package/dist/seed/dynamic-generator.cjs +45639 -0
- package/dist/seed/dynamic-generator.d.cts +67 -0
- package/dist/vitest/chunk-KTMNDJFB.js +45973 -0
- package/dist/vitest/chunk-L6HSMJ3F.js +2216 -0
- package/dist/vitest/chunk-YJICENME.js +1230 -0
- package/dist/vitest/index.cjs +51962 -0
- package/dist/vitest/index.d.ts +398 -0
- package/dist/vitest/index.js +2669 -0
- package/dist/vitest/runtime/hosted-session-reaper.cjs +29348 -0
- package/dist/vitest/runtime/hosted-session-reaper.d.ts +2 -0
- package/dist/vitest/runtime/hosted-session-reaper.js +58 -0
- package/dist/vitest/runtime/setup-files.d.ts +2 -0
- package/dist/vitest/runtime/setup-files.js +27 -0
- package/dist/vitest/src-JGHX6UKK.js +94 -0
- package/package.json +15 -19
- package/twin-assets/discord/fidelity.json +113 -0
- package/twin-assets/discord/tools.json +1953 -0
- package/twin-assets/github/fidelity.json +13 -0
- package/twin-assets/github/tools.json +21818 -0
- package/twin-assets/google-workspace/fidelity.json +19 -0
- package/twin-assets/google-workspace/tools.json +10191 -0
- package/twin-assets/jira/fidelity.json +40 -0
- package/twin-assets/jira/tools.json +17387 -0
- package/twin-assets/linear/fidelity.json +18 -0
- package/twin-assets/linear/tools.json +6496 -0
- package/twin-assets/ramp/fidelity.json +22 -0
- package/twin-assets/ramp/tools.json +2610 -0
- package/twin-assets/slack/fidelity.json +20 -0
- package/twin-assets/slack/tools.json +7301 -0
- package/twin-assets/stripe/fidelity.json +22 -0
- package/twin-assets/stripe/tools.json +15284 -0
- package/twin-assets/supabase/fidelity.json +13 -0
- package/twin-assets/supabase/tools.json +2973 -0
- package/dist/vitest.d.ts +0 -1
- package/dist/vitest.js +0 -23
package/README.md
CHANGED
|
@@ -1,38 +1,155 @@
|
|
|
1
1
|
# archal
|
|
2
2
|
|
|
3
|
-
Pre-deployment testing for AI agents via Archal's hosted digital twins
|
|
3
|
+
Pre-deployment testing for AI agents via Archal's hosted digital twins,
|
|
4
|
+
including route-mode twins for Discord, GitHub, Slack, Stripe, Linear, Jira,
|
|
5
|
+
Ramp, Supabase, and Google Workspace.
|
|
6
|
+
|
|
7
|
+
## Early access — expect rough edges
|
|
8
|
+
|
|
9
|
+
`archal@0.9.x` is early access. The CLI and twins work, but the surface is
|
|
10
|
+
still being polished:
|
|
11
|
+
|
|
12
|
+
- `npm install -g archal` prints a handful of peer-dependency warnings
|
|
13
|
+
from the vendored CLI runtime. They are safe to ignore; nothing is
|
|
14
|
+
missing at runtime.
|
|
15
|
+
- A few commands still print one or two help lines to `stderr` instead of
|
|
16
|
+
`stdout`. Scripts that redirect streams will mostly see what they expect,
|
|
17
|
+
but be aware of it.
|
|
18
|
+
- The `vitest` integration under `archal/vitest` depends on `vitest@^2.1.0`.
|
|
19
|
+
If your project is on vitest 3, the shared helper may resolve the wrong
|
|
20
|
+
copy. Pinning a workspace to vitest 2 for your Archal tests fixes it.
|
|
21
|
+
|
|
22
|
+
We're shipping `0.9.x` so that early users can start running the CLI against
|
|
23
|
+
hosted twins. File anything surprising at
|
|
24
|
+
<https://github.com/Archal-Labs/archal/issues>.
|
|
4
25
|
|
|
5
26
|
## Install
|
|
6
27
|
|
|
7
28
|
```bash
|
|
8
|
-
npm install
|
|
29
|
+
npm install -g archal
|
|
9
30
|
```
|
|
10
31
|
|
|
11
32
|
Then authenticate:
|
|
12
33
|
|
|
13
34
|
```bash
|
|
14
|
-
|
|
35
|
+
archal login
|
|
15
36
|
```
|
|
16
37
|
|
|
17
|
-
|
|
38
|
+
This writes credentials to `~/.archal/credentials.json`. You can also set
|
|
39
|
+
`ARCHAL_TOKEN` directly in CI.
|
|
40
|
+
|
|
41
|
+
## CLI — primary use case
|
|
18
42
|
|
|
19
|
-
|
|
43
|
+
The CLI is the primary way to use Archal today. `archal run` executes a
|
|
44
|
+
scenario (a markdown file describing a task, the expected behavior, and
|
|
45
|
+
success criteria) against a hosted twin session and reports a satisfaction
|
|
46
|
+
score.
|
|
20
47
|
|
|
21
|
-
### Quick start
|
|
48
|
+
### Quick start
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# 1. Log in
|
|
52
|
+
archal login
|
|
53
|
+
|
|
54
|
+
# 2. Browse the twin catalog
|
|
55
|
+
archal twin
|
|
56
|
+
|
|
57
|
+
# 3. Start a persistent session with one or more twins
|
|
58
|
+
archal twin start github stripe
|
|
59
|
+
|
|
60
|
+
# 4. Run a scenario from .archal.json in the current directory
|
|
61
|
+
archal run
|
|
62
|
+
|
|
63
|
+
# 5. When you're done
|
|
64
|
+
archal twin stop
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`archal run` auto-discovers an `.archal.json` at the project root. A
|
|
68
|
+
minimal config looks like this:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"scenarios": "./scenarios",
|
|
73
|
+
"twins": ["github", "stripe"],
|
|
74
|
+
"runs": 1
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Supported twins
|
|
79
|
+
|
|
80
|
+
`archal twin` lists the nine twins available today:
|
|
81
|
+
|
|
82
|
+
| Twin | Notes |
|
|
83
|
+
|---|---|
|
|
84
|
+
| Discord | Guilds, channels, messages, members |
|
|
85
|
+
| GitHub | Repos, issues, PRs, labels, reviews |
|
|
86
|
+
| Slack | Channels, messages, users, reactions |
|
|
87
|
+
| Stripe | Customers, subscriptions, invoices, products |
|
|
88
|
+
| Linear | Teams, issues, projects, cycles |
|
|
89
|
+
| Jira | Projects, issues, workflows, components |
|
|
90
|
+
| Ramp | Cards, transactions, reimbursements, users |
|
|
91
|
+
| Supabase | Auth, Postgres, storage, edge functions |
|
|
92
|
+
| Google Workspace | Gmail, Drive, Calendar, Docs, People |
|
|
93
|
+
|
|
94
|
+
### Command reference
|
|
95
|
+
|
|
96
|
+
| Command | What it does |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `archal login` | Authenticate with Archal |
|
|
99
|
+
| `archal logout` | Remove stored credentials |
|
|
100
|
+
| `archal twin` | Browse the twin catalog |
|
|
101
|
+
| `archal twin start [twins...]` | Start a hosted twin session |
|
|
102
|
+
| `archal twin status` | Inspect the active session |
|
|
103
|
+
| `archal twin stop` | Stop the active session |
|
|
104
|
+
| `archal twin list` | List all your active sessions |
|
|
105
|
+
| `archal twin attach <uuid>` | Reattach to a session by id |
|
|
106
|
+
| `archal twin renew <seconds>` | Extend the session lifetime |
|
|
107
|
+
| `archal twin reset` | Reset twin state without tearing down the session |
|
|
108
|
+
| `archal twin seed <twin> <name>` | Load a named seed into a running twin |
|
|
109
|
+
| `archal run [.archal.json]` | Run scenarios from a config file |
|
|
110
|
+
| `archal scenario list` | Browse local and hosted scenarios |
|
|
111
|
+
| `archal seed list [twin]` | List prebuilt twin seeds |
|
|
112
|
+
| `archal trace` | View recent scenario traces |
|
|
113
|
+
| `archal trace <name>` | View trace details for a run |
|
|
114
|
+
| `archal usage` | Check session minutes and plan |
|
|
115
|
+
|
|
116
|
+
Run `archal <command> --help` for flag details.
|
|
117
|
+
|
|
118
|
+
## Vitest integration (secondary use case)
|
|
119
|
+
|
|
120
|
+
You can also import `archal/vitest` to route SDK traffic from a vitest
|
|
121
|
+
suite through a hosted twin, with no code changes to your production
|
|
122
|
+
code. This is useful if you want to test the HTTP side of an integration
|
|
123
|
+
without hitting real provider APIs.
|
|
124
|
+
|
|
125
|
+
> Note: the vitest helper is still evolving. If you're just getting
|
|
126
|
+
> started with Archal, prefer the CLI flow above — it's the best-tested
|
|
127
|
+
> path today.
|
|
128
|
+
|
|
129
|
+
### Minimal config
|
|
22
130
|
|
|
23
131
|
```ts
|
|
24
132
|
import { defineConfig } from 'vitest/config';
|
|
25
|
-
import {
|
|
133
|
+
import { withArchal } from 'archal/vitest';
|
|
26
134
|
|
|
27
135
|
export default defineConfig({
|
|
28
|
-
test:
|
|
29
|
-
|
|
30
|
-
|
|
136
|
+
test: withArchal(
|
|
137
|
+
{
|
|
138
|
+
// everything you already had in test:, unchanged
|
|
139
|
+
globals: true,
|
|
140
|
+
coverage: { provider: 'v8' },
|
|
31
141
|
},
|
|
32
|
-
|
|
142
|
+
{
|
|
143
|
+
services: {
|
|
144
|
+
stripe: { mode: 'route', seed: 'small-business' },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
),
|
|
33
148
|
});
|
|
34
149
|
```
|
|
35
150
|
|
|
151
|
+
`withArchal(existingTest, { services })` wraps an existing `vitest.config.ts`'s `test:` block, preserving every field you already had. Pass `{}` as the first argument if you're starting from scratch.
|
|
152
|
+
|
|
36
153
|
Your existing tests work unchanged:
|
|
37
154
|
|
|
38
155
|
```ts
|
|
@@ -48,22 +165,6 @@ it('creates a customer', async () => {
|
|
|
48
165
|
});
|
|
49
166
|
```
|
|
50
167
|
|
|
51
|
-
### Multi-project monorepos — `vitest.workspace.ts`
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
import { archalVitestProject } from 'archal/vitest';
|
|
55
|
-
|
|
56
|
-
export default [
|
|
57
|
-
archalVitestProject({
|
|
58
|
-
name: 'stripe-integration-tests',
|
|
59
|
-
services: {
|
|
60
|
-
stripe: { mode: 'route', seed: 'small-business' },
|
|
61
|
-
slack: { mode: 'route' },
|
|
62
|
-
},
|
|
63
|
-
}),
|
|
64
|
-
];
|
|
65
|
-
```
|
|
66
|
-
|
|
67
168
|
### Per-test state isolation
|
|
68
169
|
|
|
69
170
|
```ts
|
|
@@ -77,10 +178,10 @@ beforeEach(async () => {
|
|
|
77
178
|
|
|
78
179
|
### Webhook testing
|
|
79
180
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
181
|
+
The hosted twin runs in AWS ECS, so it can't POST to your localhost.
|
|
182
|
+
Instead, your test pulls queued deliveries with `waitForArchalWebhook()`
|
|
183
|
+
and invokes your handler directly with the exact payload the twin would
|
|
184
|
+
have sent.
|
|
84
185
|
|
|
85
186
|
```ts
|
|
86
187
|
import { it, expect } from 'vitest';
|
|
@@ -110,87 +211,68 @@ it('records a subscription when customer.subscription.created fires', async () =
|
|
|
110
211
|
|
|
111
212
|
// 4. Invoke your handler with the exact payload
|
|
112
213
|
await handleStripeWebhook(event.body, event.headers['Stripe-Signature'], process.env.STRIPE_WEBHOOK_SECRET);
|
|
113
|
-
|
|
114
|
-
// 5. Assert your handler did the right thing
|
|
115
|
-
// expect(await db.subscriptions.count()).toBe(1);
|
|
116
214
|
});
|
|
117
215
|
```
|
|
118
216
|
|
|
119
|
-
**
|
|
120
|
-
event. If no endpoint is registered, the twin has nothing to queue and
|
|
121
|
-
`waitForArchalWebhook()` will time out.
|
|
122
|
-
|
|
123
|
-
**Signature verification**: `event.body` is the raw JSON string the twin
|
|
124
|
-
would have POSTed. Pass it and `event.headers['Stripe-Signature']` directly
|
|
125
|
-
to `stripe.webhooks.constructEvent(body, sig, secret)` — the signature is
|
|
126
|
-
HMAC-computed against the body bytes, so re-serializing `event.payload`
|
|
127
|
-
would break verification. Use the secret from the endpoint you registered.
|
|
128
|
-
|
|
129
|
-
**Supported services**:
|
|
217
|
+
**Webhook coverage**:
|
|
130
218
|
|
|
131
219
|
| Service | Support | Notes |
|
|
132
220
|
|---|---|---|
|
|
133
221
|
| Stripe | ✅ | |
|
|
134
222
|
| GitHub | ✅ | |
|
|
135
|
-
| Slack | ✅ | Receiver-side signature only
|
|
223
|
+
| Slack | ✅ | Receiver-side signature only |
|
|
136
224
|
| Jira | ✅ | Delivered via history buffer (also POSTed to registered URLs) |
|
|
137
225
|
| Linear | ✅ | Delivered via history buffer (also POSTed to registered URLs) |
|
|
138
|
-
| Supabase | ❌ |
|
|
139
|
-
| Google Workspace | ❌ |
|
|
226
|
+
| Supabase | ❌ | Database-triggered — test against real Postgres |
|
|
227
|
+
| Google Workspace | ❌ | GCP Pub/Sub push notifications, not webhooks |
|
|
140
228
|
|
|
141
229
|
**Parallel workers caveat**: `waitForArchalWebhook()` consumes deliveries
|
|
142
230
|
from a shared queue by default. When vitest runs test files in parallel
|
|
143
231
|
across workers, worker A can swallow worker B's event. If your tests
|
|
144
232
|
depend on webhook events, set `testIsolation: 'serial'` in your config.
|
|
145
|
-
Alternatively, pass `consume: false` to leave the queue intact after a
|
|
146
|
-
match and use `listArchalWebhooks('stripe')` for sequence assertions.
|
|
147
|
-
|
|
148
|
-
**Slack caveat**: Slack verifies webhook signatures at the receiver using
|
|
149
|
-
the timestamp header + signing secret, not a sender-side signature header.
|
|
150
|
-
Archal's Slack twin does not add a `X-Slack-Signature` header to queued
|
|
151
|
-
deliveries. If your handler verifies signatures, stub that verification
|
|
152
|
-
in tests or compute the header yourself from `delivery.body`.
|
|
153
233
|
|
|
154
234
|
### Test isolation across parallel workers
|
|
155
235
|
|
|
156
|
-
Each vitest worker is
|
|
236
|
+
Each vitest worker is routed to its own per-worker state on the twin —
|
|
237
|
+
parallel tests across workers don't see each other's writes. The
|
|
238
|
+
integration reads `VITEST_WORKER_ID` in each worker process and tags
|
|
239
|
+
every outbound SDK request with an `X-Archal-Worker-Id` header. The twin
|
|
240
|
+
maintains a separate state engine per worker id, seeded from the
|
|
241
|
+
baseline on first request.
|
|
157
242
|
|
|
158
|
-
|
|
159
|
-
// Test A, in worker 1
|
|
160
|
-
const customer = await stripe.customers.create({ email: 'a@x.com' });
|
|
161
|
-
// Test B, in worker 2 (running in parallel, same twin session)
|
|
162
|
-
const list = await stripe.customers.list();
|
|
163
|
-
// list does NOT include a@x.com — each worker's state is isolated
|
|
164
|
-
```
|
|
243
|
+
**Isolation-enabled twins**: Stripe, GitHub, Slack, Jira, Linear.
|
|
165
244
|
|
|
166
|
-
**
|
|
245
|
+
**Twins without isolation** (Supabase, Google Workspace, Ramp) fall back
|
|
246
|
+
to shared state. If your tests depend on global assertions against those
|
|
247
|
+
twins, set `testIsolation: 'serial'`.
|
|
167
248
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
**Memory note**: per-worker state costs N × baseline size per twin process. For 4 workers × 50 KB seed, that's ~200 KB per twin. Not a concern in practice.
|
|
249
|
+
## Authentication
|
|
171
250
|
|
|
172
|
-
|
|
251
|
+
In priority order:
|
|
173
252
|
|
|
174
|
-
|
|
253
|
+
1. `ARCHAL_TOKEN` env var
|
|
254
|
+
2. Stored credentials from `archal login` in `~/.archal/credentials.json`
|
|
175
255
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
```
|
|
256
|
+
This auth is only for Archal's hosted session provisioning. Your app's
|
|
257
|
+
provider credentials do not need to be real when traffic is routed through
|
|
258
|
+
a twin — use placeholder tokens that satisfy the SDK's local validation
|
|
259
|
+
rules, such as `sk_test_fake`, `ghp_fake_token_for_twin`, or a dummy
|
|
260
|
+
Google bearer token.
|
|
182
261
|
|
|
183
|
-
## What you see in the terminal
|
|
262
|
+
## What you'll see in the terminal
|
|
184
263
|
|
|
185
|
-
On the first `
|
|
264
|
+
On the first `archal run`, session provisioning takes about 30 seconds
|
|
265
|
+
(ECS Fargate cold start). A progress line prints every few seconds so
|
|
266
|
+
the wait is visible:
|
|
186
267
|
|
|
187
268
|
```
|
|
188
269
|
[archal] provisioning stripe twin... 5s
|
|
189
|
-
[archal] provisioning stripe
|
|
270
|
+
[archal] provisioning stripe twin... 10s
|
|
190
271
|
...
|
|
191
272
|
```
|
|
192
273
|
|
|
193
|
-
Subsequent runs with the same configuration reuse the warm session
|
|
274
|
+
Subsequent runs with the same configuration reuse the warm session
|
|
275
|
+
(~2 seconds).
|
|
194
276
|
|
|
195
277
|
At the end of every run, the estimated twin-minute usage is printed:
|
|
196
278
|
|
|
@@ -198,18 +280,6 @@ At the end of every run, the estimated twin-minute usage is printed:
|
|
|
198
280
|
[archal] ~2 twin-minutes for this run (38.5s × 1 twin: stripe)
|
|
199
281
|
```
|
|
200
282
|
|
|
201
|
-
Silence these outputs with `ARCHAL_VITEST_QUIET_PROGRESS=1` and `ARCHAL_VITEST_QUIET_USAGE=1`.
|
|
202
|
-
|
|
203
|
-
## Authentication
|
|
204
|
-
|
|
205
|
-
In priority order:
|
|
206
|
-
|
|
207
|
-
1. `ARCHAL_VITEST_TOKEN` env var
|
|
208
|
-
2. `ARCHAL_TOKEN` env var
|
|
209
|
-
3. Stored credentials from `archal login` in `~/.archal/credentials.json`
|
|
210
|
-
|
|
211
283
|
## Docs
|
|
212
284
|
|
|
213
|
-
Full documentation: https://archal.ai
|
|
214
|
-
|
|
215
|
-
Full `@archal/vitest` reference: https://github.com/Archal-Labs/archal/tree/main/packages/vitest/README.md
|
|
285
|
+
Full documentation: <https://docs.archal.ai>
|
package/bin/archal.cjs
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
const { existsSync } = require("node:fs");
|
|
4
4
|
const { join } = require("node:path");
|
|
5
5
|
|
|
6
|
-
// Try the co-located CLI bundle first (when installed as dependency),
|
|
7
|
-
// then fall back to resolving @archal/cli directly.
|
|
8
6
|
const localDist = join(__dirname, "..", "dist", "index.cjs");
|
|
9
7
|
|
|
10
8
|
if (existsSync(localDist)) {
|
|
11
9
|
require(localDist);
|
|
12
10
|
} else {
|
|
13
|
-
|
|
11
|
+
throw new Error(
|
|
12
|
+
'The archal package is missing its bundled CLI payload. Use the published npm package, or build from the Archal repo root with `pnpm run build:archal`.',
|
|
13
|
+
);
|
|
14
14
|
}
|