archal 0.9.8 → 0.9.9

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 (39) hide show
  1. package/README.md +163 -93
  2. package/bin/archal.cjs +3 -3
  3. package/dist/index.cjs +82301 -0
  4. package/dist/index.d.cts +1 -0
  5. package/dist/seed/dynamic-generator.cjs +45640 -0
  6. package/dist/seed/dynamic-generator.d.cts +67 -0
  7. package/dist/vitest/chunk-RKYS44AS.js +2216 -0
  8. package/dist/vitest/chunk-YJICENME.js +1230 -0
  9. package/dist/vitest/chunk-YV6BH6DO.js +45974 -0
  10. package/dist/vitest/index.cjs +51963 -0
  11. package/dist/vitest/index.d.ts +398 -0
  12. package/dist/vitest/index.js +2669 -0
  13. package/dist/vitest/runtime/hosted-session-reaper.cjs +29349 -0
  14. package/dist/vitest/runtime/hosted-session-reaper.d.ts +2 -0
  15. package/dist/vitest/runtime/hosted-session-reaper.js +58 -0
  16. package/dist/vitest/runtime/setup-files.d.ts +2 -0
  17. package/dist/vitest/runtime/setup-files.js +27 -0
  18. package/dist/vitest/src-JGHX6UKK.js +94 -0
  19. package/package.json +15 -19
  20. package/twin-assets/discord/fidelity.json +113 -0
  21. package/twin-assets/discord/tools.json +1953 -0
  22. package/twin-assets/github/fidelity.json +13 -0
  23. package/twin-assets/github/tools.json +21818 -0
  24. package/twin-assets/google-workspace/fidelity.json +19 -0
  25. package/twin-assets/google-workspace/tools.json +10191 -0
  26. package/twin-assets/jira/fidelity.json +40 -0
  27. package/twin-assets/jira/tools.json +17387 -0
  28. package/twin-assets/linear/fidelity.json +18 -0
  29. package/twin-assets/linear/tools.json +6496 -0
  30. package/twin-assets/ramp/fidelity.json +22 -0
  31. package/twin-assets/ramp/tools.json +2610 -0
  32. package/twin-assets/slack/fidelity.json +20 -0
  33. package/twin-assets/slack/tools.json +7301 -0
  34. package/twin-assets/stripe/fidelity.json +22 -0
  35. package/twin-assets/stripe/tools.json +15284 -0
  36. package/twin-assets/supabase/fidelity.json +13 -0
  37. package/twin-assets/supabase/tools.json +2973 -0
  38. package/dist/vitest.d.ts +0 -1
  39. 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 --save-dev archal
29
+ npm install -g archal
9
30
  ```
10
31
 
11
32
  Then authenticate:
12
33
 
13
34
  ```bash
14
- npx archal login
35
+ archal login
15
36
  ```
16
37
 
17
- ## Vitest Integration (primary use case)
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
- Test your code against hosted GitHub / Stripe / Slack / Jira / Supabase / Google Workspace twins without hitting real APIs. Your SDKs work unchanged — `archal/vitest` transparently routes their traffic to the twin.
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 — single `vitest.config.ts`
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 { archalVitestConfig } from 'archal/vitest';
133
+ import { withArchal } from 'archal/vitest';
26
134
 
27
135
  export default defineConfig({
28
- test: archalVitestConfig({
29
- services: {
30
- stripe: { mode: 'route', seed: 'small-business' },
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
- Test your webhook handlers against the twins' queued events. The hosted twin
81
- runs in AWS ECS so it can't POST to your localhost instead, your test pulls
82
- queued deliveries with `waitForArchalWebhook()` and invokes your handler
83
- directly with the exact payload the twin would have sent.
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
- **Important**: register the webhook endpoint on the twin *before* firing the
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 — see Slack caveat below |
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 | ❌ | Supabase webhooks are database-triggered; test against real Postgres or `supabase_functions.pg_net` directly |
139
- | Google Workspace | ❌ | No webhook API — uses GCP Pub/Sub push notifications |
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 automatically routed to its own per-worker state on the twin — parallel tests across workers don't see each other's writes. This is transparent: the integration reads `VITEST_WORKER_ID` in each worker process and tags every outbound SDK request with an `X-Archal-Worker-Id` header. The twin maintains a separate `StateEngine` per worker id, seeded from the baseline on first request.
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
- ```ts
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
- **Currently isolation-enabled twins**: Stripe, GitHub, Slack, Jira, Linear.
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
- **Twins without isolation** (Supabase, Google Workspace, Telegram, Ramp, Browser) fall back to shared state — the worker header is sent but the twin ignores it. Writes from all workers land in the same baseline state. If your tests depend on global assertions against these twins, use `testIsolation: 'serial'` (see below).
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
- #### Forcing serial tests
251
+ In priority order:
173
252
 
174
- If your test suite needs full serialization (for example, it asserts on global counts across tests, or you're hitting one of the non-isolated twins), opt in to `testIsolation: 'serial'`:
253
+ 1. `ARCHAL_TOKEN` env var
254
+ 2. Stored credentials from `archal login` in `~/.archal/credentials.json`
175
255
 
176
- ```ts
177
- archalVitestConfig({
178
- services: { stripe: { mode: 'route' } },
179
- testIsolation: 'serial', // maxWorkers: 1, fileParallelism: false
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 `vitest run`, session provisioning takes about 30 seconds (ECS Fargate cold start). The integration prints a progress line every few seconds so the wait is visible:
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 twins... 10s
270
+ [archal] provisioning stripe twin... 10s
190
271
  ...
191
272
  ```
192
273
 
193
- Subsequent runs with the same configuration reuse the warm session (~2 seconds).
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/docs
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
- require("@archal/cli");
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
  }