@hagicode/cli 0.1.0-dev.42.1.b13f8d2 → 0.1.0-dev.47.1.f8624d4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -8
- package/dist/chunks/main-CAH7GrRu.js +251 -0
- package/dist/cli.js +1 -1
- package/dist/main.js +1 -1
- package/package.json +4 -3
- package/resources/saga/.gitignore +1 -0
- package/resources/saga/manifest.json +12 -0
- package/resources/saga/prompts/acceptance.md +15 -0
- package/resources/saga/prompts/amend.md +10 -0
- package/resources/saga/prompts/goal.md +23 -0
- package/resources/saga/prompts/plan.md +16 -0
- package/resources/saga/prompts/research.md +16 -0
- package/resources/saga/prompts/run.md +18 -0
- package/skills/README.md +1 -0
- package/skills/hagi/SKILL.md +23 -2
- package/skills/hagi/agents/openai.yaml +2 -2
- package/skills/hagi/references/cli-usage.md +63 -6
- package/skills/hagi/references/local-development.md +10 -0
- package/skills/hagi/references/resource-lock.md +135 -0
- package/skills/hagi/references/saga.md +189 -0
- package/skills/hagi/references/session-data.md +14 -0
- package/skills/hagi/references/validation.md +6 -2
- package/dist/chunks/main-CGAPe6tb.js +0 -179
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./chunks/main-
|
|
2
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./chunks/main-CAH7GrRu.js");s.runCli().then(e=>{e!==0&&(process.exitCode=e)}).catch(e=>{const n=e instanceof Error?e.stack??e.message:String(e);process.stderr.write(`${n}
|
|
3
3
|
`),process.exitCode=s.EXIT_CODES.UNKNOWN});
|
package/dist/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./chunks/main-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./chunks/main-CAH7GrRu.js");exports.createCliApp=e.createCliApp;exports.runCli=e.runCli;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hagicode/cli",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.47.1.f8624d4",
|
|
4
4
|
"description": "HagiCode CLI for project, proposal, vault, chat, and AutoTask management.",
|
|
5
5
|
"homepage": "https://github.com/HagiCode-org/cli#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
19
|
"README.md",
|
|
20
|
-
"skills"
|
|
20
|
+
"skills",
|
|
21
|
+
"resources/saga"
|
|
21
22
|
],
|
|
22
23
|
"packageManager": "pnpm@12.16.1",
|
|
23
24
|
"engines": {
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
},
|
|
26
27
|
"scripts": {
|
|
27
28
|
"clean": "rimraf dist",
|
|
28
|
-
"build": "export NODE_OPTIONS=\"${NODE_OPTIONS:-} --max-old-space-size=8192\"; pnpm run clean && vite build",
|
|
29
|
+
"build": "export NODE_OPTIONS=\"${NODE_OPTIONS:-} --max-old-space-size=8192\"; pnpm run clean && vite build && node -e \"require('node:fs').chmodSync('dist/cli.js', 0o755)\"",
|
|
29
30
|
"dev": "tsx ./src/cli.ts",
|
|
30
31
|
"generate:grpc": "node ./buildTools/generate-grpc.mjs",
|
|
31
32
|
"generate:grpc:check": "node ./buildTools/generate-grpc.mjs --check",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*/runtime/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"files": {
|
|
4
|
+
".gitignore": "49f38d5fe88ca07cdf13680b2d4f8a8f55d9b871e88192ad25db08e5ec1476fa",
|
|
5
|
+
"prompts/acceptance.md": "11ca06794d0ec19e87d1a4e883a67014563e9750b9fa62a8bedd43a69d52ca65",
|
|
6
|
+
"prompts/amend.md": "be621d1221a85656851548aee1e9e9d78480288bd856baf1bdbf50cb3317f49b",
|
|
7
|
+
"prompts/goal.md": "a545b01c9f6010df661f02cf62ef9bcae527ccf329f304ea82ffdda239b118df",
|
|
8
|
+
"prompts/plan.md": "bcc4c0509f2971083775db2b3678f41c55f16e69deba2d994d3ed636f314d917",
|
|
9
|
+
"prompts/research.md": "2504283ea845440c7909ff1da20bfb70f846d55ca16565740168848cfb8060b1",
|
|
10
|
+
"prompts/run.md": "1193fbc45645b513bbd6e1017513b62a53286d1d60fd00df479cff15de7c785b"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# acceptance.md
|
|
2
|
+
|
|
3
|
+
## Instruction
|
|
4
|
+
Give every plan item one acceptance command. A separate verification worker runs it, so it must decide pass or fail by itself.
|
|
5
|
+
|
|
6
|
+
- One heading per item: `## <ID> <name>`, followed by one line `cmd: <command>`.
|
|
7
|
+
- The command runs from the project root (the folder that holds `.hagicode`), not from the saga root. Write `cd <dir> && ...` when it needs a subfolder. Exit code 0 means the item is done.
|
|
8
|
+
- The command must be able to fail. A command that always passes proves nothing.
|
|
9
|
+
- Every plan item has exactly one heading here, and every heading here is a plan item. If you change the command of an item that is already ticked, the next freeze reopens that item.
|
|
10
|
+
|
|
11
|
+
## Template
|
|
12
|
+
```
|
|
13
|
+
## <ID> <name>
|
|
14
|
+
cmd: <command to run from the project root>
|
|
15
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Folding an amendment into a saga
|
|
2
|
+
|
|
3
|
+
An amendment is a file under `<saga>/amendments/`. It is open while its `merged-in:` line is empty. Folding it in changes the planning artifacts only.
|
|
4
|
+
|
|
5
|
+
1. `hagi saga status <saga> --path <root> --json` reports the current `revision` N (0 means the saga was never frozen). The merge target is `r<N+1>`.
|
|
6
|
+
2. Read the amendment. Update `goal.md`, `research.md`, `acceptance.md` and `progress.md` so they agree with each other and with the amendment.
|
|
7
|
+
3. Items may be added or superseded (`- ~ <ID> <name> | superseded in r<N+1>: <reason>`), never deleted. Do not touch the ticks: when an item's acceptance command changes, the next freeze reopens it.
|
|
8
|
+
4. Do not decide new open questions yourself. List them under `## Open questions`.
|
|
9
|
+
5. In the amendment file set `merged-in: r<N+1>`.
|
|
10
|
+
6. Run `hagi saga check <saga> --phase plan --path <root>` and fix what it reports. Do not run `freeze`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# goal.md
|
|
2
|
+
|
|
3
|
+
## Instruction
|
|
4
|
+
Write the goal contract of the saga: what it must achieve, in what scope, with which safety rules.
|
|
5
|
+
|
|
6
|
+
- Every work item the saga will have must be checkable by a machine (a command that exits 0 when the item is done). Say so in the goal.
|
|
7
|
+
- Write the non-goals and the block conditions (when an item is blocked instead of forced).
|
|
8
|
+
- Do not write implementation details.
|
|
9
|
+
- Write in the language the user used for the objective.
|
|
10
|
+
- If `amendments/` holds files whose `merged-in:` line is empty, fold them in and set `merged-in: r<next revision>` in each file (see `prompts/amend.md`).
|
|
11
|
+
|
|
12
|
+
## Template
|
|
13
|
+
```
|
|
14
|
+
## Goal
|
|
15
|
+
|
|
16
|
+
## Scope
|
|
17
|
+
|
|
18
|
+
## Non-goals
|
|
19
|
+
|
|
20
|
+
## Safety rules
|
|
21
|
+
|
|
22
|
+
## Block conditions
|
|
23
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# progress.md (the plan)
|
|
2
|
+
|
|
3
|
+
## Instruction
|
|
4
|
+
List the work items, one line each: `- [ ] <ID> <name> | `. The evidence path is added when an item is ticked.
|
|
5
|
+
|
|
6
|
+
- Items are small enough to verify with one command, mostly independent, and ordered so that earlier items do not depend on later ones.
|
|
7
|
+
- Keep the list short enough to review (roughly 3 to 15 items). Use the user's work items as a start; add or split items only when needed.
|
|
8
|
+
- Do not add items for committing, pushing, opening a pull request, releasing or archiving: they are outside the contract.
|
|
9
|
+
- IDs match the headings of `acceptance.md`.
|
|
10
|
+
- In a revision an item may be added or superseded, never deleted. A superseded item is written without brackets: `- ~ <ID> <name> | superseded in r<N>: <reason>`.
|
|
11
|
+
- Planning ends here. Do not run `freeze`, do not start the run, do not edit project code.
|
|
12
|
+
|
|
13
|
+
## Template
|
|
14
|
+
```
|
|
15
|
+
- [ ] <ID> <name> |
|
|
16
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# research.md
|
|
2
|
+
|
|
3
|
+
## Instruction
|
|
4
|
+
Read the project and the references the user gave. Read only: change no project file.
|
|
5
|
+
|
|
6
|
+
- Record what you found: the layout, the existing conventions, the commands that run the tests, anything the plan depends on.
|
|
7
|
+
- List every decision you cannot make yourself under the heading `## Open questions` (the Chinese heading `## 待决问题` also works). One line per question, starting with `- `. Leave them undecided: a human answers them before the run by rewriting a line as `- [decided: <answer>] <question>` (or `- [已决定: <结论>] <问题>`).
|
|
8
|
+
- If there is nothing to decide, write `- none` under that heading.
|
|
9
|
+
- If an item has no honest verification command, say so here as an open question. Do not invent a check.
|
|
10
|
+
|
|
11
|
+
## Template
|
|
12
|
+
```
|
|
13
|
+
## Findings
|
|
14
|
+
|
|
15
|
+
## Open questions
|
|
16
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Running a saga (the orchestrator)
|
|
2
|
+
|
|
3
|
+
You are the orchestrator. You dispatch work and keep the record. You do not plan, you do not edit the contract, and you do not implement items yourself. A human started this run; starting it is the approval.
|
|
4
|
+
|
|
5
|
+
`<root>` is the registered project path given in the run's input. Every command is `hagi saga <command> <saga> --path <root>` and works from any directory. Every command that changes a Saga also takes `--token <token>`: the token that `claim` printed.
|
|
6
|
+
|
|
7
|
+
0. **Claim first.** `hagi saga claim <saga> --session <your session id> --path <root> --json`. Keep the printed token for every later command. If it refuses because another owner holds the Saga, stop and report it. Never take over by age, and never write a paused snapshot over another owner's progress.
|
|
8
|
+
1. **Freeze.** `hagi saga freeze <saga> --path <root> --token <token>`. If it refuses (open questions, open amendments, a changed contract), run `hagi saga set-status <saga> --state paused --note "<reason>" --path <root> --token <token>`, stop and report the reasons. Do not edit contract files and do not decide open questions. A first freeze writes revision 1. After an amendment was merged it writes the next revision, chained to the previous one, and reopens the items whose acceptance command changed.
|
|
9
|
+
2. **Check before every item and at every heartbeat.** `hagi saga assert-owner <saga> --path <root> --token <token>` before each dispatch, then `hagi saga check <saga> --phase run --path <root>`. If a check fails, pause the same way and report. An open amendment also means: pause.
|
|
10
|
+
3. **Work one item at a time** (`hagi saga items <saga> --path <root>` lists them with their commands), unless the goal allows parallel items. For each item:
|
|
11
|
+
- An implementation worker writes code and tests only. Give it the goal, the item, the scope and the safety rules, the project root and its report path.
|
|
12
|
+
- A separate verification worker runs the item's command from `acceptance.md` in the project root, writes the output to `<root>/.hagicode/sagas/<saga>/runtime/evidence/<ITEM>.log`, and writes `<root>/.hagicode/sagas/<saga>/runtime/reports/<ITEM>.md` with the line `Status: PASS` (or `状态: PASS`) only if the exit code is 0. It changes no files.
|
|
13
|
+
- Only `hagi saga tick <saga> <ITEM> --path <root> --token <token>` ticks an item. It refuses without a PASS report and an evidence file.
|
|
14
|
+
4. **On a failed verification, classify it.** An environment fault (missing module, port in use, quota) does not count. A real failure counts: give a tuning worker the failure log path, then verify again. After 3 real failures run `hagi saga block <saga> <ITEM> "<reason>" --path <root> --token <token>` and move on.
|
|
15
|
+
5. **After a revision reopened items,** also re-verify any item whose command is the full regression: its own command did not change, so it was not reopened.
|
|
16
|
+
6. **Keep the record.** Append a line to `<root>/.hagicode/sagas/<saga>/runtime/orchestrator-log.md` after every dispatch, verification and tick. Append every session you create to `<root>/.hagicode/sagas/<saga>/runtime/sessions.md`. Run `hagi saga set-status <saga> --state running --note "<heartbeat>" --path <root> --token <token>` at every heartbeat, and `hagi saga status <saga> --path <root> --json` to read the projection at the end.
|
|
17
|
+
7. **Never leave a command hanging.** Every shell command must end on its own: never read from standard input, and give waits a limit. If something does not answer, report it instead of waiting forever.
|
|
18
|
+
8. **Stop** when every item is ticked or blocked, when a pause condition appears, or when the human's run options say so. Write the terminal snapshot first (`set-status --state done` only when every active item is verified, otherwise `paused` with the reason), then, once every worker has stopped, `hagi saga release <saga> --path <root> --token <token> --workers-settled`. Do not archive and do not commit. Report the revision, every item with its state and evidence path, the blocked items with reasons, the sessions you created, and the next step for a human.
|
package/skills/README.md
CHANGED
|
@@ -28,6 +28,7 @@ Repository-local commands under `repos/cli` are maintainer workflows only.
|
|
|
28
28
|
- [`hagi/references/session-data.md`](hagi/references/session-data.md) - inside a HagiCode session: read-only data commands and the actions that need an explicit request
|
|
29
29
|
- [`hagi/references/proposal-flow.md`](hagi/references/proposal-flow.md) - explicit proposal lifecycle guidance
|
|
30
30
|
- [`hagi/references/openspec-workflow.md`](hagi/references/openspec-workflow.md) - the OpenSpec stage each proposal command starts and how to follow a run
|
|
31
|
+
- [`hagi/references/resource-lock.md`](hagi/references/resource-lock.md) - the shared resource lock: owner, exit codes, the watcher protocol and requisition rules
|
|
31
32
|
- [`hagi/references/super-commit.md`](hagi/references/super-commit.md) - Super Commit through the CLI: prompt-id start, options, result and explicit-request rule
|
|
32
33
|
- [`hagi/references/local-development.md`](hagi/references/local-development.md) - maintainer-only source-tree workflows
|
|
33
34
|
- [`hagi/references/validation.md`](hagi/references/validation.md) - post-change validation steps
|
package/skills/hagi/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hagi
|
|
3
|
-
description: Use when the user wants to run, verify, or update the HagiCode CLI against the Hagi API, or asks about their own projects, proposals, chat sessions, vaults, scheduled plans, or installed skills, including user skills versus built-in skills
|
|
3
|
+
description: Use when the user wants to run, verify, or update the HagiCode CLI against the Hagi API, use local Saga initialization, creation, checks, writes, or read-only queries, or asks about their own projects, proposals, chat sessions, vaults, scheduled plans, or installed skills, including user skills versus built-in skills and enabling or disabling a built-in skill. Also covers the OpenSpec workflow behind proposal commands and Super Commit, which commits a code repository through a HagiTask session. Keep package-first command guidance primary, then follow the Saga, proposal, local development, and validation references as needed. Inside a HagiCode session, read the session-data reference first for questions about the user's own data.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Hagi
|
|
@@ -11,8 +11,11 @@ Use this skill when the user asks to:
|
|
|
11
11
|
- list which installed skills are user skills and which are built-in skills, or which built-in skills are enabled
|
|
12
12
|
- enable or disable a built-in skill
|
|
13
13
|
- run or verify the `hagi` CLI
|
|
14
|
-
- explain or
|
|
14
|
+
- run, explain, or verify local `saga init`, `saga new`, `saga list`, `saga status`, or `saga items` operations
|
|
15
|
+
- run, explain, or verify local Saga ownership, checks, and writes: `claim`, `assert-owner`, `release`, `freeze`, `check`, `tick`, `block`, `set-status`, `amend`, `archive`
|
|
16
|
+
- explain or execute `project`, `proposal`, `chat`, `hagitask`, `vault`, `plan`, `skills`, or `saga` commands
|
|
15
17
|
- explain the OpenSpec workflow behind `proposal` commands, which stage each command starts, or how to follow a run until it settles
|
|
18
|
+
- take turns on a shared resource (a game server, a test environment) with other agents through `hagi agent lock`
|
|
16
19
|
- run, explain or check a Super Commit, which commits the uncommitted changes of a code repository through a HagiTask session
|
|
17
20
|
- inspect CLI flags, environment variables, exit codes, or JSON automation behavior
|
|
18
21
|
- validate proposal-session flows against a backend API
|
|
@@ -37,6 +40,8 @@ Use this skill when the user asks to:
|
|
|
37
40
|
5. Source-tree development in `repos/cli` -> read [`references/local-development.md`](references/local-development.md)
|
|
38
41
|
6. Post-change validation -> read [`references/validation.md`](references/validation.md)
|
|
39
42
|
7. The user's own data, inside a HagiCode session -> read [`references/session-data.md`](references/session-data.md)
|
|
43
|
+
8. Local Saga initialization, creation, list, status, item queries, ownership, checks, freeze, ticks, status writes, amendments, or archive -> read [`references/saga.md`](references/saga.md)
|
|
44
|
+
9. A shared resource that other agents also use, or any `hagi agent lock` command -> read [`references/resource-lock.md`](references/resource-lock.md)
|
|
40
45
|
|
|
41
46
|
When `hagi` is loaded as a built-in skill inside a HagiCode session, read item 7 first for any question about the user's own data or skills, before the other references.
|
|
42
47
|
|
|
@@ -81,6 +86,10 @@ The current top-level command families are:
|
|
|
81
86
|
- `hagitask`
|
|
82
87
|
- `plan`
|
|
83
88
|
- `skills`
|
|
89
|
+
- `agent`
|
|
90
|
+
- `saga`
|
|
91
|
+
|
|
92
|
+
`hagi saga` provides `init`, `new`, `list`, `status`, and `items`, plus the write and check commands `claim`, `assert-owner`, `release`, `freeze`, `check`, `tick`, `block`, `set-status`, `amend`, and `archive`; mutating commands take `--token` or `SAGA_EXECUTION_TOKEN`. With `--path`, these operate on host-local files without reading backend configuration or calling the API; `--project-id` resolves a project through the backend. See [`references/saga.md`](references/saga.md) for initialization, creation, offline behavior, and read-only query guarantees.
|
|
84
93
|
|
|
85
94
|
`project repositories --id <project-id>` is read-only. It lists one project's repositories with each path relative to the project root (for example `repos/cli`). Those paths are the values a proposal's `Repository scope` names; see [`references/proposal-flow.md`](references/proposal-flow.md#repository-scope).
|
|
86
95
|
|
|
@@ -90,6 +99,16 @@ HagiTask sessions (`hagi hagitask`) run a preset task with a structured input. `
|
|
|
90
99
|
|
|
91
100
|
Each family also reads one session by id. `proposal get` and `hagitask get` read a session; with `--wait` they poll until its status settles, so a run can be followed without guessing. `proposal messages` and `hagitask messages` read a session's messages, and `--last 1` reads the final message of a run. The stage behind each proposal command is in [`references/openspec-workflow.md`](references/openspec-workflow.md). Super Commit is started with `hagitask create --prompt-id auto-compose-commit.<locale>`; see [`references/super-commit.md`](references/super-commit.md).
|
|
92
101
|
|
|
102
|
+
## Resource lock
|
|
103
|
+
|
|
104
|
+
`hagi agent lock` is a fair queue lock for a resource that several agents share. Read [`references/resource-lock.md`](references/resource-lock.md) before the first lock command. The protocol is watcher-based:
|
|
105
|
+
|
|
106
|
+
- Pass your own session ID as the owner: `hagi agent lock acquire --lock-id eu-1/duckov --owner sess-7f2c`. Every example is `hagi agent lock ...`; there is no `hagi lock`.
|
|
107
|
+
- After `acquire`, read the windows. `Holding`: start the heartbeat watcher (a Monitor running `hagi agent lock heartbeat ...`, or a background process or sub-agent where there is no Monitor) before any work. `Queued`: start a continuous `hagi agent lock acquire --wait ...` watcher; do not sleep and re-check.
|
|
108
|
+
- When all tasks are done, stop the heartbeat watcher and then run `hagi agent lock release`. Stopping alone releases the lock after 10 minutes without a heartbeat; the lock is also taken back after 24 hours. The heartbeat interval is 2 minutes.
|
|
109
|
+
- When a watcher reports loss (exit code `32`), stop using the resource at once. After losing track (for example after compaction), repeat `acquire` with the same owner; it is safe.
|
|
110
|
+
- Never run `hagi agent lock requisition` unless the user explicitly ordered a forced take; nothing else is a requisition, and otherwise you always queue. When ordered, quote the request in `--reason`, start the heartbeat watcher and tell the user which owner was displaced. When you are displaced, stop at once, tell the user, queue again only if the task still needs the resource, and never requisition back. A displaced agent can use the resource until its next heartbeat (up to 2 minutes), and the lock cannot stop work already running on the resource.
|
|
111
|
+
|
|
93
112
|
## Source of truth
|
|
94
113
|
|
|
95
114
|
- Canonical writable skill source: `repos/cli/skills/hagi/`
|
|
@@ -102,5 +121,7 @@ Each family also reads one session by id. `proposal get` and `hagitask get` read
|
|
|
102
121
|
- [`references/proposal-flow.md`](references/proposal-flow.md) - explicit proposal lifecycle sequence and command examples
|
|
103
122
|
- [`references/openspec-workflow.md`](references/openspec-workflow.md) - the OpenSpec stage each proposal command starts, stage boundaries, who drives each step, and the monitoring rule
|
|
104
123
|
- [`references/super-commit.md`](references/super-commit.md) - Super Commit: starting it by prompt id, its options, result reading and the explicit-request rule
|
|
124
|
+
- [`references/resource-lock.md`](references/resource-lock.md) - the shared resource lock: numbers, owner, exit codes, the watcher protocol, the seven agent rules and requisition
|
|
125
|
+
- [`references/saga.md`](references/saga.md) - local initialization, creation, ownership, checks, Saga writes, and read-only queries
|
|
105
126
|
- [`references/local-development.md`](references/local-development.md) - maintainer-only development, build, and repository internals
|
|
106
127
|
- [`references/validation.md`](references/validation.md) - targeted verification after documentation or code changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Hagi CLI"
|
|
3
|
-
short_description: "
|
|
4
|
-
default_prompt: "Use $hagi to look up
|
|
3
|
+
short_description: "Operate the hagi CLI, including local Saga commands, and work with HagiCode data, skills, proposals, and Super Commit."
|
|
4
|
+
default_prompt: "Use $hagi to operate local Saga init, new, list, status, or items commands and the Saga ownership, check, freeze, tick, set-status, amend, and archive commands; look up HagiCode projects, proposals, sessions, vaults, plans, or skills; follow a proposal's OpenSpec workflow; run a Super Commit; enable or disable a built-in skill; or inspect, run, or update the CLI in repos/cli."
|
|
5
5
|
|
|
6
6
|
policy:
|
|
7
7
|
allow_implicit_invocation: true
|
|
@@ -35,6 +35,7 @@ For one-off execution, replace `hagi` with `npx @hagicode/cli`.
|
|
|
35
35
|
hagi --help
|
|
36
36
|
hagi project list --json
|
|
37
37
|
hagi proposal list --json
|
|
38
|
+
hagi saga list --path .
|
|
38
39
|
hagi chat list --json
|
|
39
40
|
hagi hagitask list --json
|
|
40
41
|
hagi hagitask create --title "Auto commit" --project-id <project-id> --prompt-id auto-compose-commit.en-US
|
|
@@ -55,9 +56,11 @@ Example:
|
|
|
55
56
|
hagi --base-url https://api.example.com --token "$HAGI_TOKEN" project list --json
|
|
56
57
|
```
|
|
57
58
|
|
|
59
|
+
Saga commands using `--path` accept these flags but do not read backend configuration or contact the backend.
|
|
60
|
+
|
|
58
61
|
## Environment variables
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
Backend operations resolve runtime settings centrally before accessing the API.
|
|
61
64
|
Explicit flags always override environment variables.
|
|
62
65
|
|
|
63
66
|
| Variable | Purpose |
|
|
@@ -78,7 +81,9 @@ The base URL can also be stored in a local config file:
|
|
|
78
81
|
The file is `$XDG_CONFIG_HOME/hagi/config.json`, or `~/.config/hagi/config.json` when `XDG_CONFIG_HOME` is unset. The `steer` key must be `true` or `false`; any other value exits with code `2` and names the file.
|
|
79
82
|
|
|
80
83
|
Base URL precedence, highest first: `--base-url`, then `HAGI_API_BASE_URL`, then `baseUrl` in the config file.
|
|
81
|
-
There is no default. When none of the three is set,
|
|
84
|
+
There is no default. When none of the three is set, a backend operation exits with code `2` and names all three sources.
|
|
85
|
+
The local Saga selector `--path` is the exception: it does not read this file, so malformed, unreachable, or absent backend
|
|
86
|
+
settings do not affect that local operation.
|
|
82
87
|
|
|
83
88
|
## Command overview
|
|
84
89
|
|
|
@@ -87,16 +92,45 @@ hagi
|
|
|
87
92
|
|-- project list | repositories | create | update | delete
|
|
88
93
|
| `-- monospecs show | init | set | validate | reload | clone | remove-checkout
|
|
89
94
|
|-- proposal list | create | optimize-description | generate | annotate | execute | archive | status | complete | send | get | messages
|
|
95
|
+
|-- saga init | new | list | status | items | claim | assert-owner | release | freeze | check | tick | block | set-status | amend | archive
|
|
90
96
|
|-- vault list | create | update | delete
|
|
91
97
|
| `-- files list | preview
|
|
92
98
|
|-- chat list | create | archive | delete | send
|
|
93
99
|
|-- hagitask list | schema | create | send | get | messages
|
|
94
100
|
|-- plan list | get | create | update | enable | disable | delete | run
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
|-- skills local list | enable | disable | uninstall
|
|
102
|
+
| gallery search | detail | install
|
|
103
|
+
| trusted list | upsert | delete | reset
|
|
104
|
+
`-- agent lock acquire | status | renew | heartbeat | release | requisition | list
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Saga commands
|
|
108
|
+
|
|
109
|
+
Each command requires exactly one nonempty project selector:
|
|
110
|
+
|
|
111
|
+
- `--path <directory>` resolves a local directory on the CLI host. Relative paths use the current working directory. This
|
|
112
|
+
selector does not read backend configuration or make API calls, and shared backend flags do not change its behavior.
|
|
113
|
+
- `--project-id <id>` reads the project list through the configured backend. Its project path must be a directory available
|
|
114
|
+
on the machine running the CLI; the CLI does not execute filesystem operations remotely.
|
|
115
|
+
|
|
116
|
+
Missing, empty, or conflicting selectors exit `2` before backend access or file writes. Paths with spaces should be quoted.
|
|
117
|
+
Shared `--base-url`, `--token`, `--lang`, and `--json` options are accepted.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
hagi saga init --path "./My Project"
|
|
121
|
+
hagi saga new demo --path "./My Project" --json
|
|
122
|
+
hagi saga list --path "./My Project"
|
|
123
|
+
hagi saga status demo --project-id <project-id> --json
|
|
124
|
+
hagi saga items demo --path "./My Project" --json
|
|
125
|
+
hagi saga claim demo --path "./My Project" --session orchestrator-1 --json
|
|
126
|
+
hagi saga check demo --path "./My Project" --phase run --json
|
|
127
|
+
hagi saga tick demo T1 --path "./My Project" --token "$SAGA_EXECUTION_TOKEN" --json
|
|
98
128
|
```
|
|
99
129
|
|
|
130
|
+
For offline use, invoke an installed package or a package already present in the `npx` cache. An uncached
|
|
131
|
+
`npx @hagicode/cli` command may need network access to download the package; the local `--path` operation itself does not
|
|
132
|
+
need backend access.
|
|
133
|
+
|
|
100
134
|
## Project repositories
|
|
101
135
|
|
|
102
136
|
`project repositories --id <project-id>` is read-only. It reads the same aggregation snapshot as `project list` and prints one project's repositories: name, path relative to the project root (for example `repos/cli`), display name, type and branch, with the project's MonoSpecs flag. The `path` values are the ones a proposal's `Repository scope` names.
|
|
@@ -280,6 +314,28 @@ hagi skills local disable --skill-name hagi --json
|
|
|
280
314
|
- Skill recommendation and install progress streaming are not part of the CLI. `skills gallery search`, `detail` and `install` are the discovery and install path.
|
|
281
315
|
- `skills gallery detail` adds skills.sh audit ratings. `--json` keeps the detail fields and adds `audit: { providers: [...] }`, one entry per provider with `provider` and, when supplied, `risk`, `alerts`, `score` and `analyzedAt`. Human output appends one `skills.sh audit (<provider>)` line per provider, with `--` for missing values. If the audit fails or has no data, the command still exits `0` and `audit.providers` is `[]`. A detail failure fails the command as before. The audit never changes the install command preview or installability.
|
|
282
316
|
|
|
317
|
+
## Agent lock commands
|
|
318
|
+
|
|
319
|
+
`hagi agent lock` takes turns on a shared resource with other agents. The full protocol, the numbers and the seven agent rules are in [`resource-lock.md`](resource-lock.md); read it before using these commands. There is no top-level `hagi lock`.
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
hagi agent lock acquire --lock-id eu-1/duckov --owner sess-7f2c
|
|
323
|
+
hagi agent lock acquire --server eu-1 --game duckov --owner sess-7f2c --wait --timeout 900
|
|
324
|
+
hagi agent lock status --lock-id eu-1/duckov --owner sess-7f2c --json
|
|
325
|
+
hagi agent lock heartbeat --lock-id eu-1/duckov --owner sess-7f2c --epoch 7
|
|
326
|
+
hagi agent lock renew --lock-id eu-1/duckov --owner sess-7f2c --epoch 7
|
|
327
|
+
hagi agent lock release --lock-id eu-1/duckov --owner sess-7f2c --epoch 7
|
|
328
|
+
hagi agent lock requisition --lock-id eu-1/duckov --owner sess-7f2c --reason "User order: take the lock now"
|
|
329
|
+
hagi agent lock list --prefix eu-1/
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
- Name the lock with `--lock-id <id>` or with `--server <name> --game <name>` (not both forms). The owner is your own session ID, passed as `--owner`; without it the CLI reads `HAGI_LOCK_OWNER`, then `HAGI_SESSION_ID`, and otherwise exits `2`.
|
|
333
|
+
- `acquire` takes `--wait`, `--timeout <seconds>` (default 900, needs `--wait`), `--lease-seconds <n>` and `--label <text>`. Without `--wait` it exits `0` for `Holding` and `Queued`. With `--wait` it exits `0` only when the owner holds the lock, `31` on timeout and `32` when the queue entry was dropped.
|
|
334
|
+
- `status` takes `--wait-seconds <n>`. `renew` and `heartbeat` take `--epoch <n>` and `--lease-seconds <n>`; `heartbeat` also takes `--interval <seconds>` (default 120) and `--verbose`. `release` takes `--epoch <n>`. `requisition` requires `--reason <text>` and takes `--label <text>`. `list` takes `--prefix <text>`.
|
|
335
|
+
- `heartbeat` is long-running and quiet on success. Run it under a watcher; it exits `32` when the lock is lost and `0` when stopped, without releasing.
|
|
336
|
+
- Timing: 10-minute feedback timeout, 24-hour maximum hold, 2-minute heartbeat interval, 30-second claim window, 60-second waiter TTL.
|
|
337
|
+
- Never run `requisition` unless the user explicitly ordered a forced take.
|
|
338
|
+
|
|
283
339
|
## Exit codes
|
|
284
340
|
|
|
285
341
|
Stable non-zero exits used by the CLI. The HTTP numbers are the equivalents of the gRPC status the backend answered with:
|
|
@@ -293,7 +349,8 @@ Stable non-zero exits used by the CLI. The HTTP numbers are the equivalents of t
|
|
|
293
349
|
| `24` | HTTP 404 |
|
|
294
350
|
| `29` | HTTP 409 |
|
|
295
351
|
| `30` | Operation failed: the backend returned a refusal, for example `skills local enable` or `disable` on a name that is not a built-in skill, an invalid MonoSpecs configuration, or a failed MonoSpecs clone |
|
|
296
|
-
| `31` | Wait timed out: `--wait` on `proposal get` or `
|
|
352
|
+
| `31` | Wait timed out: `--wait` on `proposal get`, `hagitask get` or `agent lock acquire` reached `--timeout` before the session settled. The last status is printed. Not a success, and not a backend error |
|
|
353
|
+
| `32` | Lock lost: a `hagi agent lock` command learned that the owner no longer holds the lock (expired, taken back at the 24-hour cap, stale epoch, requisitioned). Stop using the resource. Distinct from `31` |
|
|
297
354
|
| `40` | Other HTTP 4xx |
|
|
298
355
|
| `50` | HTTP 5xx |
|
|
299
356
|
| `60` | Transport or connection failure |
|
|
@@ -63,6 +63,16 @@ The DTO types in `src/generated/api/models` are committed and maintained by hand
|
|
|
63
63
|
generated: the backend's OpenAPI document now lists only the retained REST routes, so regenerating from it would delete the
|
|
64
64
|
types of every removed route. When a proto DTO changes, edit or add the matching type there.
|
|
65
65
|
|
|
66
|
+
## Saga asset bundle
|
|
67
|
+
|
|
68
|
+
The Saga resources are owned by this repository. `resources/saga/` contains the six method prompt files, `.gitignore`,
|
|
69
|
+
and `manifest.json`; there is no standalone Saga tool and no sync step. Keep the bytes raw: do not render templates or
|
|
70
|
+
normalize line endings. The manifest uses schema version `1` and sorted POSIX relative paths mapped to lowercase SHA-256
|
|
71
|
+
digests; it does not hash itself.
|
|
72
|
+
|
|
73
|
+
After editing a prompt, update its digest in `manifest.json`. `tests/runtime/saga/assets.test.ts` fails on any mismatch
|
|
74
|
+
between the files and the manifest, and `pnpm run pack:check` verifies the published contents.
|
|
75
|
+
|
|
66
76
|
## Release automation
|
|
67
77
|
|
|
68
78
|
GitHub workflows under `.github/workflows/` handle release drafting and npm publishing.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Resource lock
|
|
2
|
+
|
|
3
|
+
`hagi agent lock` lets several agents take turns on one shared resource, for example a game server that only one agent may deploy to or test on at a time. The lock is a fair queue held by the backend. It is cooperative: it cannot stop an action that is already running on the remote resource, so every agent has to follow the protocol below.
|
|
4
|
+
|
|
5
|
+
Every command is `hagi agent lock <verb>`. There is no top-level `hagi lock`. When the package is not installed, replace `hagi` with `npx @hagicode/cli`.
|
|
6
|
+
|
|
7
|
+
## Numbers
|
|
8
|
+
|
|
9
|
+
| Number | Value | Meaning |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| Feedback timeout | 10 minutes | A holder that sends no heartbeat for 10 minutes loses the lock. Stopping the heartbeat alone releases the lock after this time. |
|
|
12
|
+
| Maximum hold | 24 hours | Absolute, counted from the grant. The lock is taken back at the cap even when heartbeats keep arriving. |
|
|
13
|
+
| Heartbeat interval | 2 minutes (120 s) | How often `heartbeat` renews. One lost beat is survivable. |
|
|
14
|
+
| Claim window | 30 seconds | After a handoff the new holder must confirm (status, renew or acquire) within 30 s, or the lock moves on. A watcher confirms at once. |
|
|
15
|
+
| Waiter TTL | 60 seconds | A queued owner that is not polling for 60 s is dropped from the queue. |
|
|
16
|
+
| Default wait timeout | 900 seconds | `acquire --wait` gives up after this long. Change it with `--timeout <seconds>`. |
|
|
17
|
+
|
|
18
|
+
`--lease-seconds` can request a shorter feedback timeout (30 to 600 seconds, never more than 10 minutes).
|
|
19
|
+
|
|
20
|
+
## Addressing and owner
|
|
21
|
+
|
|
22
|
+
- Name the lock with `--lock-id <id>` (for example `eu-1/duckov`) or with the pair `--server <name> --game <name>`, which means `<server>/<game>`. Do not mix the two forms.
|
|
23
|
+
- The owner is **your own session ID**: pass it as `--owner <id>`, for example `--owner sess-7f2c`. When `--owner` is absent the CLI reads `HAGI_LOCK_OWNER`, then `HAGI_SESSION_ID`. With none of the three it exits `2` and makes no request. The CLI never invents an owner ID.
|
|
24
|
+
- Use the same owner ID for every command about one lock. Two agents that share one owner ID act as one owner, and nothing detects that.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
hagi agent lock acquire --lock-id eu-1/duckov --owner sess-7f2c
|
|
28
|
+
hagi agent lock acquire --server eu-1 --game duckov --owner sess-7f2c --label "deploy test build" --json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
| Command | Use |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `hagi agent lock acquire` | Take the lock or join the queue. Without `--wait` it is one call and exits `0` for both `Holding` and `Queued`. With `--wait` it waits for the turn and exits `0` only when you hold the lock. It has no force option. Options: `--wait`, `--timeout <seconds>`, `--lease-seconds <n>`, `--label <text>`. |
|
|
36
|
+
| `hagi agent lock status` | Read your own state: `Holding`, `Queued`, `Expired`, `Requisitioned` or `None`. Exit `0` for all of them. `--wait-seconds <n>` is a long poll (the server caps it at 25). |
|
|
37
|
+
| `hagi agent lock heartbeat` | Keep a held lock alive. Long-running and quiet on success; run it under a watcher. Options: `--epoch <n>`, `--interval <seconds>`, `--lease-seconds <n>`, `--verbose`. |
|
|
38
|
+
| `hagi agent lock renew` | One renewal, a single heartbeat. Prefer `heartbeat`. Options: `--epoch <n>`, `--lease-seconds <n>`. |
|
|
39
|
+
| `hagi agent lock release` | Give the lock back or leave the queue. Exit `0` whether or not something was released. Option: `--epoch <n>`. |
|
|
40
|
+
| `hagi agent lock requisition` | Emergency take that displaces the holder. Only on an explicit user order (rules 6 and 7). Requires `--reason <text>`; option `--label <text>`. |
|
|
41
|
+
| `hagi agent lock list` | List locks that have a holder or a queue. Option: `--prefix <text>`. |
|
|
42
|
+
|
|
43
|
+
Every command except `list` also takes `--lock-id`, `--server`, `--game` and `--owner`; all seven take the shared `--json` option. The answers carry the expected-time windows: when the lock is valid until, the hard cap, the check-in window and, for a queued owner, the turn window. Times are server times; they are guidance for when to expect something, not wake-up schedules. An epoch identifies one grant; the `acquire` answer prints it, and `heartbeat` reads it itself when `--epoch` is omitted.
|
|
44
|
+
|
|
45
|
+
## Exit codes
|
|
46
|
+
|
|
47
|
+
| Exit code | Meaning |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `0` | Success. For `acquire --wait`: you hold the lock (your turn). For `heartbeat`: it was stopped by SIGINT or SIGTERM (the lock is not released). |
|
|
50
|
+
| `2` | Usage error: missing owner, conflicting lock addressing, a bad number, `--timeout` without `--wait`. No request was sent. |
|
|
51
|
+
| `20` / `21` / `23` / `24` / `29` | Backend refusal: invalid argument (for example a bad lock ID, owner or reason), unauthenticated, permission denied, not found, conflict. |
|
|
52
|
+
| `30` | `acquire --wait` was interrupted (the queue entry is released), or the backend refused the operation. |
|
|
53
|
+
| `31` | Wait timeout: `acquire --wait` reached `--timeout` without the turn. The queue entry it created was released. |
|
|
54
|
+
| `32` | `LOCK_LOST`: the lock is no longer yours (lease expired, taken back at the 24-hour cap, stale epoch, not the holder, or requisitioned). Stop using the resource at once. Distinct from `31`. Printed by `heartbeat`, `renew`, and by `acquire --wait` when the queue entry was dropped. |
|
|
55
|
+
| `40` / `50` | Other HTTP 4xx / HTTP 5xx equivalent. |
|
|
56
|
+
| `60` | Transport failure. A watcher retries these itself and never treats them as loss. |
|
|
57
|
+
| `70` | Unknown error. |
|
|
58
|
+
|
|
59
|
+
## The watcher protocol
|
|
60
|
+
|
|
61
|
+
A watcher is a long-running command whose output lines reach you as notifications. Use a Monitor that runs the command. Where there is no Monitor, run the same command as a background process whose output you read, or in a background sub-agent that reports back. State the rule in terms of what the watcher must do; the provider's tool is a detail.
|
|
62
|
+
|
|
63
|
+
### 1. Acquire, read the windows, start the heartbeat watcher
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
hagi agent lock acquire --lock-id eu-1/duckov --owner sess-7f2c --label "deploy test build"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Read the status and the windows in the answer.
|
|
70
|
+
|
|
71
|
+
- `Holding`: start the heartbeat watcher **before any work**, and keep it running while you use the resource.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
hagi agent lock heartbeat --lock-id eu-1/duckov --owner sess-7f2c --epoch 7
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
It beats at once, then every 2 minutes. It prints one start line, then nothing while all is well. It prints a line, and exits `32`, when the lock is lost. It warns once when the backend has been unreachable for over 60 seconds and again on recovery, says "may already be lost" when the lease deadline passed during an outage, and warns 30 minutes and 5 minutes before the 24-hour cap. `--verbose` adds one line per beat. A transport error is never reported as loss.
|
|
78
|
+
- `Queued`: start a continuous wait watcher and carry on with other work, or stop. Do not sleep until the window and then check.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
hagi agent lock acquire --lock-id eu-1/duckov --owner sess-7f2c --wait
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
It prints one line when your position changes, and exits `0` when the turn comes (start the heartbeat watcher then), `31` on timeout (default 900 s), `32` if the entry was dropped. Pass `--timeout <seconds>` for a different limit.
|
|
85
|
+
|
|
86
|
+
### 2. Finish: stop the heartbeat, then release
|
|
87
|
+
|
|
88
|
+
When all tasks are done, stop the heartbeat watcher, then release:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
hagi agent lock release --lock-id eu-1/duckov --owner sess-7f2c --epoch 7
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Stopping the heartbeat watcher (SIGINT or SIGTERM) exits `0` and does not release. Stopping alone also ends the hold, because the backend releases the lock after 10 minutes without feedback, but `release` hands the resource over at once.
|
|
95
|
+
|
|
96
|
+
### 3. Loss and recovery
|
|
97
|
+
|
|
98
|
+
When a watcher reports that the lock was lost, stop using the resource immediately. Retrying does not extend the 24-hour cap or the 10-minute timeout.
|
|
99
|
+
|
|
100
|
+
When you lose track of whether you hold the lock (for example after your context was compacted), run `acquire` again with the same owner. It is safe: the first acquire stays valid (same epoch, same 24-hour clock) and the answer gives the windows. It does **not** refresh the lease, so it is not a heartbeat. Then check that the heartbeat watcher is running, and start it if it is not.
|
|
101
|
+
|
|
102
|
+
## The seven rules for the agent
|
|
103
|
+
|
|
104
|
+
1. After an `acquire`, read the windows in the answer. If the status is `Holding`, start the heartbeat watcher (a Monitor running `hagi agent lock heartbeat ...`) before doing any work. Where Monitor is not available, run the same command as a background process or in a background sub-agent whose output you read.
|
|
105
|
+
2. If the status is `Queued`, start a continuous wait watcher (a Monitor, or a sub-agent, running `hagi agent lock acquire --wait ...`) and carry on with other work or stop. Do not sleep until the window and then check: the waiter TTL (60 s) would drop your queue entry and the claim window (30 s) would take back a handoff nobody noticed. The window is a guide to when to expect the turn, not a wake-up schedule.
|
|
106
|
+
3. When all tasks are done, stop the heartbeat watcher and then release the lock. Stopping the heartbeat alone is enough, because the backend releases the lock after 10 minutes without feedback, but `release` hands the resource over at once.
|
|
107
|
+
4. When a watcher reports that the lock was lost, stop using the resource immediately. The 24-hour cap and the 10-minute timeout are not extended by retrying.
|
|
108
|
+
5. If you lose track of whether you hold a lock (for example after your context is compacted), call `acquire` again with the same owner: it is safe, and the answer gives the windows. Then check that the heartbeat watcher is running.
|
|
109
|
+
6. Never requisition unless the user has explicitly told you to force-take the lock. Your own judgment that something is urgent is not enough, and nothing is a requisition without an explicit user order. In every other case, call `acquire` and wait in the queue.
|
|
110
|
+
7. When the user does order a requisition, run `requisition` with a reason that quotes the request, start the heartbeat watcher, and tell the user which owner was displaced. When you are the one displaced, stop using the resource immediately, tell the user, queue again only if your task still needs the resource, and never requisition back.
|
|
111
|
+
|
|
112
|
+
## Requisition
|
|
113
|
+
|
|
114
|
+
`requisition` takes the lock at once. It is its own command; `acquire` has no force option and `acquire --wait` never requisitions.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
hagi agent lock requisition --lock-id eu-1/duckov --owner sess-7f2c --reason "User order: 'take the duckov lock now, the demo starts in five minutes'"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- Run it only after the user has explicitly ordered a forced take (rule 6). Quote the order in `--reason` (1 to 200 characters). The displaced agent is shown the reason and the backend logs it.
|
|
121
|
+
- The answer prints the new epoch, the valid-until time and the windows. Start the heartbeat watcher at once (rule 7), then tell the user which owner was displaced.
|
|
122
|
+
- If you already hold the lock, nothing changes. Waiters keep their order. The displaced owner is not queued again.
|
|
123
|
+
- When you are displaced, your next heartbeat prints the requester, the time and the reason, and exits `32`. A status read shows `Requisitioned` for 10 minutes, then `None`. Stop at once, tell the user, queue again with `acquire` only if the task still needs the resource, and never requisition back.
|
|
124
|
+
- A displaced agent may keep using the resource until its next heartbeat, up to 2 minutes. The lock cannot stop work that is already running on the remote resource.
|
|
125
|
+
|
|
126
|
+
## Failure handling
|
|
127
|
+
|
|
128
|
+
| Situation | What happens |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| Holder crashes, or stops its heartbeat without releasing | After 10 minutes the lock goes to the head of the queue; the old owner reads `Expired`. |
|
|
131
|
+
| You never started a heartbeat watcher | The lock is released after 10 minutes; your next check-in reports loss. |
|
|
132
|
+
| The heartbeat watcher dies while you live | Same as above. Check the watcher after a long step. |
|
|
133
|
+
| The backend is unreachable | The heartbeat retries with 1 to 10 s backoff and warns after 60 s. It never reports loss by itself; the 10-minute timeout bounds the damage. |
|
|
134
|
+
| You sleep instead of watching in the queue | The waiter TTL (60 s) removes your entry; the next call reads `Expired` and you queue again at the back. |
|
|
135
|
+
| A slow old holder acts after being replaced | The epoch makes its renew and release fail; the new holder is unaffected. |
|