syntaur 0.12.0 → 0.14.0
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/.claude-plugin/plugin.json +5 -1
- package/README.md +23 -0
- package/dashboard/dist/assets/{_basePickBy-XOV2F7dX.js → _basePickBy-qEDLAY_J.js} +1 -1
- package/dashboard/dist/assets/{_baseUniq-Dccfk3fK.js → _baseUniq-7tDs18Gn.js} +1 -1
- package/dashboard/dist/assets/{arc-TwJ5RF-H.js → arc-Brdw0dYW.js} +1 -1
- package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-CpkVJudw.js → architectureDiagram-2XIMDMQ5-BiEdLT9m.js} +1 -1
- package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-Ck6VQ4Fh.js → blockDiagram-WCTKOSBZ-HC-j_hPZ.js} +1 -1
- package/dashboard/dist/assets/{c4Diagram-IC4MRINW-B5V7YG03.js → c4Diagram-IC4MRINW-DA_rWbl7.js} +1 -1
- package/dashboard/dist/assets/channel-D2-caOn6.js +1 -0
- package/dashboard/dist/assets/{chunk-4BX2VUAB-rBdyOxAe.js → chunk-4BX2VUAB-CF3hguyj.js} +1 -1
- package/dashboard/dist/assets/{chunk-55IACEB6-DKlNXjYt.js → chunk-55IACEB6-BTeCeIc_.js} +1 -1
- package/dashboard/dist/assets/{chunk-FMBD7UC4-Cqm0PtUI.js → chunk-FMBD7UC4-8qVvxmks.js} +1 -1
- package/dashboard/dist/assets/{chunk-JSJVCQXG-CQyXQcG3.js → chunk-JSJVCQXG-DCf8n7EO.js} +1 -1
- package/dashboard/dist/assets/{chunk-KX2RTZJC-DmqjHPpJ.js → chunk-KX2RTZJC-CcpjTmME.js} +1 -1
- package/dashboard/dist/assets/{chunk-NQ4KR5QH-CHXoBcYa.js → chunk-NQ4KR5QH-BnFPKo4-.js} +1 -1
- package/dashboard/dist/assets/{chunk-QZHKN3VN-Dd4sChBS.js → chunk-QZHKN3VN-IPMVLLv2.js} +1 -1
- package/dashboard/dist/assets/{chunk-WL4C6EOR-D-QLnkY8.js → chunk-WL4C6EOR-D1pQmHqX.js} +1 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-HFOb_XEt.js +1 -0
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-HFOb_XEt.js +1 -0
- package/dashboard/dist/assets/clone-BrYOwgIq.js +1 -0
- package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-VZi6uV56.js → cose-bilkent-S5V4N54A-tvJjvBQr.js} +1 -1
- package/dashboard/dist/assets/{dagre-KLK3FWXG-CtT97Qhx.js → dagre-KLK3FWXG-qp1vt6LY.js} +1 -1
- package/dashboard/dist/assets/{diagram-E7M64L7V-BjYTNNHb.js → diagram-E7M64L7V-VF5eizNr.js} +1 -1
- package/dashboard/dist/assets/{diagram-IFDJBPK2-qj8_r6fb.js → diagram-IFDJBPK2-C3pCbJ1e.js} +1 -1
- package/dashboard/dist/assets/{diagram-P4PSJMXO-DlfWo7Vt.js → diagram-P4PSJMXO-D-taXZwH.js} +1 -1
- package/dashboard/dist/assets/{erDiagram-INFDFZHY-Ch_nApTv.js → erDiagram-INFDFZHY-QjY-NHVs.js} +1 -1
- package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-EOVsqNyi.js → flowDiagram-PKNHOUZH-FjO8P5Tq.js} +1 -1
- package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-CS-lx0B-.js → ganttDiagram-A5KZAMGK-Bsn7CyK3.js} +1 -1
- package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-Ba6RDzPy.js → gitGraphDiagram-K3NZZRJ6-BZ8DjhnF.js} +1 -1
- package/dashboard/dist/assets/{graph-BKaAyLk-.js → graph-AdliIYqX.js} +1 -1
- package/dashboard/dist/assets/{index-BTWPZaIA.css → index-BoR_oyUZ.css} +1 -1
- package/dashboard/dist/assets/index-RCBI4aX2.js +525 -0
- package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-Cr20xEsd.js → infoDiagram-LFFYTUFH-BfZjLA86.js} +1 -1
- package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-CuILV9ph.js → ishikawaDiagram-PHBUUO56-BSgSGMp5.js} +1 -1
- package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-CO-l7Mpm.js → journeyDiagram-4ABVD52K-BlQ7qeMC.js} +1 -1
- package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-CcirPw_S.js → kanban-definition-K7BYSVSG-CifO0AUu.js} +1 -1
- package/dashboard/dist/assets/{layout-BXvr8dMw.js → layout-B9r-gpD9.js} +1 -1
- package/dashboard/dist/assets/{linear-B85hgYnX.js → linear-CaaIRxVZ.js} +1 -1
- package/dashboard/dist/assets/{mermaid.core-DcZN9Xp2.js → mermaid.core-C8wCWYw-.js} +4 -4
- package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-Bxi6p5_3.js → mindmap-definition-YRQLILUH-BpX5T7iT.js} +1 -1
- package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-DOSvU0UD.js → pieDiagram-SKSYHLDU-BNGYtWrc.js} +1 -1
- package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-Cmo-5tW9.js → quadrantDiagram-337W2JSQ-CR4GeM9D.js} +1 -1
- package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-Dw8alwuI.js → requirementDiagram-Z7DCOOCP-CXrPkMLl.js} +1 -1
- package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-ZPB-rzOg.js → sankeyDiagram-WA2Y5GQK-CIzof7Dm.js} +1 -1
- package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-Ct8bkK2h.js → sequenceDiagram-2WXFIKYE-BJZLt0O2.js} +1 -1
- package/dashboard/dist/assets/{stateDiagram-RAJIS63D-DnGOXlmx.js → stateDiagram-RAJIS63D-x9gC6zy6.js} +1 -1
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-CN5Dcv7u.js +1 -0
- package/dashboard/dist/assets/{timeline-definition-YZTLITO2-AUFmbJjr.js → timeline-definition-YZTLITO2-D_ZSQn1K.js} +1 -1
- package/dashboard/dist/assets/{treemap-KZPCXAKY-Dw5FDFAV.js → treemap-KZPCXAKY-LPpMEco4.js} +1 -1
- package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-DfxicU4N.js → vennDiagram-LZ73GAT5-CRFZQpr7.js} +1 -1
- package/dashboard/dist/assets/{xychartDiagram-JWTSCODW--9N0V1r_.js → xychartDiagram-JWTSCODW-Bivutynw.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/dashboard/server.js +419 -84
- package/dist/dashboard/server.js.map +1 -1
- package/dist/db/leases-db.d.ts +227 -0
- package/dist/db/leases-db.js +679 -0
- package/dist/db/leases-db.js.map +1 -0
- package/dist/index.js +1825 -445
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/claude-code/.claude-plugin/plugin.json +5 -1
- package/platforms/claude-code/skills/claim-resource/SKILL.md +89 -0
- package/platforms/claude-code/skills/extend-resource/SKILL.md +83 -0
- package/platforms/claude-code/skills/list-resources/SKILL.md +74 -0
- package/platforms/claude-code/skills/release-resource/SKILL.md +65 -0
- package/platforms/claude-code/skills/syntaur-protocol/SKILL.md +1 -0
- package/platforms/codex/skills/claim-resource/SKILL.md +89 -0
- package/platforms/codex/skills/extend-resource/SKILL.md +83 -0
- package/platforms/codex/skills/list-resources/SKILL.md +74 -0
- package/platforms/codex/skills/release-resource/SKILL.md +65 -0
- package/platforms/codex/skills/syntaur-protocol/SKILL.md +1 -0
- package/skills/claim-resource/SKILL.md +89 -0
- package/skills/extend-resource/SKILL.md +83 -0
- package/skills/list-resources/SKILL.md +74 -0
- package/skills/release-resource/SKILL.md +65 -0
- package/skills/syntaur-protocol/SKILL.md +1 -0
- package/dashboard/dist/assets/channel-AEMTX70R.js +0 -1
- package/dashboard/dist/assets/classDiagram-VBA2DB6C-LzuOAGzu.js +0 -1
- package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-LzuOAGzu.js +0 -1
- package/dashboard/dist/assets/clone-Cw63QGUJ.js +0 -1
- package/dashboard/dist/assets/index-Dk9PBm5B.js +0 -510
- package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-COGzlZxn.js +0 -1
package/package.json
CHANGED
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
"./skills/add-memory",
|
|
26
26
|
"./skills/list-assignments",
|
|
27
27
|
"./skills/log-progress",
|
|
28
|
-
"./skills/set-workspace"
|
|
28
|
+
"./skills/set-workspace",
|
|
29
|
+
"./skills/claim-resource",
|
|
30
|
+
"./skills/release-resource",
|
|
31
|
+
"./skills/extend-resource",
|
|
32
|
+
"./skills/list-resources"
|
|
29
33
|
]
|
|
30
34
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: claim-resource
|
|
3
|
+
description: Claim an idle member of a Syntaur leases inventory (dev env, test DB, API key, named lock, etc.) for the current assignment session. Triggers on "/claim-resource", "claim a dev env", "lease an environment", "grab a test DB", "claim a slot", or when the user wants to coordinate access to a shared finite resource.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Claim Resource
|
|
8
|
+
|
|
9
|
+
Claim an idle member of a Syntaur leases inventory and persist the lease into `.syntaur/context.json`. The claimed member's connection metadata (URL, ssh string, port, etc.) is printed back so the agent can use it immediately.
|
|
10
|
+
|
|
11
|
+
The claim is **fail-fast** — if no member is idle, the command exits non-zero. If a long-running blocking claim is wanted, the agent retries externally with backoff.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
User arguments: `$ARGUMENTS`
|
|
16
|
+
|
|
17
|
+
- `<inventory_slug>` (required) — which inventory to claim from
|
|
18
|
+
- `--ttl <duration>` (optional) — lease TTL, e.g. `15m`, `2h`. Defaults to the inventory's `default_ttl`.
|
|
19
|
+
- `--for <tag>` (optional) — free-form requester tag (defaults to the active assignment slug if omitted)
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
- `/claim-resource dev-envs`
|
|
23
|
+
- `/claim-resource dev-envs --ttl 1h`
|
|
24
|
+
- `/claim-resource prod-migration-lock --ttl 5m --for "migration-2026-05-12"`
|
|
25
|
+
|
|
26
|
+
## Workflow
|
|
27
|
+
|
|
28
|
+
### Step 1: Parse arguments
|
|
29
|
+
|
|
30
|
+
Extract `<inventory_slug>` (required, first positional), plus optional `--ttl <duration>` and `--for <tag>`.
|
|
31
|
+
|
|
32
|
+
### Step 2: Pre-check assignment context
|
|
33
|
+
|
|
34
|
+
Read `.syntaur/context.json` from the current working directory. If the file is missing, OR has neither `sessionId` nor any of `projectSlug`/`assignmentSlug`/`assignmentDir`, abort with:
|
|
35
|
+
|
|
36
|
+
> "No active Syntaur context in this workspace. Grab an assignment first (`/grab-assignment <project> <slug>`) or restart the session so the SessionStart hook can populate `.syntaur/context.json`."
|
|
37
|
+
|
|
38
|
+
This guard exists because writing a leases-only context file would trip `syntaur doctor`'s workspace check.
|
|
39
|
+
|
|
40
|
+
If `--for` was not provided, derive its value from the context: prefer `assignmentSlug` if present, otherwise `sessionId`.
|
|
41
|
+
|
|
42
|
+
### Step 3: Run the claim CLI
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
syntaur lease claim "$INVENTORY_SLUG" --json \
|
|
46
|
+
${TTL:+--ttl "$TTL"} \
|
|
47
|
+
--for "$TAG"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
(Use `dangerouslyDisableSandbox: true` for the Bash call — the CLI writes to `~/.syntaur/syntaur.db`.)
|
|
51
|
+
|
|
52
|
+
Possible non-zero exits and how to surface them to the user:
|
|
53
|
+
|
|
54
|
+
| stderr fragment | meaning | how to respond |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `no idle members in '<slug>'` | `NoIdleMemberError` — pool exhausted | Tell user; suggest waiting / retrying later or asking a human to add capacity. |
|
|
57
|
+
| `contention timeout on '<slug>'; retry` | `LeaseContentionError` — busy timeout | Retry once after ~1s. If it fails again, surface the error. |
|
|
58
|
+
| `inventory '<slug>' not found` | typo or inventory doesn't exist | Tell user; list with `syntaur lease list`. |
|
|
59
|
+
|
|
60
|
+
### Step 4: Parse the claim result
|
|
61
|
+
|
|
62
|
+
Parse the stdout JSON: `{ lease_id, inventory_slug, member_id, member_gen, granted_at, expires_at, metadata }`.
|
|
63
|
+
|
|
64
|
+
### Step 5: Persist the lease in `.syntaur/context.json`
|
|
65
|
+
|
|
66
|
+
Append the lease record to the `leases: []` array in `.syntaur/context.json` (creating the array if absent). Atomic write via `jq` + rename:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
mkdir -p .syntaur
|
|
70
|
+
jq --arg lid "$LEASE_ID" \
|
|
71
|
+
--arg slug "$INVENTORY_SLUG" \
|
|
72
|
+
--arg mid "$MEMBER_ID" \
|
|
73
|
+
--arg exp "$EXPIRES_AT" \
|
|
74
|
+
--arg claimed "$GRANTED_AT" \
|
|
75
|
+
--argjson meta "$METADATA_JSON" \
|
|
76
|
+
'.leases = ((.leases // []) | map(select(.lease_id != $lid)) +
|
|
77
|
+
[{ lease_id: $lid, inventory_slug: $slug, member_id: $mid,
|
|
78
|
+
expires_at: $exp, metadata: $meta, claimed_at: $claimed }])' \
|
|
79
|
+
.syntaur/context.json > .syntaur/context.json.tmp \
|
|
80
|
+
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Step 6: Report back
|
|
84
|
+
|
|
85
|
+
Tell the user:
|
|
86
|
+
- Which member was claimed (`<inventory>/<member_id>`) and the lease id.
|
|
87
|
+
- When the lease expires (`expires_at`).
|
|
88
|
+
- The connection metadata, if any (URL, port, credentials reference, etc.) — print as a code block so the agent (or human) can use it.
|
|
89
|
+
- Reminder: leases do NOT auto-release on session end or assignment completion in v1. Call `/release-resource <lease_id>` when finished, or let the TTL expire and `gc` reclaim.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: extend-resource
|
|
3
|
+
description: Extend the TTL on a Syntaur resource lease previously claimed via /claim-resource. Triggers on "/extend-resource", "extend my lease", "renew the lease", "bump the TTL", "keep this resource a bit longer", or when the user wants more time on an active claim.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Extend Resource
|
|
8
|
+
|
|
9
|
+
Extend an active Syntaur resource lease by pushing its `expires_at` forward. On success, also updates the lease's `expires_at` in `.syntaur/context.json` so the local record stays accurate. If the lease has already gone stale (expired, revoked, or member generation advanced), drops it from `.syntaur/context.json` and reports.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
User arguments: `$ARGUMENTS`
|
|
14
|
+
|
|
15
|
+
- `<lease_id>` (required) — lease to extend
|
|
16
|
+
- `--ttl <duration>` (required) — new TTL from now (e.g. `15m`, `2h`)
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
- `/extend-resource cf3bd0a6-ba38-4a8c-a882-bdba9cabad80 --ttl 1h`
|
|
20
|
+
- `/extend-resource 6d4a... --ttl 30m`
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
### Step 1: Parse arguments
|
|
25
|
+
|
|
26
|
+
Extract `<lease_id>` (first positional) and `--ttl <duration>` (required). If either is missing, abort with a usage message and a hint to call `/list-resources` to see active leases.
|
|
27
|
+
|
|
28
|
+
### Step 2: Pre-check assignment context
|
|
29
|
+
|
|
30
|
+
Read `.syntaur/context.json` from the current working directory. If the file is missing, OR has neither `sessionId` nor any of `projectSlug`/`assignmentSlug`/`assignmentDir`, abort with:
|
|
31
|
+
|
|
32
|
+
> "No active Syntaur context in this workspace. Grab an assignment first (`/grab-assignment <project> <slug>`) or restart the session so the SessionStart hook can populate `.syntaur/context.json`."
|
|
33
|
+
|
|
34
|
+
This guard mirrors `/claim-resource` and `/release-resource` — writing a leases-only context file would trip `syntaur doctor`'s workspace check.
|
|
35
|
+
|
|
36
|
+
### Step 3: Run the extend CLI
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
syntaur lease extend "$LEASE_ID" --ttl "$TTL"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
(Use `dangerouslyDisableSandbox: true` — the CLI writes to `~/.syntaur/syntaur.db`.)
|
|
43
|
+
|
|
44
|
+
Possible non-zero exits and how to surface them:
|
|
45
|
+
|
|
46
|
+
| stderr fragment | meaning | how to respond |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `cannot be extended (expired, revoked, or member generation advanced)` | `StaleLeaseError` — lease is no longer the holder. | Drop the entry from `.syntaur/context.json` (Step 5) and tell user the lease is dead — they'll need to `/claim-resource` again. |
|
|
49
|
+
| `contention timeout; retry` | `LeaseContentionError` — busy timeout. | Retry once after ~1s. If it fails again, surface to user. |
|
|
50
|
+
| `--ttl must be positive` | Bad duration. | Tell user to pass a positive duration like `15m`, `2h`. |
|
|
51
|
+
|
|
52
|
+
### Step 4: Parse the new expiry from stdout
|
|
53
|
+
|
|
54
|
+
On exit 0, stdout looks like: `Extended lease <id> (new expires_at=<iso>).`
|
|
55
|
+
|
|
56
|
+
Capture the `new_expires_at` value (the ISO timestamp inside the parens).
|
|
57
|
+
|
|
58
|
+
### Step 5a: On success, update `.syntaur/context.json`
|
|
59
|
+
|
|
60
|
+
Find the matching entry in `leases[]` by `lease_id` and rewrite its `expires_at`:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
jq --arg lid "$LEASE_ID" --arg exp "$NEW_EXPIRES_AT" \
|
|
64
|
+
'.leases = ((.leases // []) | map(
|
|
65
|
+
if .lease_id == $lid then .expires_at = $exp else . end
|
|
66
|
+
))' \
|
|
67
|
+
.syntaur/context.json > .syntaur/context.json.tmp \
|
|
68
|
+
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Step 5b: On `StaleLeaseError`, drop the entry instead
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
jq --arg lid "$LEASE_ID" \
|
|
75
|
+
'.leases = ((.leases // []) | map(select(.lease_id != $lid)))' \
|
|
76
|
+
.syntaur/context.json > .syntaur/context.json.tmp \
|
|
77
|
+
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 6: Report back
|
|
81
|
+
|
|
82
|
+
- On success: `Extended <lease_id> — new expires_at=<iso>.` Also surface the original member id (look it up in the context entry before mutation) so the user knows which resource was extended.
|
|
83
|
+
- On stale: `Lease <lease_id> is no longer active — removed from context. Run /claim-resource to grab a new one.`
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: list-resources
|
|
3
|
+
description: List the Syntaur resource leases held by the current session, plus the workspace-wide overview of inventories and active leases. Triggers on "/list-resources", "what leases do I have", "show my leases", "list my resources", "what resources am I holding", or when the user wants both a session-local and system-wide view of leased resources.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# List Resources
|
|
8
|
+
|
|
9
|
+
Print two views in one call:
|
|
10
|
+
|
|
11
|
+
1. **Your active leases** — the `leases[]` array from `.syntaur/context.json` (this session's claims).
|
|
12
|
+
2. **All active leases in this workspace** — output of `syntaur lease list`, which shows every inventory plus its idle/leased counts.
|
|
13
|
+
|
|
14
|
+
This is the cheap "what am I holding, and what's out there?" lookup before deciding to extend, release, or grab another resource.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
User arguments: `$ARGUMENTS` (no arguments accepted in v1).
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
- `/list-resources`
|
|
22
|
+
|
|
23
|
+
## Workflow
|
|
24
|
+
|
|
25
|
+
### Step 1: Read this session's leases
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
jq -r '.leases // []' .syntaur/context.json 2>/dev/null
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
(No `dangerouslyDisableSandbox` needed — read-only.)
|
|
32
|
+
|
|
33
|
+
If `.syntaur/context.json` is missing or has no `leases` array, treat it as empty. Do NOT abort — listing is informational; the absence of session context is itself a useful signal.
|
|
34
|
+
|
|
35
|
+
For each entry, capture: `lease_id`, `inventory_slug`, `member_id`, `expires_at`, `claimed_at`, and any `metadata` (e.g. connection URL).
|
|
36
|
+
|
|
37
|
+
### Step 2: Run the system-wide overview
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
syntaur lease list
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
(Use `dangerouslyDisableSandbox: true` — the CLI reads `~/.syntaur/syntaur.db`.)
|
|
44
|
+
|
|
45
|
+
Capture stdout. If the CLI exits non-zero, surface the error message but still print whatever Step 1 produced.
|
|
46
|
+
|
|
47
|
+
### Step 3: Report back
|
|
48
|
+
|
|
49
|
+
Print two sections:
|
|
50
|
+
|
|
51
|
+
**Your active leases (from `.syntaur/context.json`):**
|
|
52
|
+
|
|
53
|
+
If the array is empty:
|
|
54
|
+
> "No leases held by this session."
|
|
55
|
+
|
|
56
|
+
Otherwise, one block per lease:
|
|
57
|
+
```
|
|
58
|
+
<lease_id>
|
|
59
|
+
inventory: <inventory_slug>/<member_id>
|
|
60
|
+
expires: <expires_at>
|
|
61
|
+
claimed: <claimed_at>
|
|
62
|
+
metadata: <metadata JSON, if any>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**All inventories in this workspace (from `syntaur lease list`):**
|
|
66
|
+
|
|
67
|
+
Paste the CLI output verbatim (one row per inventory with kind/idle/leased counts).
|
|
68
|
+
|
|
69
|
+
### Step 4: Suggest next actions if any leases are nearing expiry
|
|
70
|
+
|
|
71
|
+
If any session-local lease's `expires_at` is within the next 5 minutes, append:
|
|
72
|
+
> "Note: lease `<id>` expires at `<iso>` (within 5 minutes). Run `/extend-resource <id> --ttl <duration>` to keep it."
|
|
73
|
+
|
|
74
|
+
This is informational only — don't extend automatically.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release-resource
|
|
3
|
+
description: Release a Syntaur resource lease previously claimed via /claim-resource, freeing the member for the next claimant. Triggers on "/release-resource", "release this dev env", "drop the lease", "release my slot", "release all leases", or when the user is done with a claimed resource.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Release Resource
|
|
8
|
+
|
|
9
|
+
Release one or more active resource leases, removing them from `.syntaur/context.json` and freeing their members for the next claimant.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
User arguments: `$ARGUMENTS`
|
|
14
|
+
|
|
15
|
+
- `<lease_id>` — release a specific lease by id
|
|
16
|
+
- `--all` — release every active lease recorded in `.syntaur/context.json`
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
- `/release-resource cf3bd0a6-ba38-4a8c-a882-bdba9cabad80`
|
|
20
|
+
- `/release-resource --all`
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
### Step 1: Parse arguments
|
|
25
|
+
|
|
26
|
+
If `--all` is passed, build the list of `lease_id`s from `.syntaur/context.json`'s `leases: []` array. Otherwise the first positional argument is the single `lease_id` to release.
|
|
27
|
+
|
|
28
|
+
If there is no `lease_id` and `--all` was not passed, abort with: "Specify `<lease_id>` or use `--all`. Active leases: $(jq -r '.leases[]?.lease_id' .syntaur/context.json 2>/dev/null || echo 'none')."
|
|
29
|
+
|
|
30
|
+
### Step 2: Release each lease
|
|
31
|
+
|
|
32
|
+
For each `lease_id`:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
syntaur lease release "$LEASE_ID"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
(Use `dangerouslyDisableSandbox: true` since the CLI writes to `~/.syntaur/syntaur.db`.)
|
|
39
|
+
|
|
40
|
+
Outcomes:
|
|
41
|
+
|
|
42
|
+
| Result | Meaning | What to do |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| Exit 0 with `Released lease <id>.` | Normal release. | Continue. |
|
|
45
|
+
| Exit 1 with `lease ... is no longer active` | Stale lease (already expired/revoked). The slot has already been freed. | Still remove from `.syntaur/context.json` — the row is dead either way. Note the staleness in the final summary. |
|
|
46
|
+
| Exit 1 with `contention timeout; retry` | `LeaseContentionError`. | Retry once after ~1s; if it fails again, surface to the user. |
|
|
47
|
+
|
|
48
|
+
### Step 3: Remove the entry from `.syntaur/context.json`
|
|
49
|
+
|
|
50
|
+
Whether the CLI succeeded OR returned a stale-lease error, drop the matching record from `.syntaur/context.json` (stale leases are dead — keeping them in context is misleading):
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
jq --arg lid "$LEASE_ID" \
|
|
54
|
+
'.leases = ((.leases // []) | map(select(.lease_id != $lid)))' \
|
|
55
|
+
.syntaur/context.json > .syntaur/context.json.tmp \
|
|
56
|
+
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Step 4: Report back
|
|
60
|
+
|
|
61
|
+
For a single release: `Released <lease_id> (<inventory>/<member_id>).` or `Lease <id> was already stale; removed from context.`
|
|
62
|
+
|
|
63
|
+
For `--all`: print one line per lease, then a summary count: `Released N lease(s), M already stale.`
|
|
64
|
+
|
|
65
|
+
If no leases were recorded in context, say so explicitly.
|
|
@@ -60,6 +60,7 @@ If `.syntaur/context.json` exists in the current working directory, read it befo
|
|
|
60
60
|
- `workspaceRoot` — absolute path to the code workspace
|
|
61
61
|
- `sessionId` — real agent-runtime session id (never a synthesized UUID)
|
|
62
62
|
- `transcriptPath` — absolute path to the agent's rollout/transcript file, if known
|
|
63
|
+
- `leases` — array of active resource-lease records (managed by `/claim-resource` and `/release-resource`). Entry shape: `{ lease_id, inventory_slug, member_id, expires_at, metadata, claimed_at }`. Leases are NOT auto-released on session end or assignment completion in v1 — call `/release-resource` explicitly (or let the TTL expire).
|
|
63
64
|
|
|
64
65
|
## Required Reading Order
|
|
65
66
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: claim-resource
|
|
3
|
+
description: Claim an idle member of a Syntaur leases inventory (dev env, test DB, API key, named lock, etc.) for the current assignment session. Triggers on "/claim-resource", "claim a dev env", "lease an environment", "grab a test DB", "claim a slot", or when the user wants to coordinate access to a shared finite resource.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Claim Resource
|
|
8
|
+
|
|
9
|
+
Claim an idle member of a Syntaur leases inventory and persist the lease into `.syntaur/context.json`. The claimed member's connection metadata (URL, ssh string, port, etc.) is printed back so the agent can use it immediately.
|
|
10
|
+
|
|
11
|
+
The claim is **fail-fast** — if no member is idle, the command exits non-zero. If a long-running blocking claim is wanted, the agent retries externally with backoff.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
User arguments: `$ARGUMENTS`
|
|
16
|
+
|
|
17
|
+
- `<inventory_slug>` (required) — which inventory to claim from
|
|
18
|
+
- `--ttl <duration>` (optional) — lease TTL, e.g. `15m`, `2h`. Defaults to the inventory's `default_ttl`.
|
|
19
|
+
- `--for <tag>` (optional) — free-form requester tag (defaults to the active assignment slug if omitted)
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
- `/claim-resource dev-envs`
|
|
23
|
+
- `/claim-resource dev-envs --ttl 1h`
|
|
24
|
+
- `/claim-resource prod-migration-lock --ttl 5m --for "migration-2026-05-12"`
|
|
25
|
+
|
|
26
|
+
## Workflow
|
|
27
|
+
|
|
28
|
+
### Step 1: Parse arguments
|
|
29
|
+
|
|
30
|
+
Extract `<inventory_slug>` (required, first positional), plus optional `--ttl <duration>` and `--for <tag>`.
|
|
31
|
+
|
|
32
|
+
### Step 2: Pre-check assignment context
|
|
33
|
+
|
|
34
|
+
Read `.syntaur/context.json` from the current working directory. If the file is missing, OR has neither `sessionId` nor any of `projectSlug`/`assignmentSlug`/`assignmentDir`, abort with:
|
|
35
|
+
|
|
36
|
+
> "No active Syntaur context in this workspace. Grab an assignment first (`/grab-assignment <project> <slug>`) or restart the session so the SessionStart hook can populate `.syntaur/context.json`."
|
|
37
|
+
|
|
38
|
+
This guard exists because writing a leases-only context file would trip `syntaur doctor`'s workspace check.
|
|
39
|
+
|
|
40
|
+
If `--for` was not provided, derive its value from the context: prefer `assignmentSlug` if present, otherwise `sessionId`.
|
|
41
|
+
|
|
42
|
+
### Step 3: Run the claim CLI
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
syntaur lease claim "$INVENTORY_SLUG" --json \
|
|
46
|
+
${TTL:+--ttl "$TTL"} \
|
|
47
|
+
--for "$TAG"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
(Use `dangerouslyDisableSandbox: true` for the Bash call — the CLI writes to `~/.syntaur/syntaur.db`.)
|
|
51
|
+
|
|
52
|
+
Possible non-zero exits and how to surface them to the user:
|
|
53
|
+
|
|
54
|
+
| stderr fragment | meaning | how to respond |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `no idle members in '<slug>'` | `NoIdleMemberError` — pool exhausted | Tell user; suggest waiting / retrying later or asking a human to add capacity. |
|
|
57
|
+
| `contention timeout on '<slug>'; retry` | `LeaseContentionError` — busy timeout | Retry once after ~1s. If it fails again, surface the error. |
|
|
58
|
+
| `inventory '<slug>' not found` | typo or inventory doesn't exist | Tell user; list with `syntaur lease list`. |
|
|
59
|
+
|
|
60
|
+
### Step 4: Parse the claim result
|
|
61
|
+
|
|
62
|
+
Parse the stdout JSON: `{ lease_id, inventory_slug, member_id, member_gen, granted_at, expires_at, metadata }`.
|
|
63
|
+
|
|
64
|
+
### Step 5: Persist the lease in `.syntaur/context.json`
|
|
65
|
+
|
|
66
|
+
Append the lease record to the `leases: []` array in `.syntaur/context.json` (creating the array if absent). Atomic write via `jq` + rename:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
mkdir -p .syntaur
|
|
70
|
+
jq --arg lid "$LEASE_ID" \
|
|
71
|
+
--arg slug "$INVENTORY_SLUG" \
|
|
72
|
+
--arg mid "$MEMBER_ID" \
|
|
73
|
+
--arg exp "$EXPIRES_AT" \
|
|
74
|
+
--arg claimed "$GRANTED_AT" \
|
|
75
|
+
--argjson meta "$METADATA_JSON" \
|
|
76
|
+
'.leases = ((.leases // []) | map(select(.lease_id != $lid)) +
|
|
77
|
+
[{ lease_id: $lid, inventory_slug: $slug, member_id: $mid,
|
|
78
|
+
expires_at: $exp, metadata: $meta, claimed_at: $claimed }])' \
|
|
79
|
+
.syntaur/context.json > .syntaur/context.json.tmp \
|
|
80
|
+
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Step 6: Report back
|
|
84
|
+
|
|
85
|
+
Tell the user:
|
|
86
|
+
- Which member was claimed (`<inventory>/<member_id>`) and the lease id.
|
|
87
|
+
- When the lease expires (`expires_at`).
|
|
88
|
+
- The connection metadata, if any (URL, port, credentials reference, etc.) — print as a code block so the agent (or human) can use it.
|
|
89
|
+
- Reminder: leases do NOT auto-release on session end or assignment completion in v1. Call `/release-resource <lease_id>` when finished, or let the TTL expire and `gc` reclaim.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: extend-resource
|
|
3
|
+
description: Extend the TTL on a Syntaur resource lease previously claimed via /claim-resource. Triggers on "/extend-resource", "extend my lease", "renew the lease", "bump the TTL", "keep this resource a bit longer", or when the user wants more time on an active claim.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Extend Resource
|
|
8
|
+
|
|
9
|
+
Extend an active Syntaur resource lease by pushing its `expires_at` forward. On success, also updates the lease's `expires_at` in `.syntaur/context.json` so the local record stays accurate. If the lease has already gone stale (expired, revoked, or member generation advanced), drops it from `.syntaur/context.json` and reports.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
User arguments: `$ARGUMENTS`
|
|
14
|
+
|
|
15
|
+
- `<lease_id>` (required) — lease to extend
|
|
16
|
+
- `--ttl <duration>` (required) — new TTL from now (e.g. `15m`, `2h`)
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
- `/extend-resource cf3bd0a6-ba38-4a8c-a882-bdba9cabad80 --ttl 1h`
|
|
20
|
+
- `/extend-resource 6d4a... --ttl 30m`
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
### Step 1: Parse arguments
|
|
25
|
+
|
|
26
|
+
Extract `<lease_id>` (first positional) and `--ttl <duration>` (required). If either is missing, abort with a usage message and a hint to call `/list-resources` to see active leases.
|
|
27
|
+
|
|
28
|
+
### Step 2: Pre-check assignment context
|
|
29
|
+
|
|
30
|
+
Read `.syntaur/context.json` from the current working directory. If the file is missing, OR has neither `sessionId` nor any of `projectSlug`/`assignmentSlug`/`assignmentDir`, abort with:
|
|
31
|
+
|
|
32
|
+
> "No active Syntaur context in this workspace. Grab an assignment first (`/grab-assignment <project> <slug>`) or restart the session so the SessionStart hook can populate `.syntaur/context.json`."
|
|
33
|
+
|
|
34
|
+
This guard mirrors `/claim-resource` and `/release-resource` — writing a leases-only context file would trip `syntaur doctor`'s workspace check.
|
|
35
|
+
|
|
36
|
+
### Step 3: Run the extend CLI
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
syntaur lease extend "$LEASE_ID" --ttl "$TTL"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
(Use `dangerouslyDisableSandbox: true` — the CLI writes to `~/.syntaur/syntaur.db`.)
|
|
43
|
+
|
|
44
|
+
Possible non-zero exits and how to surface them:
|
|
45
|
+
|
|
46
|
+
| stderr fragment | meaning | how to respond |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `cannot be extended (expired, revoked, or member generation advanced)` | `StaleLeaseError` — lease is no longer the holder. | Drop the entry from `.syntaur/context.json` (Step 5) and tell user the lease is dead — they'll need to `/claim-resource` again. |
|
|
49
|
+
| `contention timeout; retry` | `LeaseContentionError` — busy timeout. | Retry once after ~1s. If it fails again, surface to user. |
|
|
50
|
+
| `--ttl must be positive` | Bad duration. | Tell user to pass a positive duration like `15m`, `2h`. |
|
|
51
|
+
|
|
52
|
+
### Step 4: Parse the new expiry from stdout
|
|
53
|
+
|
|
54
|
+
On exit 0, stdout looks like: `Extended lease <id> (new expires_at=<iso>).`
|
|
55
|
+
|
|
56
|
+
Capture the `new_expires_at` value (the ISO timestamp inside the parens).
|
|
57
|
+
|
|
58
|
+
### Step 5a: On success, update `.syntaur/context.json`
|
|
59
|
+
|
|
60
|
+
Find the matching entry in `leases[]` by `lease_id` and rewrite its `expires_at`:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
jq --arg lid "$LEASE_ID" --arg exp "$NEW_EXPIRES_AT" \
|
|
64
|
+
'.leases = ((.leases // []) | map(
|
|
65
|
+
if .lease_id == $lid then .expires_at = $exp else . end
|
|
66
|
+
))' \
|
|
67
|
+
.syntaur/context.json > .syntaur/context.json.tmp \
|
|
68
|
+
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Step 5b: On `StaleLeaseError`, drop the entry instead
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
jq --arg lid "$LEASE_ID" \
|
|
75
|
+
'.leases = ((.leases // []) | map(select(.lease_id != $lid)))' \
|
|
76
|
+
.syntaur/context.json > .syntaur/context.json.tmp \
|
|
77
|
+
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 6: Report back
|
|
81
|
+
|
|
82
|
+
- On success: `Extended <lease_id> — new expires_at=<iso>.` Also surface the original member id (look it up in the context entry before mutation) so the user knows which resource was extended.
|
|
83
|
+
- On stale: `Lease <lease_id> is no longer active — removed from context. Run /claim-resource to grab a new one.`
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: list-resources
|
|
3
|
+
description: List the Syntaur resource leases held by the current session, plus the workspace-wide overview of inventories and active leases. Triggers on "/list-resources", "what leases do I have", "show my leases", "list my resources", "what resources am I holding", or when the user wants both a session-local and system-wide view of leased resources.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# List Resources
|
|
8
|
+
|
|
9
|
+
Print two views in one call:
|
|
10
|
+
|
|
11
|
+
1. **Your active leases** — the `leases[]` array from `.syntaur/context.json` (this session's claims).
|
|
12
|
+
2. **All active leases in this workspace** — output of `syntaur lease list`, which shows every inventory plus its idle/leased counts.
|
|
13
|
+
|
|
14
|
+
This is the cheap "what am I holding, and what's out there?" lookup before deciding to extend, release, or grab another resource.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
User arguments: `$ARGUMENTS` (no arguments accepted in v1).
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
- `/list-resources`
|
|
22
|
+
|
|
23
|
+
## Workflow
|
|
24
|
+
|
|
25
|
+
### Step 1: Read this session's leases
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
jq -r '.leases // []' .syntaur/context.json 2>/dev/null
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
(No `dangerouslyDisableSandbox` needed — read-only.)
|
|
32
|
+
|
|
33
|
+
If `.syntaur/context.json` is missing or has no `leases` array, treat it as empty. Do NOT abort — listing is informational; the absence of session context is itself a useful signal.
|
|
34
|
+
|
|
35
|
+
For each entry, capture: `lease_id`, `inventory_slug`, `member_id`, `expires_at`, `claimed_at`, and any `metadata` (e.g. connection URL).
|
|
36
|
+
|
|
37
|
+
### Step 2: Run the system-wide overview
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
syntaur lease list
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
(Use `dangerouslyDisableSandbox: true` — the CLI reads `~/.syntaur/syntaur.db`.)
|
|
44
|
+
|
|
45
|
+
Capture stdout. If the CLI exits non-zero, surface the error message but still print whatever Step 1 produced.
|
|
46
|
+
|
|
47
|
+
### Step 3: Report back
|
|
48
|
+
|
|
49
|
+
Print two sections:
|
|
50
|
+
|
|
51
|
+
**Your active leases (from `.syntaur/context.json`):**
|
|
52
|
+
|
|
53
|
+
If the array is empty:
|
|
54
|
+
> "No leases held by this session."
|
|
55
|
+
|
|
56
|
+
Otherwise, one block per lease:
|
|
57
|
+
```
|
|
58
|
+
<lease_id>
|
|
59
|
+
inventory: <inventory_slug>/<member_id>
|
|
60
|
+
expires: <expires_at>
|
|
61
|
+
claimed: <claimed_at>
|
|
62
|
+
metadata: <metadata JSON, if any>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**All inventories in this workspace (from `syntaur lease list`):**
|
|
66
|
+
|
|
67
|
+
Paste the CLI output verbatim (one row per inventory with kind/idle/leased counts).
|
|
68
|
+
|
|
69
|
+
### Step 4: Suggest next actions if any leases are nearing expiry
|
|
70
|
+
|
|
71
|
+
If any session-local lease's `expires_at` is within the next 5 minutes, append:
|
|
72
|
+
> "Note: lease `<id>` expires at `<iso>` (within 5 minutes). Run `/extend-resource <id> --ttl <duration>` to keep it."
|
|
73
|
+
|
|
74
|
+
This is informational only — don't extend automatically.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release-resource
|
|
3
|
+
description: Release a Syntaur resource lease previously claimed via /claim-resource, freeing the member for the next claimant. Triggers on "/release-resource", "release this dev env", "drop the lease", "release my slot", "release all leases", or when the user is done with a claimed resource.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Release Resource
|
|
8
|
+
|
|
9
|
+
Release one or more active resource leases, removing them from `.syntaur/context.json` and freeing their members for the next claimant.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
User arguments: `$ARGUMENTS`
|
|
14
|
+
|
|
15
|
+
- `<lease_id>` — release a specific lease by id
|
|
16
|
+
- `--all` — release every active lease recorded in `.syntaur/context.json`
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
- `/release-resource cf3bd0a6-ba38-4a8c-a882-bdba9cabad80`
|
|
20
|
+
- `/release-resource --all`
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
### Step 1: Parse arguments
|
|
25
|
+
|
|
26
|
+
If `--all` is passed, build the list of `lease_id`s from `.syntaur/context.json`'s `leases: []` array. Otherwise the first positional argument is the single `lease_id` to release.
|
|
27
|
+
|
|
28
|
+
If there is no `lease_id` and `--all` was not passed, abort with: "Specify `<lease_id>` or use `--all`. Active leases: $(jq -r '.leases[]?.lease_id' .syntaur/context.json 2>/dev/null || echo 'none')."
|
|
29
|
+
|
|
30
|
+
### Step 2: Release each lease
|
|
31
|
+
|
|
32
|
+
For each `lease_id`:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
syntaur lease release "$LEASE_ID"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
(Use `dangerouslyDisableSandbox: true` since the CLI writes to `~/.syntaur/syntaur.db`.)
|
|
39
|
+
|
|
40
|
+
Outcomes:
|
|
41
|
+
|
|
42
|
+
| Result | Meaning | What to do |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| Exit 0 with `Released lease <id>.` | Normal release. | Continue. |
|
|
45
|
+
| Exit 1 with `lease ... is no longer active` | Stale lease (already expired/revoked). The slot has already been freed. | Still remove from `.syntaur/context.json` — the row is dead either way. Note the staleness in the final summary. |
|
|
46
|
+
| Exit 1 with `contention timeout; retry` | `LeaseContentionError`. | Retry once after ~1s; if it fails again, surface to the user. |
|
|
47
|
+
|
|
48
|
+
### Step 3: Remove the entry from `.syntaur/context.json`
|
|
49
|
+
|
|
50
|
+
Whether the CLI succeeded OR returned a stale-lease error, drop the matching record from `.syntaur/context.json` (stale leases are dead — keeping them in context is misleading):
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
jq --arg lid "$LEASE_ID" \
|
|
54
|
+
'.leases = ((.leases // []) | map(select(.lease_id != $lid)))' \
|
|
55
|
+
.syntaur/context.json > .syntaur/context.json.tmp \
|
|
56
|
+
&& mv .syntaur/context.json.tmp .syntaur/context.json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Step 4: Report back
|
|
60
|
+
|
|
61
|
+
For a single release: `Released <lease_id> (<inventory>/<member_id>).` or `Lease <id> was already stale; removed from context.`
|
|
62
|
+
|
|
63
|
+
For `--all`: print one line per lease, then a summary count: `Released N lease(s), M already stale.`
|
|
64
|
+
|
|
65
|
+
If no leases were recorded in context, say so explicitly.
|
|
@@ -60,6 +60,7 @@ If `.syntaur/context.json` exists in the current working directory, read it befo
|
|
|
60
60
|
- `workspaceRoot` — absolute path to the code workspace
|
|
61
61
|
- `sessionId` — real agent-runtime session id (never a synthesized UUID)
|
|
62
62
|
- `transcriptPath` — absolute path to the agent's rollout/transcript file, if known
|
|
63
|
+
- `leases` — array of active resource-lease records (managed by `/claim-resource` and `/release-resource`). Entry shape: `{ lease_id, inventory_slug, member_id, expires_at, metadata, claimed_at }`. Leases are NOT auto-released on session end or assignment completion in v1 — call `/release-resource` explicitly (or let the TTL expire).
|
|
63
64
|
|
|
64
65
|
## Required Reading Order
|
|
65
66
|
|