@hagicode/cli 0.1.0-dev.43.1.03d9a6a → 0.1.0-dev.48.1.ce630a8
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 +42 -4
- package/dist/chunks/main-_kYHYZ-C.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/hagi/SKILL.md +10 -3
- package/skills/hagi/agents/openai.yaml +2 -2
- package/skills/hagi/references/cli-usage.md +35 -2
- package/skills/hagi/references/local-development.md +10 -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-mvnmEVmb.js +0 -201
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-_kYHYZ-C.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-_kYHYZ-C.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.48.1.ce630a8",
|
|
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": "b43c8b58f191b9e0a0b54b6938c0aa4685d70b8f4ae2294c83a9ad6e728b7c0a",
|
|
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/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,7 +11,9 @@ 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
|
|
16
18
|
- take turns on a shared resource (a game server, a test environment) with other agents through `hagi agent lock`
|
|
17
19
|
- run, explain or check a Super Commit, which commits the uncommitted changes of a code repository through a HagiTask session
|
|
@@ -38,7 +40,8 @@ Use this skill when the user asks to:
|
|
|
38
40
|
5. Source-tree development in `repos/cli` -> read [`references/local-development.md`](references/local-development.md)
|
|
39
41
|
6. Post-change validation -> read [`references/validation.md`](references/validation.md)
|
|
40
42
|
7. The user's own data, inside a HagiCode session -> read [`references/session-data.md`](references/session-data.md)
|
|
41
|
-
8.
|
|
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)
|
|
42
45
|
|
|
43
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.
|
|
44
47
|
|
|
@@ -84,6 +87,9 @@ The current top-level command families are:
|
|
|
84
87
|
- `plan`
|
|
85
88
|
- `skills`
|
|
86
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.
|
|
87
93
|
|
|
88
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).
|
|
89
95
|
|
|
@@ -116,5 +122,6 @@ Each family also reads one session by id. `proposal get` and `hagitask get` read
|
|
|
116
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
|
|
117
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
|
|
118
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
|
|
119
126
|
- [`references/local-development.md`](references/local-development.md) - maintainer-only development, build, and repository internals
|
|
120
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,6 +92,7 @@ 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
|
|
@@ -98,6 +104,33 @@ hagi
|
|
|
98
104
|
`-- agent lock acquire | status | renew | heartbeat | release | requisition | list
|
|
99
105
|
```
|
|
100
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
|
|
128
|
+
```
|
|
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
|
+
|
|
101
134
|
## Project repositories
|
|
102
135
|
|
|
103
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.
|
|
@@ -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,189 @@
|
|
|
1
|
+
# Saga commands
|
|
2
|
+
|
|
3
|
+
Saga files are project-local. Select exactly one project with `--path <directory>` or `--project-id <id>` for every
|
|
4
|
+
Saga command. A local `--path` is resolved on the CLI host and does not read backend configuration or make API calls.
|
|
5
|
+
|
|
6
|
+
## Initialize managed resources
|
|
7
|
+
|
|
8
|
+
Run `init` before creating a Saga:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
hagi saga init --path "./My Project"
|
|
12
|
+
hagi saga init --path "./My Project" --force --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Initialization installs the six bundled method prompts and the ignore template under `.hagicode/sagas`. It does not repair
|
|
16
|
+
or overwrite existing Saga contracts, metadata, or runtime records.
|
|
17
|
+
|
|
18
|
+
By default, differing managed resources are preserved as conflicts while missing nonconflicting resources are still
|
|
19
|
+
installed. The command prints each file's `created`, `unchanged`, `merged`, `replaced`, or `conflict` outcome and exits
|
|
20
|
+
with code `4` if any conflicts remain. Use `--force` to replace differing managed resources with the bundled versions;
|
|
21
|
+
identical resources remain untouched. Forced initialization never discards custom `.gitignore` entries.
|
|
22
|
+
|
|
23
|
+
The `.gitignore` rule `**/runtime/` is merged as a separate exact line. Existing bytes, line endings, and entries are
|
|
24
|
+
preserved; LF and CRLF files are supported, and repeated initialization does not append duplicate rules.
|
|
25
|
+
|
|
26
|
+
Before writing, initialization checks that managed directories and files are not redirected, that resource targets are
|
|
27
|
+
regular files, and that writes will not replace unsafe hard-linked resources. Refused targets are reported as operation
|
|
28
|
+
failures rather than followed outside the selected project. Exact resources are not rewritten on repeat runs, preserving
|
|
29
|
+
their modes and modification times.
|
|
30
|
+
|
|
31
|
+
With `--json`, stdout contains the installation root, `force` setting, per-file `path`/`outcome` entries, and any
|
|
32
|
+
conflicts. A conflict report is still emitted before the command reports the code-4 error on stderr.
|
|
33
|
+
|
|
34
|
+
## Create and inspect Sagas
|
|
35
|
+
|
|
36
|
+
`new <saga-id>` creates the Saga natively: it reserves `<saga-id>/` with an exclusive directory creation and writes
|
|
37
|
+
`saga.json` with `id`, `createdAt`, and `method`. It writes no runtime file. IDs must
|
|
38
|
+
match `^[a-z0-9][a-z0-9-]{0,62}$`: one to 63 lowercase letters, digits, or hyphens, beginning with a letter or digit. The
|
|
39
|
+
reserved names are `prompts`, `tools`, `archive`, `runtime`, `amendments`, and `revisions`. Invalid IDs are usage errors
|
|
40
|
+
(code `2`). An existing active path or an archive entry whose name ends in `-<saga-id>` is a collision; creation is
|
|
41
|
+
refused with code `30` and neither Saga is changed. Concurrent creations of one ID leave exactly one Saga.
|
|
42
|
+
|
|
43
|
+
The `--json` result identifies the Saga directory and includes the metadata written to `saga.json`:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"id": "demo",
|
|
48
|
+
"directory": "/path/to/My Project/.hagicode/sagas/demo",
|
|
49
|
+
"metadata": {
|
|
50
|
+
"id": "demo",
|
|
51
|
+
"createdAt": "2026-01-01T00:00:00Z",
|
|
52
|
+
"method": 1
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The human result names the installed goal prompt and the four planning files to write. From the project root, the prompt is
|
|
58
|
+
`.hagicode/sagas/prompts/goal.md`; the planning files are `goal.md`, `research.md`, `acceptance.md`, and `progress.md`.
|
|
59
|
+
|
|
60
|
+
Then inspect the Saga with the read-only commands:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
hagi saga new demo --path "./My Project" --json
|
|
64
|
+
hagi saga status demo --path "./My Project" --json
|
|
65
|
+
hagi saga list --path "./My Project"
|
|
66
|
+
hagi saga items demo --path "./My Project" --json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Query payloads and read-only behavior
|
|
70
|
+
|
|
71
|
+
`list --json` returns `{ "sagas": [...] }`; each row contains `sagaId`, `state`, `revision`, `counts`, `openAmendments`,
|
|
72
|
+
and `updatedAt`. `items <saga-id> --json` returns `{ "sagaId": "...", "items": [...] }`, with each item carrying its
|
|
73
|
+
canonical `id`, `title`, `state`, `cmd`, and `note`.
|
|
74
|
+
|
|
75
|
+
`status <saga-id> --json` returns the `saga-status/2` projection directly, with `schema`, `sagaId`, `revision`, `state`,
|
|
76
|
+
`updatedAt`, `note`, `artifacts`, `nextArtifact`, `counts`, `openAmendments`, and `items`. It derives this view from the
|
|
77
|
+
Saga files; `updatedAt` is the time of this observation, not the execution heartbeat in `runtime/status.json`. The query
|
|
78
|
+
does not refresh or rewrite that stored status, and its default `note` is empty rather than a cached execution note.
|
|
79
|
+
|
|
80
|
+
All three queries are strictly read-only: they do not initialize or repair resources, create runtime files, run the Saga
|
|
81
|
+
tool, or execute acceptance commands. Missing optional draft files use canonical empty-data behavior; malformed or
|
|
82
|
+
unreadable existing data is reported instead of being repaired. ## Execution ownership and the token
|
|
83
|
+
|
|
84
|
+
`claim`, `assert-owner`, and `release` manage `runtime/execute.lock`. Every mutating command (`freeze`, `tick`, `block`,
|
|
85
|
+
`set-status`, `amend`, `archive`, `release`, `assert-owner`) reads the execution token from `--token <token>` or, when
|
|
86
|
+
that flag is absent, from `SAGA_EXECUTION_TOKEN`.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
hagi saga claim demo --path "./My Project" --session orchestrator-1
|
|
90
|
+
hagi saga assert-owner demo --path "./My Project" --token "$SAGA_EXECUTION_TOKEN"
|
|
91
|
+
hagi saga release demo --path "./My Project" --token "$SAGA_EXECUTION_TOKEN" --workers-settled --json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- `claim --session <id>` creates the lock exclusively and returns the token once, in the human output and as `token` in
|
|
95
|
+
JSON. A second claim is refused with code `1` and names the owning session. A lock is never taken over because of its
|
|
96
|
+
age, and a refused claim changes no file.
|
|
97
|
+
- While a lock exists, a mutating command needs the holder's token. A missing or different token is refused with exit
|
|
98
|
+
code `1` and changes no file. Without a lock, mutating commands run under their own gates, so a Saga created before ownership stays runnable.
|
|
99
|
+
- `assert-owner` exits `0` when no lock exists or the token matches, and `1` otherwise.
|
|
100
|
+
- `release` removes the lock only for the holder, with `--workers-settled`, and only when `runtime/status.json` records
|
|
101
|
+
`paused` or `done`. Any other case exits `1` and keeps the lock.
|
|
102
|
+
- `status`, `items`, `list`, and `check` need no token and never write.
|
|
103
|
+
- With `--project-id`, the root `--token` is the backend bearer token, so `--token` is rejected with `--project-id` as a
|
|
104
|
+
usage error (code `2`) that explains the rule. Pass the execution token through `SAGA_EXECUTION_TOKEN` instead. An execution token is never sent to the backend.
|
|
105
|
+
|
|
106
|
+
## Plan check and freeze
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
hagi saga check demo --path "./My Project" --phase plan
|
|
110
|
+
hagi saga check demo --path "./My Project" --phase run --json
|
|
111
|
+
hagi saga freeze demo --path "./My Project" --token "$SAGA_EXECUTION_TOKEN" --json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`check --phase plan` passes when `goal.md`, `research.md`, `acceptance.md`, and `progress.md` exist, `progress.md` has at
|
|
115
|
+
least one active item, every active item has an acceptance `cmd:`, and every acceptance entry names an active item.
|
|
116
|
+
`check --phase run` is the default; it adds the frozen-contract hash comparison, the amendment and open-question gates,
|
|
117
|
+
and the proof of every ticked item (an evidence file and a `Status: PASS` or `状态: PASS` report). Any other `--phase`
|
|
118
|
+
value is a usage error (code `2`). Checks write nothing.
|
|
119
|
+
|
|
120
|
+
`freeze` writes `contract.lock` revision 1 for a valid first contract. A repeat on an unchanged contract exits `0`, reports
|
|
121
|
+
the existing revision, and leaves the lock bytes intact. After a contract change, freeze writes revision N+1 only when an
|
|
122
|
+
amendment is merged into `rN+1` and no frozen item disappeared without a superseded row. The previous lock moves to
|
|
123
|
+
`revisions/rN.lock`, each ticked item whose acceptance command changed is reopened, and its evidence and report move to
|
|
124
|
+
`runtime/history/rN/`. Every refusal (open question, unmerged amendment, plan mismatch, tampered contract, removed item)
|
|
125
|
+
lists each reason, exits `1`, and writes nothing.
|
|
126
|
+
|
|
127
|
+
## Items, amendments, and archive
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
hagi saga tick demo T1 --path "./My Project" --token "$SAGA_EXECUTION_TOKEN" --json
|
|
131
|
+
hagi saga block demo T2 "tests keep failing" --path "./My Project" --token "$SAGA_EXECUTION_TOKEN"
|
|
132
|
+
hagi saga amend demo "Add retry" "Retry twice on timeout" --path "./My Project" --token "$SAGA_EXECUTION_TOKEN"
|
|
133
|
+
hagi saga archive demo --path "./My Project" --token "$SAGA_EXECUTION_TOKEN" --json
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- `tick` marks an active item done in `progress.md` as `- [x] <id> <title> | evidence/<id>.log`. It needs a PASS report at
|
|
137
|
+
`runtime/reports/<id>.md`, the evidence file, and a passing run check; otherwise it exits `1` and keeps `progress.md`.
|
|
138
|
+
A successful tick clears that item's blocker. Item IDs containing a path separator or `.`/`..` are refused before any
|
|
139
|
+
file access.
|
|
140
|
+
- `block` records a reason for an active item in `runtime/blocked.json`. An unknown item is refused. An empty reason is a
|
|
141
|
+
usage error (code `2`).
|
|
142
|
+
- `amend` appends the next numbered file, `amendments/<NNN>-<slug>.md`, with an empty `merged-in:` header; the new
|
|
143
|
+
amendment is open until the contract merges it. An empty title is a usage error (code `2`).
|
|
144
|
+
- `archive` moves a finished Saga (every active item done, no open amendment) to `archive/<date>-<saga-id>`. Use
|
|
145
|
+
`--force` to archive unfinished work. An existing destination is refused even with `--force`.
|
|
146
|
+
|
|
147
|
+
## Status snapshot
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
hagi saga set-status demo --state paused --note "freeze refused" --path "./My Project" --token "$SAGA_EXECUTION_TOKEN" --json
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`set-status --state` accepts `draft`, `planned`, `running`, `paused`, or `done`; any other value (or a missing value) is a
|
|
154
|
+
usage error (code `2`) and writes no file. The snapshot is the same `saga-status/2` projection that `status` reports, with
|
|
155
|
+
only `state` and `note` replaced. `planned` and `running` require the plan check to pass. `done` requires every active
|
|
156
|
+
item to be done with its evidence and PASS report, a frozen and unchanged contract, no open amendment, and no undecided
|
|
157
|
+
research question. A refusal exits `1`, lists its reasons, and leaves the stored `runtime/status.json` unchanged. The file
|
|
158
|
+
is replaced atomically, so a concurrent reader always sees a complete document.
|
|
159
|
+
|
|
160
|
+
## Exit codes and JSON
|
|
161
|
+
|
|
162
|
+
| Code | Meaning |
|
|
163
|
+
|------|---------|
|
|
164
|
+
| `0` | Success. |
|
|
165
|
+
| `1` | Refusal or failed check. Every reason is printed; nothing was changed. |
|
|
166
|
+
| `2` | Usage error: bad selector, missing or invalid argument, or `--token` with `--project-id`. |
|
|
167
|
+
| `4` | Init resource conflict (see above). |
|
|
168
|
+
| `24` | Saga or project not found. |
|
|
169
|
+
| `30` | Operation failed, including a `new` collision. |
|
|
170
|
+
|
|
171
|
+
Write and check commands accept `--json`. Success and refusal write one object to stdout:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{ "sagaId": "demo", "command": "tick", "ok": true, "itemId": "T1", "evidence": "evidence/T1.log" }
|
|
175
|
+
{ "sagaId": "demo", "command": "tick", "ok": false, "errors": ["no PASS report for T1: runtime/reports/T1.md must contain \"Status: PASS\""] }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Human output prints a one-line outcome and one line per refusal reason.
|
|
179
|
+
|
|
180
|
+
## Runtime ignore precondition
|
|
181
|
+
|
|
182
|
+
Before any command writes a file under a Saga's `runtime/` directory (`claim`, `set-status`, `tick`, `block`, and a
|
|
183
|
+
`freeze` that moves history), it makes sure `.hagicode/sagas/.gitignore` ignores runtime directories. An existing
|
|
184
|
+
`**/runtime/` line is kept byte for byte; otherwise `**/runtime/` is appended with the file's line endings.
|
|
185
|
+
If the ignore file cannot be written, the command stops before `runtime/` is created.
|
|
186
|
+
|
|
187
|
+
## Read-only projection and ownership
|
|
188
|
+
|
|
189
|
+
Every write and check command is implemented by the CLI and never executes a separate tool. The CLI installs only the method prompts and the ignore rule; there is no installed tool to run.
|
|
@@ -98,6 +98,19 @@ hagi plan list --json
|
|
|
98
98
|
hagi plan get --id <plan-id> --json
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
### Sagas
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
hagi saga list --project-id <project-id> --json
|
|
105
|
+
hagi saga status <saga-id> --project-id <project-id> --json
|
|
106
|
+
hagi saga items <saga-id> --project-id <project-id> --json
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
These queries read the selected project's Saga files without initializing or repairing them, refreshing runtime status,
|
|
110
|
+
or executing acceptance commands. Status is a fresh `saga-status/2` observation; its `updatedAt` is not the stored
|
|
111
|
+
execution heartbeat in `runtime/status.json`. `init` installs resources and `new` creates a Saga, so run either only
|
|
112
|
+
when the user explicitly asks for that change. Contract and lifecycle operations run through `hagi saga` with the execution token rules in `references/saga.md`.
|
|
113
|
+
|
|
101
114
|
### Skills
|
|
102
115
|
|
|
103
116
|
```bash
|
|
@@ -128,6 +141,7 @@ A question such as "what is in my plan" is not a request to run, enable, disable
|
|
|
128
141
|
| `chat` | `create`, `archive`, `delete`, `send` |
|
|
129
142
|
| `hagitask` | `create`, `send` |
|
|
130
143
|
| `plan` | `create`, `update`, `enable`, `disable`, `delete`, `run` |
|
|
144
|
+
| `saga` | `init`, `new` |
|
|
131
145
|
| `skills` | `local enable`, `local disable`, `local uninstall`, `gallery install`, `trusted upsert`, `trusted delete`, `trusted reset` |
|
|
132
146
|
|
|
133
147
|
A `send` or `run` starts agent work, and `execute` and `generate` start it too. Treat those as changes of the same kind.
|
|
@@ -135,11 +135,15 @@ If only a specific command changed, also verify that command's help directly.
|
|
|
135
135
|
|
|
136
136
|
## Package publish-surface check
|
|
137
137
|
|
|
138
|
-
Run this
|
|
138
|
+
Run this when `package.json`, publish contents, or release metadata changed. The Saga asset check and the package check
|
|
139
|
+
are offline:
|
|
139
140
|
|
|
140
141
|
```bash
|
|
141
142
|
cd repos/cli
|
|
143
|
+
pnpm exec vitest run tests/runtime/saga/assets.test.ts
|
|
142
144
|
pnpm run pack:check
|
|
143
145
|
```
|
|
144
146
|
|
|
145
|
-
The npm tarball ships `dist
|
|
147
|
+
The npm tarball ships `dist`, `README.md`, `skills/**`, and only
|
|
148
|
+
the allowlisted Saga resources, including the hidden `.gitignore` template. `pack:check` verifies the actual package
|
|
149
|
+
contents and rejects source maps or unexpected resource files.
|