@cursor/july 0.1.39 → 0.1.41
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/AGENTS.md +4 -3
- package/dist/bin/agent-serve.js +28 -9
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +18 -8
- package/dist/channels/slack/attachments.d.ts +82 -0
- package/dist/channels/slack/attachments.d.ts.map +1 -0
- package/dist/channels/slack/attachments.js +520 -0
- package/dist/channels/slack/cursor-account.d.ts +7 -1
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +2 -2
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +26 -17
- package/dist/channels/slack/dispatch.d.ts +4 -3
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +84 -21
- package/dist/channels/slack/inbound.d.ts +6 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +48 -2
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +1 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +16 -4
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +1 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +7 -4
- package/dist/channels/slack/types.d.ts +49 -1
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +6 -6
- package/dist/docs/assets/{ab.md.6cLOW7--.js → ab.md.hdxsvX5M.js} +2 -2
- package/dist/docs/assets/{app.BQ8Hihdf.js → app.mIw24pb1.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.txrcGU2B.js → building-with-agents.md.PeZaZA1P.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BA7V8dEJ.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BBCr8Yuy.js → VPLocalSearchBox.hOzpPwrG.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CK_NiGC-.js → theme.BtFhUYmh.js} +2 -2
- package/dist/docs/assets/{deployment.md.CuK5SNjN.js → deployment.md.BHVjVqRa.js} +4 -4
- package/dist/docs/assets/{deployment.md.CuK5SNjN.lean.js → deployment.md.BHVjVqRa.lean.js} +1 -1
- package/dist/docs/assets/{evals.md.BQXI3rXy.js → evals.md.qeoGgPw0.js} +3 -3
- package/dist/docs/assets/example-agents_index.md.xmJ87d_3.js +2 -0
- package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.js → guides_webhooks.md.DB-r_er9.js} +47 -4
- package/dist/docs/assets/{guides_webhooks.md.BERuBSJW.lean.js → guides_webhooks.md.DB-r_er9.lean.js} +1 -1
- package/dist/docs/assets/index.md.BKpbkCa6.js +24 -0
- package/dist/docs/assets/{index.md.CmhptOmN.lean.js → index.md.BKpbkCa6.lean.js} +1 -1
- package/dist/docs/assets/{quickstart.md.C_b6ESpD.js → quickstart.md.rIbfahJM.js} +4 -4
- package/dist/docs/assets/{reference_cli.md.Byvrg8eu.js → reference_cli.md.DqEqQpGn.js} +5 -5
- package/dist/docs/assets/{reference_cli.md.Byvrg8eu.lean.js → reference_cli.md.DqEqQpGn.lean.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.js → reference_hooks.md.BHeG-vjK.js} +2 -2
- package/dist/docs/assets/{reference_hooks.md.BGDw4VLm.lean.js → reference_hooks.md.BHeG-vjK.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.mQDtIULc.js → storage.md.DcGSnIxX.js} +10 -4
- package/dist/docs/assets/{storage.md.mQDtIULc.lean.js → storage.md.DcGSnIxX.lean.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.CkgwmVI0.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.B5RVX_tL.lean.js → troubleshooting.md.CkgwmVI0.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +5 -5
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +6 -6
- package/dist/docs/evals.html +7 -7
- package/dist/docs/example-agents/approval-buddy.html +3 -3
- package/dist/docs/example-agents/benny.html +3 -3
- package/dist/docs/example-agents/bugbot.html +3 -3
- package/dist/docs/example-agents/codebase-wiki.html +3 -3
- package/dist/docs/example-agents/codeowners-review.html +3 -3
- package/dist/docs/example-agents/concierge.html +3 -3
- package/dist/docs/example-agents/fsd.html +3 -3
- package/dist/docs/example-agents/index.html +5 -5
- package/dist/docs/example-agents/knowledge-base.html +3 -3
- package/dist/docs/example-agents/oncall.html +3 -3
- package/dist/docs/example-agents/security-reviewer.html +3 -3
- package/dist/docs/example-agents/slack-agent.html +3 -3
- package/dist/docs/example-agents/weather-agent.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +3 -3
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +49 -6
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +7 -7
- package/dist/docs/quickstart.html +8 -8
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/artifacts.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +8 -8
- package/dist/docs/reference/connections.html +3 -3
- package/dist/docs/reference/hooks.html +5 -5
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/prompt.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +14 -8
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +22 -2
- package/dist/internal/cli-deploy.d.ts +6 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +14 -4
- package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
- package/dist/internal/cli-mcp-oauth.js +3 -1
- package/dist/internal/cli-mcp.js +4 -4
- package/dist/internal/cursor-event-relay.d.ts +45 -0
- package/dist/internal/cursor-event-relay.d.ts.map +1 -1
- package/dist/internal/cursor-event-relay.js +96 -2
- package/dist/internal/deploy-client.js +1 -1
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +35 -7
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +3 -1
- package/dist/internal/durable-session-store.d.ts +48 -0
- package/dist/internal/durable-session-store.d.ts.map +1 -0
- package/dist/internal/durable-session-store.js +86 -0
- package/dist/internal/hosting.d.ts +1 -1
- package/dist/internal/hosting.js +2 -2
- package/dist/internal/init-project.d.ts +34 -0
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +121 -2
- package/dist/internal/ledger-serving.d.ts +101 -0
- package/dist/internal/ledger-serving.d.ts.map +1 -0
- package/dist/internal/ledger-serving.js +174 -0
- package/dist/internal/listen-port.d.ts +22 -0
- package/dist/internal/listen-port.d.ts.map +1 -0
- package/dist/internal/listen-port.js +77 -0
- package/dist/internal/mcp-oauth.d.ts +12 -1
- package/dist/internal/mcp-oauth.d.ts.map +1 -1
- package/dist/internal/mcp-oauth.js +25 -3
- package/dist/internal/playground/static.d.ts +21 -4
- package/dist/internal/playground/static.d.ts.map +1 -1
- package/dist/internal/playground/static.js +82 -18
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +10 -1
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +67 -49
- package/dist/internal/session-engine.d.ts +57 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +117 -28
- package/dist/internal/slack-provision-client.js +1 -1
- package/dist/internal/workspace.d.ts +6 -2
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +10 -2
- package/dist/kv/memory-kv.d.ts +23 -0
- package/dist/kv/memory-kv.d.ts.map +1 -0
- package/dist/kv/memory-kv.js +103 -0
- package/dist/kv.d.ts +22 -0
- package/dist/kv.d.ts.map +1 -0
- package/dist/kv.js +20 -0
- package/dist/ledger/session-ledger.d.ts +204 -0
- package/dist/ledger/session-ledger.d.ts.map +1 -0
- package/dist/ledger/session-ledger.js +382 -0
- package/dist/ledger.d.ts +11 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +9 -0
- package/dist/playground/assets/index-B3HBneZZ.js +85 -0
- package/dist/playground/assets/index-Bqk9nplh.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +25 -3
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +50 -2
- package/dist/storage-backends/file-kv.d.ts +5 -2
- package/dist/storage-backends/file-kv.d.ts.map +1 -1
- package/dist/storage-backends/file-kv.js +107 -7
- package/dist/storage.d.ts +60 -5
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +28 -4
- package/dist/types.d.ts +123 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +14 -0
- package/docs/README.md +10 -7
- package/docs/ab.md +2 -2
- package/docs/building-with-agents.md +1 -1
- package/docs/deployment.md +34 -11
- package/docs/evals.md +3 -3
- package/docs/example-agents/index.md +1 -1
- package/docs/guides/webhooks.md +87 -0
- package/docs/quickstart.md +7 -8
- package/docs/reference/cli.md +15 -6
- package/docs/reference/hooks.md +8 -2
- package/docs/storage.md +67 -7
- package/docs/troubleshooting.md +10 -2
- package/package.json +20 -7
- package/skills/create-agent/SKILL.md +1 -1
- package/src/bin/agent-serve.ts +27 -11
- package/src/channels/slack/api.ts +19 -14
- package/src/channels/slack/attachments.ts +635 -0
- package/src/channels/slack/cursor-account.ts +8 -0
- package/src/channels/slack/defaults.ts +34 -18
- package/src/channels/slack/dispatch.ts +121 -6
- package/src/channels/slack/inbound.ts +60 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/live-delivery.ts +17 -3
- package/src/channels/slack/manifest.ts +1 -0
- package/src/channels/slack/slack-channel.ts +7 -0
- package/src/channels/slack/types.ts +47 -1
- package/src/index.ts +9 -0
- package/src/internal/cli-ax.ts +25 -1
- package/src/internal/cli-deploy.ts +22 -4
- package/src/internal/cli-mcp-oauth.ts +3 -1
- package/src/internal/cli-mcp.ts +4 -4
- package/src/internal/cursor-event-relay.ts +168 -0
- package/src/internal/deploy-client.ts +1 -1
- package/src/internal/discovery.ts +42 -5
- package/src/internal/distribution.ts +3 -1
- package/src/internal/durable-session-store.ts +95 -0
- package/src/internal/hosting.ts +2 -2
- package/src/internal/init-project.ts +151 -2
- package/src/internal/ledger-serving.ts +240 -0
- package/src/internal/listen-port.ts +85 -0
- package/src/internal/mcp-oauth.ts +29 -4
- package/src/internal/playground/static.ts +111 -20
- package/src/internal/sdk-runner.ts +11 -1
- package/src/internal/server.ts +76 -62
- package/src/internal/session-engine.ts +192 -16
- package/src/internal/slack-provision-client.ts +1 -1
- package/src/internal/workspace.ts +14 -3
- package/src/kv/memory-kv.ts +99 -0
- package/src/kv.ts +27 -0
- package/src/ledger/session-ledger.ts +535 -0
- package/src/ledger.ts +29 -0
- package/src/storage-backends/cursor-hosted.ts +108 -3
- package/src/storage-backends/file-kv.ts +128 -12
- package/src/storage.ts +90 -6
- package/src/types.ts +130 -4
- package/dist/channels/slack/post-update-delivery.d.ts +0 -85
- package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.B-VTH4As.js +0 -1
- package/dist/docs/assets/example-agents_index.md.DgGBwckv.js +0 -2
- package/dist/docs/assets/index.md.CmhptOmN.js +0 -24
- package/dist/docs/assets/troubleshooting.md.B5RVX_tL.js +0 -1
- package/dist/internal/json-dir-store.d.ts +0 -32
- package/dist/internal/json-dir-store.d.ts.map +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/multi-tenant.d.ts +0 -80
- package/dist/multi-tenant.d.ts.map +0 -1
- package/dist/multi-tenant.js +0 -69
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/index-BRhBbnd4.css +0 -1
- package/dist/playground/assets/index-_2WKw9a-.js +0 -85
- package/dist/storage-backends/postgres-kv.d.ts +0 -82
- package/dist/storage-backends/postgres-kv.d.ts.map +0 -1
- package/dist/storage-backends/postgres-kv.js +0 -185
- package/src/storage-backends/postgres-kv.ts +0 -253
- /package/dist/docs/assets/{ab.md.6cLOW7--.lean.js → ab.md.hdxsvX5M.lean.js} +0 -0
- /package/dist/docs/assets/{building-with-agents.md.txrcGU2B.lean.js → building-with-agents.md.PeZaZA1P.lean.js} +0 -0
- /package/dist/docs/assets/{evals.md.BQXI3rXy.lean.js → evals.md.qeoGgPw0.lean.js} +0 -0
- /package/dist/docs/assets/{example-agents_index.md.DgGBwckv.lean.js → example-agents_index.md.xmJ87d_3.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.C_b6ESpD.lean.js → quickstart.md.rIbfahJM.lean.js} +0 -0
package/docs/guides/webhooks.md
CHANGED
|
@@ -177,6 +177,18 @@ swaps the default for `bearerAuth` on every channel that doesn't author
|
|
|
177
177
|
its own chain, and `--allow-anonymous` swaps it for `allowAll()`
|
|
178
178
|
(trusted networks only). Authored `auth` arrays always win over both.
|
|
179
179
|
|
|
180
|
+
## Hosted aliases need an alias-token relay
|
|
181
|
+
|
|
182
|
+
Cursor-managed deployments expose a stable alias URL. External callers
|
|
183
|
+
must send `X-Agent-Alias-Token` on every request to that URL. Channel
|
|
184
|
+
auth still runs after the alias gate.
|
|
185
|
+
|
|
186
|
+
Webhook providers that cannot attach custom headers cannot POST
|
|
187
|
+
straight at a managed alias. Put a relay (or other authenticating
|
|
188
|
+
intermediary) in front, use a Cursor-managed ingress path that does not
|
|
189
|
+
use the public alias (for example Cursor Slack / GitHub event relay),
|
|
190
|
+
or self-host. See [Deployment](../deployment.md#use-the-hosted-agent).
|
|
191
|
+
|
|
180
192
|
## Example: Linear as the control plane
|
|
181
193
|
|
|
182
194
|
Everything above composes into a working ticket-driven agent. This
|
|
@@ -346,6 +358,81 @@ See [MCP connections](../reference/connections.md) for the direct
|
|
|
346
358
|
`https://mcp.linear.app/mcp` form when the host isn't signed in to
|
|
347
359
|
Cursor.
|
|
348
360
|
|
|
361
|
+
### Production Linear agents: expiring OAuth tokens
|
|
362
|
+
|
|
363
|
+
A plain API key fits a personal integration. A production Linear agent
|
|
364
|
+
is an OAuth application: installing it in a workspace mints an access
|
|
365
|
+
token with an expiry plus a refresh token. The serve host can be
|
|
366
|
+
replaced at any time, so the pair can't live in process memory.
|
|
367
|
+
Persist it in [`host.kv`](../storage.md#author-kv-ctx-host-kv) instead.
|
|
368
|
+
Route handlers receive `host` in their args, and event handlers get the
|
|
369
|
+
same services on `ctx`.
|
|
370
|
+
|
|
371
|
+
Two prerequisites:
|
|
372
|
+
|
|
373
|
+
- Keep the OAuth client id and client secret in
|
|
374
|
+
[deployment secrets](../deployment.md). They're static, so
|
|
375
|
+
deploy-time env vars fit them.
|
|
376
|
+
- Back kv with durable storage. On Cursor-managed hosting, use
|
|
377
|
+
`cursorHostedStorage` in `agent/storage.ts`
|
|
378
|
+
([Storage](../storage.md)). Without it, kv falls back to local disk
|
|
379
|
+
and a host replacement drops the tokens.
|
|
380
|
+
|
|
381
|
+
Save the pair when the install flow completes, then refresh on demand:
|
|
382
|
+
|
|
383
|
+
```ts
|
|
384
|
+
import type { HostKvApi } from "@cursor/july/kv";
|
|
385
|
+
|
|
386
|
+
interface LinearTokens {
|
|
387
|
+
accessToken: string;
|
|
388
|
+
refreshToken: string;
|
|
389
|
+
expiresAtMs: number;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const TOKENS_KEY = "linear/oauth-tokens";
|
|
393
|
+
|
|
394
|
+
export async function linearAccessToken(kv: HostKvApi): Promise<string> {
|
|
395
|
+
const tokens = (await kv.get(TOKENS_KEY)) as LinearTokens | undefined;
|
|
396
|
+
if (tokens === undefined) {
|
|
397
|
+
throw new Error("No Linear tokens stored. Complete the install flow first.");
|
|
398
|
+
}
|
|
399
|
+
if (Date.now() < tokens.expiresAtMs - 60_000) {
|
|
400
|
+
return tokens.accessToken;
|
|
401
|
+
}
|
|
402
|
+
const response = await fetch("https://api.linear.app/oauth/token", {
|
|
403
|
+
method: "POST",
|
|
404
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
405
|
+
body: new URLSearchParams({
|
|
406
|
+
grant_type: "refresh_token",
|
|
407
|
+
refresh_token: tokens.refreshToken,
|
|
408
|
+
client_id: process.env.LINEAR_CLIENT_ID ?? "",
|
|
409
|
+
client_secret: process.env.LINEAR_CLIENT_SECRET ?? "",
|
|
410
|
+
}),
|
|
411
|
+
});
|
|
412
|
+
if (!response.ok) {
|
|
413
|
+
throw new Error(`Linear token refresh failed: ${response.status}`);
|
|
414
|
+
}
|
|
415
|
+
const next = (await response.json()) as {
|
|
416
|
+
access_token: string;
|
|
417
|
+
refresh_token?: string;
|
|
418
|
+
expires_in: number;
|
|
419
|
+
};
|
|
420
|
+
const rotated: LinearTokens = {
|
|
421
|
+
accessToken: next.access_token,
|
|
422
|
+
refreshToken: next.refresh_token ?? tokens.refreshToken,
|
|
423
|
+
expiresAtMs: Date.now() + next.expires_in * 1000,
|
|
424
|
+
};
|
|
425
|
+
await kv.put(TOKENS_KEY, rotated);
|
|
426
|
+
return rotated.accessToken;
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Then authorize GraphQL calls with `Bearer ${await
|
|
431
|
+
linearAccessToken(host.kv)}` in place of the static `apiKey` above.
|
|
432
|
+
Writes to `host.kv` await the durable sink and propagate errors, so a
|
|
433
|
+
failed save surfaces instead of silently losing the rotated refresh
|
|
434
|
+
token.
|
|
435
|
+
|
|
349
436
|
To test without a public URL, save a payload from the webhook's
|
|
350
437
|
delivery log (or the sample in
|
|
351
438
|
[Linear's webhook docs](https://linear.app/developers/webhooks)) under
|
package/docs/quickstart.md
CHANGED
|
@@ -21,9 +21,8 @@ You need:
|
|
|
21
21
|
- Node 22.13 or newer. Bun isn't supported.
|
|
22
22
|
- The `agent-sdk` CLI. `npx @cursor/july init ./pr-approver` bootstraps
|
|
23
23
|
it with no prior install: `init` scaffolds the project, runs
|
|
24
|
-
`npm install`,
|
|
25
|
-
|
|
26
|
-
[Run the CLI](./README.md#run-the-cli) for other setups, such as a
|
|
24
|
+
`npm install`, links `agent-sdk` onto your PATH, and offers a Cursor
|
|
25
|
+
sign-in. See [Run the CLI](/#run-the-cli) for other setups, such as a
|
|
27
26
|
monorepo source checkout.
|
|
28
27
|
- A Cursor credential for model turns. Sign in once:
|
|
29
28
|
|
|
@@ -44,9 +43,9 @@ Want a working agent before the full tutorial? Four commands get you
|
|
|
44
43
|
there:
|
|
45
44
|
|
|
46
45
|
```bash
|
|
47
|
-
|
|
46
|
+
npx @cursor/july init ./pr-approver # scaffold + npm install + PATH link + sign-in offer
|
|
48
47
|
cd pr-approver
|
|
49
|
-
agent-sdk dev
|
|
48
|
+
agent-sdk dev # serve, and print the playground URL
|
|
50
49
|
```
|
|
51
50
|
|
|
52
51
|
Open the playground URL and chat with the scaffold. Then, in a second
|
|
@@ -79,7 +78,7 @@ full guided workflow.
|
|
|
79
78
|
Start with the built-in scaffold:
|
|
80
79
|
|
|
81
80
|
```bash
|
|
82
|
-
|
|
81
|
+
npx @cursor/july init ./pr-approver
|
|
83
82
|
cd pr-approver
|
|
84
83
|
agent-sdk dev
|
|
85
84
|
```
|
|
@@ -299,7 +298,7 @@ Call the tool directly first, on a real merged pull request:
|
|
|
299
298
|
|
|
300
299
|
```bash
|
|
301
300
|
agent-sdk call inspect_pr --dir . \
|
|
302
|
-
--input '{"prUrl":"https://github.com/
|
|
301
|
+
--input '{"prUrl":"https://github.com/facebook/react/pull/35623"}'
|
|
303
302
|
```
|
|
304
303
|
|
|
305
304
|
`call` validates the input and runs `execute` without a model turn.
|
|
@@ -322,7 +321,7 @@ Now call it on the PR that added `experimental_useEvent` to React:
|
|
|
322
321
|
|
|
323
322
|
```bash
|
|
324
323
|
agent-sdk call inspect_pr --dir . \
|
|
325
|
-
--input '{"prUrl":"https://github.com/
|
|
324
|
+
--input '{"prUrl":"https://github.com/facebook/react/pull/25229"}'
|
|
326
325
|
```
|
|
327
326
|
|
|
328
327
|
The rating flips to `large` and the patches disappear from the result.
|
package/docs/reference/cli.md
CHANGED
|
@@ -11,7 +11,7 @@ page use `agent-sdk`. Run the CLI with Node 22.13 or newer. Don't run it
|
|
|
11
11
|
with Bun; Bun corrupts tool-result streams from the Cursor SDK.
|
|
12
12
|
|
|
13
13
|
The current release still uses `.agent-serve` for on-disk state. See the
|
|
14
|
-
[rename table](
|
|
14
|
+
[rename table](/#run-the-cli) for identifiers still moving to
|
|
15
15
|
agent-sdk names.
|
|
16
16
|
|
|
17
17
|
`agent-sdk help` prints the built-in summary. The Slack and GitHub packs
|
|
@@ -111,7 +111,7 @@ Unless `--state-root` is set, each mount uses
|
|
|
111
111
|
|
|
112
112
|
| Flag | Meaning |
|
|
113
113
|
| --- | --- |
|
|
114
|
-
| `--port` | Listen on this port. `0` selects an available port. The default is `3000`. |
|
|
114
|
+
| `--port` | Listen on this port. `0` selects an available port. The default is `3000`. When the default is taken, serve tries the next free port and prints a notice; an explicit `--port` fails with a next-port hint instead. |
|
|
115
115
|
| `--host` | Bind this host. The default is loopback-only `127.0.0.1`. |
|
|
116
116
|
| `--dev` | Disable automatic schedule and reminder firing, admit unsigned loopback GitHub deliveries, widen playground session access on loopback, and start Vite HMR when available. |
|
|
117
117
|
| `--mode` | Use `multi` for slugged routes and an index, or `single` for one agent at the unslugged `/v1/*`. The default is `multi`. |
|
|
@@ -733,14 +733,23 @@ See the [Host MCP OAuth guide](../guides/mcp-oauth.md).
|
|
|
733
733
|
`secrets` manages environment secrets for a deployment.
|
|
734
734
|
|
|
735
735
|
```bash
|
|
736
|
-
agent-sdk secrets set <slug> NAME[
|
|
736
|
+
agent-sdk secrets set <slug> NAME [NAME2 ...] [--team <id>] [--json]
|
|
737
737
|
agent-sdk secrets list <slug> [--team <id>] [--json]
|
|
738
738
|
agent-sdk secrets unset <slug> NAME [--team <id>] [--json]
|
|
739
739
|
```
|
|
740
740
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
741
|
+
Pass names only. On a TTY, `secrets set` prompts for each value with
|
|
742
|
+
hidden input (nothing echoes). When stdin is piped, provide one line per
|
|
743
|
+
name. Values never print on stdout.
|
|
744
|
+
|
|
745
|
+
Do not put values on the command line. `NAME=VALUE` in argv shows up in
|
|
746
|
+
shell history and in agent-captured terminals. The CLI refuses that form
|
|
747
|
+
unless you pass `--from-argv` (still warns). Prefer a file redirect when
|
|
748
|
+
a human is not at the prompt:
|
|
749
|
+
|
|
750
|
+
```bash
|
|
751
|
+
agent-sdk secrets set weather-agent WEATHER_API_KEY < ./weather-api-key.txt
|
|
752
|
+
```
|
|
744
753
|
|
|
745
754
|
Secret names use `UPPER_SNAKE_CASE`, start with a letter, and contain at
|
|
746
755
|
most 64 characters. Names beginning with `CURSOR_` are reserved. Values
|
package/docs/reference/hooks.md
CHANGED
|
@@ -9,8 +9,14 @@ A hook is an observe-only subscriber to the session event stream. Hooks
|
|
|
9
9
|
run after each event is recorded and fanned out (file persistence flushes
|
|
10
10
|
in the background). That makes them the home for audit logging, metrics,
|
|
11
11
|
mirroring transcripts into your own store, and maintaining derived state.
|
|
12
|
-
Handler errors are logged and never fatal. A hook can't modify events
|
|
13
|
-
block a turn.
|
|
12
|
+
Handler errors are logged and never fatal. A hook can't modify events,
|
|
13
|
+
inject context into the next turn, or block a turn.
|
|
14
|
+
|
|
15
|
+
For deterministic context composition before the model runs, use the
|
|
16
|
+
host path that already owns the wake: channel handlers (fetch, `callTool`,
|
|
17
|
+
`workspaceFiles`, and the message you pass to `send`), plus
|
|
18
|
+
`instructions.md`, skills, and `sandbox/workspace/` seed files. Hooks
|
|
19
|
+
observe what happened; they do not assemble the prompt.
|
|
14
20
|
|
|
15
21
|
Author `agent/hooks/<name>.ts` with `defineHook` from
|
|
16
22
|
`@cursor/july/hooks`:
|
package/docs/storage.md
CHANGED
|
@@ -22,7 +22,10 @@ for one machine; it does not survive replacing the host.
|
|
|
22
22
|
|
|
23
23
|
To keep the same framework storage across hosts, plug in a key-value
|
|
24
24
|
backend with `agent/storage.ts`. You provide `put` / `get` / `delete` /
|
|
25
|
-
`list
|
|
25
|
+
`list`, plus the `cas` group when the deployment uses coordination
|
|
26
|
+
features (conditional writes — see
|
|
27
|
+
[Conditional writes](#conditional-writes-the-cas-group)). The Agent SDK
|
|
28
|
+
does the rest.
|
|
26
29
|
|
|
27
30
|
```ts
|
|
28
31
|
// agent/storage.ts
|
|
@@ -33,26 +36,33 @@ export default defineStorage({
|
|
|
33
36
|
get: (key) => db.get(key),
|
|
34
37
|
delete: (key) => db.delete(key),
|
|
35
38
|
list: (prefix) => db.listByPrefix(prefix), // [{ key, value }], key order
|
|
39
|
+
cas: {
|
|
40
|
+
getWithVersion: (key) => db.getRow(key), // { value, version }
|
|
41
|
+
putIfAbsent: (key, value) => db.insertIfAbsent(key, value),
|
|
42
|
+
putIfVersion: (key, value, expected) => db.casUpdate(key, value, expected),
|
|
43
|
+
listKeys: (prefix) => db.listKeysByPrefix(prefix),
|
|
44
|
+
},
|
|
36
45
|
});
|
|
37
46
|
```
|
|
38
47
|
|
|
39
48
|
> [!NOTE]
|
|
40
49
|
> Import paths here use `@cursor/july/storage`. On projects still
|
|
41
50
|
> using `@anysphere/agent-serve`, swap the import. See
|
|
42
|
-
> [Run the CLI](
|
|
51
|
+
> [Run the CLI](/#run-the-cli) for the full rename table.
|
|
43
52
|
|
|
44
53
|
## Which fields to provide
|
|
45
54
|
|
|
46
55
|
| Field | Required | Role |
|
|
47
56
|
| --- | --- | --- |
|
|
48
57
|
| `put` | Yes | Write or update a value |
|
|
58
|
+
| `cas` | For coordination | Conditional writes; see [Conditional writes](#conditional-writes-the-cas-group) |
|
|
49
59
|
| `get` | For restore | Look up one key |
|
|
50
60
|
| `list` | For restore | Return entries under a prefix, in key order |
|
|
51
61
|
| `delete` | For cleanup | Remove a key |
|
|
52
62
|
| `name` | No | Label surfaced on `GET /v1/info` diagnostics |
|
|
53
63
|
| `policy` | No | Timing knobs; see [Policy](#policy) |
|
|
54
|
-
| `evals` | No | Dedicated eval-runs table; see [Eval and A/B tables](#eval-and-
|
|
55
|
-
| `abs` | No | Dedicated A/B metrics table; see [Eval and A/B tables](#eval-and-
|
|
64
|
+
| `evals` | No | Dedicated eval-runs table; see [Eval and A/B tables](#eval-and-a-b-tables) |
|
|
65
|
+
| `abs` | No | Dedicated A/B metrics table; see [Eval and A/B tables](#eval-and-a-b-tables) |
|
|
56
66
|
|
|
57
67
|
A throwing `put` is logged and dropped. It never fails a turn. When
|
|
58
68
|
resolving a missing continuation token, a throwing `get` fails the
|
|
@@ -142,8 +152,6 @@ survive replacing the host. For Cursor-managed hosting, prefer
|
|
|
142
152
|
`@cursor/july/storage/cursor-hosted` so sessions and author KV share the
|
|
143
153
|
platform Bugbot tables through a control-plane HTTP proxy (authenticated
|
|
144
154
|
as the deployment pod credential — engines never receive a database URL).
|
|
145
|
-
For self-hosted Postgres you own, use `@cursor/july/storage/postgres-kv`
|
|
146
|
-
and supply `BUGBOTDB_URL` / `AGENT_SERVE_DEPLOYMENT_ID` yourself.
|
|
147
155
|
|
|
148
156
|
```ts
|
|
149
157
|
// agent/storage.ts — Cursor-managed hosting
|
|
@@ -161,4 +169,56 @@ Built-in helpers:
|
|
|
161
169
|
| --- | --- |
|
|
162
170
|
| `@cursor/july/storage/file-kv` | File-per-key under `.agent-serve/kv` |
|
|
163
171
|
| `@cursor/july/storage/cursor-hosted` | Platform Bugbot `agent_serve_*` via control-plane proxy |
|
|
164
|
-
|
|
172
|
+
|
|
173
|
+
## Bring your own backend
|
|
174
|
+
|
|
175
|
+
There is no built-in Postgres backend on purpose. Cursor's internal
|
|
176
|
+
`agent_serve_*` tables are owned by the backend and reachable only
|
|
177
|
+
through the hosted proxy, and this doc does not prescribe a schema —
|
|
178
|
+
what you back the KV with is your call. Any durable store works:
|
|
179
|
+
|
|
180
|
+
- **Local disk** — the built-in `fileKv` (single process only).
|
|
181
|
+
- **Object storage (S3-class)** — one object per key; conditional
|
|
182
|
+
writes map directly onto the contract (`putIfAbsent` = put with
|
|
183
|
+
`If-None-Match: *`, `putIfVersion` = put with `If-Match: <etag>`,
|
|
184
|
+
the ETag is the version token, `listKeys` is a prefix listing).
|
|
185
|
+
- **Redis, DynamoDB, a SQL table, …** — anything that can do an
|
|
186
|
+
atomic compare-and-set and a prefix listing.
|
|
187
|
+
|
|
188
|
+
Implement the `StorageConfig` methods (and the `cas` group when the
|
|
189
|
+
deployment uses coordination features) against that store. The
|
|
190
|
+
contract, defined at `@cursor/july/kv`: version tokens are opaque
|
|
191
|
+
strings that change on every successful write — including plain
|
|
192
|
+
`put`, so a stale token fences instead of clobbering; conditional
|
|
193
|
+
writes are atomic; `listKeys` returns every key under the prefix.
|
|
194
|
+
`@cursor/july/kv/memory` is a complete reference implementation to
|
|
195
|
+
compare behavior against.
|
|
196
|
+
|
|
197
|
+
## Conditional writes (the `cas` group)
|
|
198
|
+
|
|
199
|
+
The `cas` group is compare-and-swap over the same keyspace:
|
|
200
|
+
`getWithVersion` / `putIfAbsent` / `putIfVersion` / `listKeys`, defined
|
|
201
|
+
backend-agnostically at `@cursor/july/kv`. Plain storage works without
|
|
202
|
+
it, so an existing backend keeps working across a platform upgrade.
|
|
203
|
+
Coordination features require it: they fail at startup, with a message
|
|
204
|
+
naming this group, when the backend lacks it. `defineStorage` rejects a
|
|
205
|
+
partial group — implement all four methods or none. Version tokens are
|
|
206
|
+
opaque strings that must change on every write (a counter column, a row
|
|
207
|
+
version, a content hash). The built-in backends both include it: `fileKv`
|
|
208
|
+
uses content-hash tokens (single-process correctness) and
|
|
209
|
+
`cursorHostedStorage` the control-plane proxy (a `version` counter on the
|
|
210
|
+
server).
|
|
211
|
+
|
|
212
|
+
## Durable sessions (the session ledger)
|
|
213
|
+
|
|
214
|
+
Conditional writes are the substrate for the session ledger, which
|
|
215
|
+
ships behind `defineAgent({ serving: "ledger" })`: session identity,
|
|
216
|
+
one-writer-per-session leases with generation fencing, and a fenced
|
|
217
|
+
commit sequence, coordinated through the agent's storage backend by
|
|
218
|
+
default (its `cas` group) or an explicit `durableSessionStore`
|
|
219
|
+
override. The ledger has **no durable inbox** — an event arriving while
|
|
220
|
+
a session's lease is held waits in-process on the delivering pod, so
|
|
221
|
+
crash durability matches resident serving; what ledger mode adds is
|
|
222
|
+
cross-pod mutual exclusion, zombie fencing, and the committed head
|
|
223
|
+
sequence. A backend that implements `cas` needs no storage migration to
|
|
224
|
+
adopt it.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -13,7 +13,7 @@ Start with four checks, in order:
|
|
|
13
13
|
4. The session event stream (trace)
|
|
14
14
|
|
|
15
15
|
Match your symptom below. Keep the commands as `agent-sdk`; see
|
|
16
|
-
[Run the CLI](
|
|
16
|
+
[Run the CLI](/#run-the-cli) if you still need an alias.
|
|
17
17
|
|
|
18
18
|
## What if serve or the playground looks wrong?
|
|
19
19
|
|
|
@@ -23,7 +23,7 @@ Match your symptom below. Keep the commands as `agent-sdk`; see
|
|
|
23
23
|
| Playground is blank or says there are no agents | The UI needs a running `serve` process. Building the playground assets alone is not enough. |
|
|
24
24
|
| Edits to the playground don't show up | Use `serve --dev` and open the printed playground HMR URL (often port `5273`), not only the static `:3000` URL. |
|
|
25
25
|
| Sessions exist on disk but the playground list is empty | The list shows sessions for the authenticated caller. In `--dev` on loopback the list is wider. Otherwise open `/<slug>/playground?sessionId=ses_…` or inspect `sessions/` under your state root. |
|
|
26
|
-
| Port 3000 or 5273 is already in use |
|
|
26
|
+
| Port 3000 or 5273 is already in use | For the default serve port, the CLI tries the next free port and prints a notice. Pass `--port` to pick one, or `--port 0` for any free port. Stop leftover Vite or webhook-forwarder processes if you need the original port. |
|
|
27
27
|
|
|
28
28
|
## What if a model turn goes wrong?
|
|
29
29
|
|
|
@@ -75,6 +75,14 @@ Match your symptom below. Keep the commands as `agent-sdk`; see
|
|
|
75
75
|
See [Host MCP OAuth](./guides/mcp-oauth.md) and
|
|
76
76
|
[`skills/mcp-auth/SKILL.md`](../skills/mcp-auth/SKILL.md).
|
|
77
77
|
|
|
78
|
+
## What if a secret showed up in a terminal transcript?
|
|
79
|
+
|
|
80
|
+
| What you see | What to do |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `secrets set … NAME=VALUE` in an agent-captured terminal or shell history | Rotate the secret at the provider. Set it again with names only: `agent-sdk secrets set <slug> NAME` (hidden prompt) or pipe/redirect the value. `NAME=VALUE` requires `--from-argv` and still leaks into argv. |
|
|
83
|
+
| Alias token printed during first deploy or `rotate-token` | Treat it as exposed if the transcript left your machine. Run `agent-sdk rotate-token <slug>`, store the new token outside agent transcripts, and update callers. |
|
|
84
|
+
| Someone verified a secret with `echo` / `printenv` | Rotate it. Confirm presence with `agent-sdk secrets list <slug>` (names only), then redeploy and test the feature. |
|
|
85
|
+
|
|
78
86
|
## What if schedules, reminders, or approvals stall?
|
|
79
87
|
|
|
80
88
|
| What you see | What to do |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cursor/july",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"repository": {
|
|
@@ -141,6 +141,24 @@
|
|
|
141
141
|
"import": "./dist/artifacts.js",
|
|
142
142
|
"default": "./dist/artifacts.js"
|
|
143
143
|
},
|
|
144
|
+
"./kv": {
|
|
145
|
+
"anysphere-source": "./src/kv.ts",
|
|
146
|
+
"types": "./dist/kv.d.ts",
|
|
147
|
+
"import": "./dist/kv.js",
|
|
148
|
+
"default": "./dist/kv.js"
|
|
149
|
+
},
|
|
150
|
+
"./kv/memory": {
|
|
151
|
+
"anysphere-source": "./src/kv/memory-kv.ts",
|
|
152
|
+
"types": "./dist/kv/memory-kv.d.ts",
|
|
153
|
+
"import": "./dist/kv/memory-kv.js",
|
|
154
|
+
"default": "./dist/kv/memory-kv.js"
|
|
155
|
+
},
|
|
156
|
+
"./ledger": {
|
|
157
|
+
"anysphere-source": "./src/ledger.ts",
|
|
158
|
+
"types": "./dist/ledger.d.ts",
|
|
159
|
+
"import": "./dist/ledger.js",
|
|
160
|
+
"default": "./dist/ledger.js"
|
|
161
|
+
},
|
|
144
162
|
"./storage": {
|
|
145
163
|
"anysphere-source": "./src/storage.ts",
|
|
146
164
|
"types": "./dist/storage.d.ts",
|
|
@@ -153,12 +171,6 @@
|
|
|
153
171
|
"import": "./dist/storage-backends/file-kv.js",
|
|
154
172
|
"default": "./dist/storage-backends/file-kv.js"
|
|
155
173
|
},
|
|
156
|
-
"./storage/postgres-kv": {
|
|
157
|
-
"anysphere-source": "./src/storage-backends/postgres-kv.ts",
|
|
158
|
-
"types": "./dist/storage-backends/postgres-kv.d.ts",
|
|
159
|
-
"import": "./dist/storage-backends/postgres-kv.js",
|
|
160
|
-
"default": "./dist/storage-backends/postgres-kv.js"
|
|
161
|
-
},
|
|
162
174
|
"./storage/cursor-hosted": {
|
|
163
175
|
"anysphere-source": "./src/storage-backends/cursor-hosted.ts",
|
|
164
176
|
"types": "./dist/storage-backends/cursor-hosted.d.ts",
|
|
@@ -182,6 +194,7 @@
|
|
|
182
194
|
"docs:dev": "vitepress dev docs",
|
|
183
195
|
"docs:build": "vitepress build docs",
|
|
184
196
|
"docs:preview": "vitepress preview docs",
|
|
197
|
+
"docs:verify-links": "node scripts/verify-docs-links.mjs",
|
|
185
198
|
"fix": "biome check --write --unsafe src",
|
|
186
199
|
"test": "vitest run --passWithNoTests",
|
|
187
200
|
"type-check": "tsgo --noEmit && tsgo --noEmit -p playground/tsconfig.json",
|
|
@@ -144,7 +144,7 @@ a demo `agent/tools/echo.ts`, and empty capability folders
|
|
|
144
144
|
(`skills/`, `channels/`, `evals/`, …) each with a `.gitkeep`; existing
|
|
145
145
|
files are left alone (`exist`) and missing ones are filled in. It then
|
|
146
146
|
runs `npm install`, and when the host is unsigned runs `login` and waits
|
|
147
|
-
before printing `cd` (when needed) and
|
|
147
|
+
before printing `cd` (when needed) and `agent-sdk dev`. Then shape it to the
|
|
148
148
|
plan:
|
|
149
149
|
|
|
150
150
|
1. `tsconfig.json` — init writes a strict, `noEmit` config covering `agent/`
|
package/src/bin/agent-serve.ts
CHANGED
|
@@ -136,8 +136,8 @@ Usage:
|
|
|
136
136
|
${CLI} stop <slug> [--team <id>] [--json] [--no-wait]
|
|
137
137
|
${CLI} rotate-token <slug> [--team <id>]
|
|
138
138
|
${CLI} rotate-pod-credential <slug> [--team <id>]
|
|
139
|
-
${CLI} secrets set <slug> NAME
|
|
140
|
-
[--team <id>] [--json]
|
|
139
|
+
${CLI} secrets set <slug> NAME... | list <slug> | unset <slug> NAME
|
|
140
|
+
[--team <id>] [--json] [--from-argv]
|
|
141
141
|
${CLI} slack <subcommand> …
|
|
142
142
|
${CLI} github <subcommand> …
|
|
143
143
|
|
|
@@ -257,9 +257,9 @@ Commands:
|
|
|
257
257
|
rotate-pod-credential
|
|
258
258
|
Rotate a deployment's pod credential (prints the masked key);
|
|
259
259
|
the running pod keeps the old one until the next deploy.
|
|
260
|
-
secrets Manage deployment secrets: set (
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
secrets Manage deployment secrets: set (names only by default: hidden
|
|
261
|
+
prompt or piped stdin; NAME=VALUE requires --from-argv), list
|
|
262
|
+
(names + createdAt; never values), unset.
|
|
263
263
|
slack Slack channel pack: create/destroy/icon (Cursor Add to Slack
|
|
264
264
|
provisioning), init, manifests, doctor (see slack help).
|
|
265
265
|
github GitHub webhook pack: forward live deliveries, events, doctor
|
|
@@ -276,7 +276,9 @@ Agent loop:
|
|
|
276
276
|
Options:
|
|
277
277
|
--version, -V Print the installed version and exit.
|
|
278
278
|
--dir Project root (defaults to the current directory).
|
|
279
|
-
--port Port to listen on (default 3000).
|
|
279
|
+
--port Port to listen on (default 3000). When the default is
|
|
280
|
+
taken, serve tries the next free port and prints a notice.
|
|
281
|
+
An explicit --port fails with a next-port hint instead.
|
|
280
282
|
--host Host to bind (default 127.0.0.1).
|
|
281
283
|
--mode serve: "multi" (default, slugged /<dir>/v1/*) or "single"
|
|
282
284
|
(unslugged /v1/*). Multi also exposes host /v1/health for
|
|
@@ -402,6 +404,9 @@ Options:
|
|
|
402
404
|
--allow-domain deploy: egress domain the engine pod may reach
|
|
403
405
|
(repeatable; unioned with hosting.egressDomains from the
|
|
404
406
|
agent manifest). Repo-backed deploys only.
|
|
407
|
+
--from-argv secrets set: allow NAME=VALUE on argv (leaks into shell
|
|
408
|
+
history and agent-captured terminals). Default is names
|
|
409
|
+
only with a hidden prompt or piped stdin.
|
|
405
410
|
--org github forward: organization login (org-level hooks).
|
|
406
411
|
--channel github: select one channel id when several are declared.
|
|
407
412
|
--secret github forward: webhook signing secret (defaults to
|
|
@@ -535,6 +540,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
535
540
|
all: { type: "boolean", default: false },
|
|
536
541
|
"cursor-events-repo": { type: "string", multiple: true },
|
|
537
542
|
"allow-domain": { type: "string", multiple: true },
|
|
543
|
+
"from-argv": { type: "boolean", default: false },
|
|
538
544
|
strict: { type: "boolean", default: false },
|
|
539
545
|
junit: { type: "string" },
|
|
540
546
|
artifacts: { type: "string" },
|
|
@@ -1148,8 +1154,13 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1148
1154
|
}
|
|
1149
1155
|
const serveDir = serveDirResult;
|
|
1150
1156
|
const port =
|
|
1151
|
-
values.port === undefined
|
|
1152
|
-
|
|
1157
|
+
values.port === undefined
|
|
1158
|
+
? undefined
|
|
1159
|
+
: Number.parseInt(values.port, 10);
|
|
1160
|
+
if (
|
|
1161
|
+
port !== undefined &&
|
|
1162
|
+
(Number.isNaN(port) || port < 0 || port > 65535)
|
|
1163
|
+
) {
|
|
1153
1164
|
process.stderr.write(`invalid --port: ${values.port}\n`);
|
|
1154
1165
|
return 1;
|
|
1155
1166
|
}
|
|
@@ -1303,12 +1314,14 @@ function deployOptionsFromValues(values: {
|
|
|
1303
1314
|
json?: boolean;
|
|
1304
1315
|
"no-wait"?: boolean;
|
|
1305
1316
|
"api-key"?: string;
|
|
1317
|
+
"from-argv"?: boolean;
|
|
1306
1318
|
}): DeployCliOptions {
|
|
1307
1319
|
return {
|
|
1308
|
-
|
|
1320
|
+
team: values.team,
|
|
1309
1321
|
json: values.json === true,
|
|
1310
1322
|
noWait: values["no-wait"] === true,
|
|
1311
|
-
|
|
1323
|
+
apiKey: values["api-key"],
|
|
1324
|
+
fromArgv: values["from-argv"] === true ? true : undefined,
|
|
1312
1325
|
};
|
|
1313
1326
|
}
|
|
1314
1327
|
|
|
@@ -1484,7 +1497,10 @@ function printServeBanner(
|
|
|
1484
1497
|
if (playgroundUrl !== undefined) {
|
|
1485
1498
|
process.stdout.write(` playground ${c.cyan(playgroundUrl)}\n`);
|
|
1486
1499
|
}
|
|
1487
|
-
|
|
1500
|
+
// `/` is only mounted when the playground host home is enabled.
|
|
1501
|
+
if (!opts.noPlayground) {
|
|
1502
|
+
process.stdout.write(` home ${c.cyan(handle.url + "/")}\n`);
|
|
1503
|
+
}
|
|
1488
1504
|
// Dev is playground-first (Vite proxies the API). Keep API/route detail for
|
|
1489
1505
|
// plain `serve`, where operators often curl the HTTP surface directly.
|
|
1490
1506
|
if (!opts.dev) {
|
|
@@ -204,25 +204,30 @@ export async function setThreadStatus(args: {
|
|
|
204
204
|
return { ok: false, error: "missing_channel_or_thread" };
|
|
205
205
|
}
|
|
206
206
|
const status = truncateTypingStatus(args.status);
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
207
|
+
const body: Record<string, unknown> = {
|
|
208
|
+
channel_id: args.channelId,
|
|
209
|
+
thread_ts: args.threadTs,
|
|
210
|
+
status,
|
|
211
|
+
};
|
|
212
|
+
// Empty status clears Slack's assistant chip ("App is working…").
|
|
213
|
+
// Sending loading_messages with it keeps the chip rotating.
|
|
214
|
+
if (status.length > 0) {
|
|
215
|
+
const loadingRaw =
|
|
216
|
+
args.loadingMessages !== undefined && args.loadingMessages.length > 0
|
|
217
|
+
? args.loadingMessages
|
|
218
|
+
: [
|
|
212
219
|
status,
|
|
213
220
|
...SLACK_DEFAULT_LOADING_MESSAGES.filter((m) => m !== status),
|
|
214
|
-
]
|
|
215
|
-
|
|
216
|
-
|
|
221
|
+
];
|
|
222
|
+
const loading_messages = truncateLoadingMessages(loadingRaw);
|
|
223
|
+
if (loading_messages.length > 0) {
|
|
224
|
+
body.loading_messages = loading_messages;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
217
227
|
return callSlackApiSoft({
|
|
218
228
|
botToken: args.botToken,
|
|
219
229
|
operation: "assistant.threads.setStatus",
|
|
220
|
-
body
|
|
221
|
-
channel_id: args.channelId,
|
|
222
|
-
thread_ts: args.threadTs,
|
|
223
|
-
status,
|
|
224
|
-
...(loading_messages.length > 0 ? { loading_messages } : {}),
|
|
225
|
-
},
|
|
230
|
+
body,
|
|
226
231
|
});
|
|
227
232
|
}
|
|
228
233
|
|