@kylecheng3146/agent-ops 0.0.1
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/LICENSE +21 -0
- package/README.md +83 -0
- package/SECURITY.md +22 -0
- package/dist/packages/cli/src/args.js +322 -0
- package/dist/packages/cli/src/bin.js +290 -0
- package/dist/packages/cli/src/cli.js +80 -0
- package/dist/packages/cli/src/commands/config.js +8 -0
- package/dist/packages/cli/src/commands/doctor.js +32 -0
- package/dist/packages/cli/src/commands/index.js +16 -0
- package/dist/packages/cli/src/commands/init.js +65 -0
- package/dist/packages/cli/src/commands/review.js +71 -0
- package/dist/packages/cli/src/commands/task.js +141 -0
- package/dist/packages/cli/src/commands/trust.js +48 -0
- package/dist/packages/cli/src/commands/uninstall.js +58 -0
- package/dist/packages/cli/src/commands/update.js +58 -0
- package/dist/packages/cli/src/commands/verify.js +108 -0
- package/dist/packages/cli/src/output.js +53 -0
- package/dist/packages/cli/src/plan-output.js +28 -0
- package/dist/packages/cli/src/wizard.js +75 -0
- package/dist/runtime/src/adapters/claude/config.js +109 -0
- package/dist/runtime/src/adapters/claude/events.js +8 -0
- package/dist/runtime/src/adapters/claude/input.js +38 -0
- package/dist/runtime/src/adapters/claude/output.js +30 -0
- package/dist/runtime/src/adapters/codex/config.js +93 -0
- package/dist/runtime/src/adapters/codex/events.js +8 -0
- package/dist/runtime/src/adapters/codex/input.js +41 -0
- package/dist/runtime/src/adapters/codex/output.js +24 -0
- package/dist/runtime/src/config/explain.js +34 -0
- package/dist/runtime/src/config/load.js +25 -0
- package/dist/runtime/src/config/merge.js +170 -0
- package/dist/runtime/src/config/migrate.js +61 -0
- package/dist/runtime/src/contracts.js +1 -0
- package/dist/runtime/src/discovery/go.js +145 -0
- package/dist/runtime/src/discovery/index.js +40 -0
- package/dist/runtime/src/discovery/make.js +162 -0
- package/dist/runtime/src/discovery/node.js +175 -0
- package/dist/runtime/src/discovery/python.js +163 -0
- package/dist/runtime/src/discovery/rust.js +159 -0
- package/dist/runtime/src/discovery/types.js +1 -0
- package/dist/runtime/src/fs/hash.js +19 -0
- package/dist/runtime/src/fs/managed-block.js +90 -0
- package/dist/runtime/src/fs/manifest.js +24 -0
- package/dist/runtime/src/fs/mutation-worker.js +185 -0
- package/dist/runtime/src/fs/paths.js +96 -0
- package/dist/runtime/src/fs/transaction.js +498 -0
- package/dist/runtime/src/guardrails/destructive.js +207 -0
- package/dist/runtime/src/guardrails/evaluate.js +9 -0
- package/dist/runtime/src/guardrails/exceptions.js +49 -0
- package/dist/runtime/src/guardrails/secrets.js +97 -0
- package/dist/runtime/src/guardrails/types.js +9 -0
- package/dist/runtime/src/hooks/dispatch.js +78 -0
- package/dist/runtime/src/hooks/events.js +1 -0
- package/dist/runtime/src/hooks/hook-entry.js +19 -0
- package/dist/runtime/src/hooks/normalize.js +59 -0
- package/dist/runtime/src/hooks/output.js +12 -0
- package/dist/runtime/src/hooks/shell.js +138 -0
- package/dist/runtime/src/hooks/stop-verify.js +70 -0
- package/dist/runtime/src/install/apply.js +70 -0
- package/dist/runtime/src/install/doctor.js +196 -0
- package/dist/runtime/src/install/harness.js +87 -0
- package/dist/runtime/src/install/ownership.js +84 -0
- package/dist/runtime/src/install/plan.js +257 -0
- package/dist/runtime/src/install/profiles.js +28 -0
- package/dist/runtime/src/install/types.js +1 -0
- package/dist/runtime/src/install/uninstall.js +206 -0
- package/dist/runtime/src/install/update.js +123 -0
- package/dist/runtime/src/logging/local-log.js +158 -0
- package/dist/runtime/src/registry/npm.js +141 -0
- package/dist/runtime/src/review/claude-runner.js +4 -0
- package/dist/runtime/src/review/codex-runner.js +4 -0
- package/dist/runtime/src/review/packet.js +10 -0
- package/dist/runtime/src/review/result.js +24 -0
- package/dist/runtime/src/review/roles.js +3 -0
- package/dist/runtime/src/review/runner.js +45 -0
- package/dist/runtime/src/schema/validate.js +584 -0
- package/dist/runtime/src/security/permissions.js +654 -0
- package/dist/runtime/src/security/redact.js +41 -0
- package/dist/runtime/src/security/trust.js +209 -0
- package/dist/runtime/src/task/render.js +43 -0
- package/dist/runtime/src/task/service.js +235 -0
- package/dist/runtime/src/task/store.js +265 -0
- package/dist/runtime/src/verify/change-surface.js +86 -0
- package/dist/runtime/src/verify/evidence.js +89 -0
- package/dist/runtime/src/verify/fingerprint.js +67 -0
- package/dist/runtime/src/verify/scope.js +69 -0
- package/dist/runtime/src/verify/service.js +217 -0
- package/dist/runtime/src/verify/spawn.js +326 -0
- package/dist/runtime/src/verify/test-count.js +148 -0
- package/docs/en/spec/README.md +13 -0
- package/docs/en/spec/acceptance-and-evidence.md +21 -0
- package/docs/en/spec/delegation.md +21 -0
- package/docs/en/spec/guardrails.md +21 -0
- package/docs/en/spec/harness-adapters.md +21 -0
- package/docs/en/spec/judgment.md +21 -0
- package/docs/en/spec/loop-engineering.md +23 -0
- package/docs/en/spec/maintenance.md +21 -0
- package/docs/en/spec/review.md +21 -0
- package/docs/en/spec/troubleshooting.md +21 -0
- package/docs/zh-TW/spec/README.md +13 -0
- package/docs/zh-TW/spec/acceptance-and-evidence.md +23 -0
- package/docs/zh-TW/spec/delegation.md +23 -0
- package/docs/zh-TW/spec/guardrails.md +23 -0
- package/docs/zh-TW/spec/harness-adapters.md +23 -0
- package/docs/zh-TW/spec/judgment.md +23 -0
- package/docs/zh-TW/spec/loop-engineering.md +23 -0
- package/docs/zh-TW/spec/maintenance.md +23 -0
- package/docs/zh-TW/spec/review.md +23 -0
- package/docs/zh-TW/spec/troubleshooting.md +23 -0
- package/package.json +41 -0
- package/schemas/config.schema.json +231 -0
- package/schemas/evidence.schema.json +115 -0
- package/schemas/manifest.schema.json +116 -0
- package/schemas/task.schema.json +59 -0
- package/templates/common/AGENTS.block.md +3 -0
- package/templates/common/CLAUDE.block.md +3 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kyle Cheng
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Loop Engineering Toolkit
|
|
2
|
+
|
|
3
|
+
Loop Engineering Toolkit is an evidence-driven development-loop toolkit for
|
|
4
|
+
Codex and Claude Code. It is designed to turn acceptance criteria, explicit
|
|
5
|
+
verification, safe lifecycle hooks, and independent review into a repeatable
|
|
6
|
+
engineering workflow.
|
|
7
|
+
|
|
8
|
+
This repository is in its foundation stage. The CLI, hook runtime, normative
|
|
9
|
+
specification, and installation profiles are being developed in a reviewable
|
|
10
|
+
feature branch before the first pre-1.0 release.
|
|
11
|
+
|
|
12
|
+
The current CLI is an unreleased development interface. Its packed artifact is
|
|
13
|
+
checked by `npm run package:check`; command behavior may change before the first
|
|
14
|
+
tagged pre-1.0 release.
|
|
15
|
+
|
|
16
|
+
## Quick start from a source checkout
|
|
17
|
+
|
|
18
|
+
Version 0.1.0 is prepared for release but has not yet been published to npm.
|
|
19
|
+
Until the protected release workflow completes, use a source checkout:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
git clone https://github.com/kylecheng3146/agent-ops.git
|
|
23
|
+
cd agent-ops
|
|
24
|
+
npm ci
|
|
25
|
+
npm run build
|
|
26
|
+
node dist/packages/cli/src/bin.js --version
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Preview a project installation before changing files:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
node dist/packages/cli/src/bin.js init \
|
|
33
|
+
--dry-run --scope project --harness both --profile core --json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
After reviewing the plan, apply it explicitly with `--yes`. Trust, diagnostics,
|
|
37
|
+
updates, and removal are separate commands:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
node dist/packages/cli/src/bin.js init --scope project --harness both --profile core --yes
|
|
41
|
+
node dist/packages/cli/src/bin.js trust status --json
|
|
42
|
+
node dist/packages/cli/src/bin.js doctor --json
|
|
43
|
+
node dist/packages/cli/src/bin.js update --target-version 0.1.0 --dry-run --json
|
|
44
|
+
node dist/packages/cli/src/bin.js uninstall --dry-run --json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The commands after `init --yes` are post-apply operations; `doctor` may report
|
|
48
|
+
an unknown probe status until a repository-specific verification setup exists.
|
|
49
|
+
|
|
50
|
+
Use `--scope user` with user-home installations. Do not install from npm until
|
|
51
|
+
the `v0.1.0` tag has been published; the release workflow is the source of the
|
|
52
|
+
published package and provenance record.
|
|
53
|
+
|
|
54
|
+
## Project principles
|
|
55
|
+
|
|
56
|
+
- Define verifiable success before making changes.
|
|
57
|
+
- Treat command output and current filesystem state as evidence.
|
|
58
|
+
- Keep advisory automation separate from blocking guardrails.
|
|
59
|
+
- Preserve user configuration through managed, reversible updates.
|
|
60
|
+
- Support Codex and Claude Code without project-specific assumptions.
|
|
61
|
+
- Collect no network telemetry.
|
|
62
|
+
|
|
63
|
+
## Project status
|
|
64
|
+
|
|
65
|
+
No npm package has been published yet. Do not depend on the current repository
|
|
66
|
+
as a stable interface until a tagged release is available.
|
|
67
|
+
|
|
68
|
+
Documentation:
|
|
69
|
+
|
|
70
|
+
- [English specification](docs/en/spec/README.md)
|
|
71
|
+
- [繁體中文規範](docs/zh-TW/spec/README.md)
|
|
72
|
+
- [English guides](docs/en/guides/quickstart.md)
|
|
73
|
+
- [繁體中文指南](docs/zh-TW/guides/quickstart.md)
|
|
74
|
+
|
|
75
|
+
## Community
|
|
76
|
+
|
|
77
|
+
- Read [CONTRIBUTING.md](CONTRIBUTING.md) before proposing a change.
|
|
78
|
+
- Report security issues according to [SECURITY.md](SECURITY.md).
|
|
79
|
+
- Participation is governed by [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
Copyright (c) 2026 Kyle Cheng. Released under the [MIT License](LICENSE).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
The project has not published a supported release yet. Development branches
|
|
6
|
+
and pre-1.0 artifacts are provided for evaluation and do not carry an SLA.
|
|
7
|
+
Supported release lines and security-fix policy will be listed before version
|
|
8
|
+
1.0.0.
|
|
9
|
+
|
|
10
|
+
## Reporting a vulnerability
|
|
11
|
+
|
|
12
|
+
Do not disclose suspected vulnerabilities in a public issue. Use GitHub's
|
|
13
|
+
private vulnerability reporting interface for this repository when available.
|
|
14
|
+
If that interface is unavailable, contact the maintainer through the public
|
|
15
|
+
contact method listed on the
|
|
16
|
+
[kylecheng3146 GitHub profile](https://github.com/kylecheng3146) and request a
|
|
17
|
+
private reporting channel. Do not include exploit details in the initial public
|
|
18
|
+
message.
|
|
19
|
+
|
|
20
|
+
Reports should include the affected version, impact, minimal reproduction, and
|
|
21
|
+
any known mitigation. No response-time or remediation SLA is currently
|
|
22
|
+
promised.
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
export const COMMAND_NAMES = [
|
|
2
|
+
"init",
|
|
3
|
+
"config",
|
|
4
|
+
"trust",
|
|
5
|
+
"doctor",
|
|
6
|
+
"update",
|
|
7
|
+
"uninstall",
|
|
8
|
+
"task",
|
|
9
|
+
"verify",
|
|
10
|
+
"review"
|
|
11
|
+
];
|
|
12
|
+
const COMMAND_SET = new Set(COMMAND_NAMES);
|
|
13
|
+
const SCOPES = new Set(["project", "user"]);
|
|
14
|
+
const HARNESSES = new Set(["both", "claude", "codex"]);
|
|
15
|
+
const PROFILES = new Set(["advisory", "core", "guardrails"]);
|
|
16
|
+
export class CliArgumentError extends Error {
|
|
17
|
+
code;
|
|
18
|
+
option;
|
|
19
|
+
constructor(code, message, option) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "CliArgumentError";
|
|
22
|
+
this.code = code;
|
|
23
|
+
this.option = option;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function readOptionValue(argv, index, option) {
|
|
27
|
+
const value = argv[index + 1];
|
|
28
|
+
if (value === undefined || value.startsWith("--")) {
|
|
29
|
+
throw new CliArgumentError("CLI_MISSING_VALUE", `${option} requires a value.`, option);
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
function duplicate(option) {
|
|
34
|
+
throw new CliArgumentError("CLI_DUPLICATE_OPTION", `${option} may not be repeated.`, option);
|
|
35
|
+
}
|
|
36
|
+
function invalidValue(option, value) {
|
|
37
|
+
throw new CliArgumentError("CLI_INVALID_VALUE", `Invalid value for ${option}: ${value}`, option);
|
|
38
|
+
}
|
|
39
|
+
export function parseArgs(argv) {
|
|
40
|
+
let command;
|
|
41
|
+
let action;
|
|
42
|
+
let scope;
|
|
43
|
+
let harness;
|
|
44
|
+
let taskId;
|
|
45
|
+
let targetVersion;
|
|
46
|
+
let title;
|
|
47
|
+
let sessionId;
|
|
48
|
+
const profiles = [];
|
|
49
|
+
const criteria = [];
|
|
50
|
+
const evidence = [];
|
|
51
|
+
let dryRun = false;
|
|
52
|
+
let json = false;
|
|
53
|
+
let yes = false;
|
|
54
|
+
let helpSeen = false;
|
|
55
|
+
let versionSeen = false;
|
|
56
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
57
|
+
const token = argv[index];
|
|
58
|
+
if (token === undefined) {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
switch (token) {
|
|
62
|
+
case "--scope": {
|
|
63
|
+
if (scope !== undefined) {
|
|
64
|
+
duplicate(token);
|
|
65
|
+
}
|
|
66
|
+
const value = readOptionValue(argv, index, token);
|
|
67
|
+
if (!SCOPES.has(value)) {
|
|
68
|
+
invalidValue(token, value);
|
|
69
|
+
}
|
|
70
|
+
scope = value;
|
|
71
|
+
index += 1;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case "--harness": {
|
|
75
|
+
if (harness !== undefined) {
|
|
76
|
+
duplicate(token);
|
|
77
|
+
}
|
|
78
|
+
const value = readOptionValue(argv, index, token);
|
|
79
|
+
if (!HARNESSES.has(value)) {
|
|
80
|
+
invalidValue(token, value);
|
|
81
|
+
}
|
|
82
|
+
harness = value;
|
|
83
|
+
index += 1;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "--profile": {
|
|
87
|
+
const value = readOptionValue(argv, index, token);
|
|
88
|
+
if (!PROFILES.has(value)) {
|
|
89
|
+
invalidValue(token, value);
|
|
90
|
+
}
|
|
91
|
+
if (profiles.includes(value)) {
|
|
92
|
+
duplicate(`${token} ${value}`);
|
|
93
|
+
}
|
|
94
|
+
profiles.push(value);
|
|
95
|
+
index += 1;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case "--task": {
|
|
99
|
+
if (taskId !== undefined) {
|
|
100
|
+
duplicate(token);
|
|
101
|
+
}
|
|
102
|
+
taskId = readOptionValue(argv, index, token);
|
|
103
|
+
index += 1;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case "--target-version": {
|
|
107
|
+
if (targetVersion !== undefined) {
|
|
108
|
+
duplicate(token);
|
|
109
|
+
}
|
|
110
|
+
targetVersion = readOptionValue(argv, index, token);
|
|
111
|
+
index += 1;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
case "--title": {
|
|
115
|
+
if (title !== undefined) {
|
|
116
|
+
duplicate(token);
|
|
117
|
+
}
|
|
118
|
+
title = readOptionValue(argv, index, token);
|
|
119
|
+
index += 1;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
case "--criterion": {
|
|
123
|
+
criteria.push(readOptionValue(argv, index, token));
|
|
124
|
+
index += 1;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
case "--evidence": {
|
|
128
|
+
evidence.push(readOptionValue(argv, index, token));
|
|
129
|
+
index += 1;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case "--session": {
|
|
133
|
+
if (sessionId !== undefined) {
|
|
134
|
+
duplicate(token);
|
|
135
|
+
}
|
|
136
|
+
sessionId = readOptionValue(argv, index, token);
|
|
137
|
+
index += 1;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case "--dry-run":
|
|
141
|
+
if (dryRun) {
|
|
142
|
+
duplicate(token);
|
|
143
|
+
}
|
|
144
|
+
dryRun = true;
|
|
145
|
+
break;
|
|
146
|
+
case "--json":
|
|
147
|
+
if (json) {
|
|
148
|
+
duplicate(token);
|
|
149
|
+
}
|
|
150
|
+
json = true;
|
|
151
|
+
break;
|
|
152
|
+
case "--yes":
|
|
153
|
+
if (yes) {
|
|
154
|
+
duplicate(token);
|
|
155
|
+
}
|
|
156
|
+
yes = true;
|
|
157
|
+
break;
|
|
158
|
+
case "--help":
|
|
159
|
+
case "-h":
|
|
160
|
+
if (helpSeen) {
|
|
161
|
+
duplicate(token);
|
|
162
|
+
}
|
|
163
|
+
helpSeen = true;
|
|
164
|
+
break;
|
|
165
|
+
case "--version":
|
|
166
|
+
case "-v":
|
|
167
|
+
if (versionSeen) {
|
|
168
|
+
duplicate(token);
|
|
169
|
+
}
|
|
170
|
+
versionSeen = true;
|
|
171
|
+
break;
|
|
172
|
+
default:
|
|
173
|
+
if (token.startsWith("-")) {
|
|
174
|
+
throw new CliArgumentError("CLI_UNKNOWN_OPTION", `Unknown option: ${token}`, token);
|
|
175
|
+
}
|
|
176
|
+
if (command === "config" &&
|
|
177
|
+
action === undefined &&
|
|
178
|
+
token === "explain") {
|
|
179
|
+
action = token;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
if (command === "trust" &&
|
|
183
|
+
action === undefined &&
|
|
184
|
+
["grant", "revoke", "status"].includes(token)) {
|
|
185
|
+
action = token;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
if (command === "task" &&
|
|
189
|
+
action === undefined &&
|
|
190
|
+
[
|
|
191
|
+
"archive",
|
|
192
|
+
"attach",
|
|
193
|
+
"complete",
|
|
194
|
+
"create",
|
|
195
|
+
"export",
|
|
196
|
+
"status"
|
|
197
|
+
].includes(token)) {
|
|
198
|
+
action = token;
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
if (command !== undefined) {
|
|
202
|
+
throw new CliArgumentError("CLI_UNEXPECTED_ARGUMENT", `Unexpected argument: ${token}`);
|
|
203
|
+
}
|
|
204
|
+
if (!COMMAND_SET.has(token)) {
|
|
205
|
+
throw new CliArgumentError("CLI_UNKNOWN_COMMAND", `Unknown command: ${token}`);
|
|
206
|
+
}
|
|
207
|
+
command = token;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (helpSeen && versionSeen) {
|
|
211
|
+
throw new CliArgumentError("CLI_CONFLICTING_ACTION", "--help and --version cannot be combined.");
|
|
212
|
+
}
|
|
213
|
+
if ((helpSeen || versionSeen) && command !== undefined) {
|
|
214
|
+
throw new CliArgumentError("CLI_CONFLICTING_ACTION", "Global help or version cannot be combined with a command.");
|
|
215
|
+
}
|
|
216
|
+
if (helpSeen || versionSeen) {
|
|
217
|
+
if (scope !== undefined ||
|
|
218
|
+
harness !== undefined ||
|
|
219
|
+
profiles.length > 0 ||
|
|
220
|
+
taskId !== undefined ||
|
|
221
|
+
targetVersion !== undefined ||
|
|
222
|
+
title !== undefined ||
|
|
223
|
+
criteria.length > 0 ||
|
|
224
|
+
evidence.length > 0 ||
|
|
225
|
+
sessionId !== undefined ||
|
|
226
|
+
dryRun ||
|
|
227
|
+
yes) {
|
|
228
|
+
throw new CliArgumentError("CLI_OPTION_NOT_ALLOWED", "Only --json may be combined with global help or version.");
|
|
229
|
+
}
|
|
230
|
+
command = helpSeen ? "help" : "version";
|
|
231
|
+
}
|
|
232
|
+
if (command === undefined) {
|
|
233
|
+
throw new CliArgumentError("CLI_COMMAND_REQUIRED", "A command, --help, or --version is required.");
|
|
234
|
+
}
|
|
235
|
+
if (command === "trust" && action === undefined) {
|
|
236
|
+
throw new CliArgumentError("CLI_ACTION_REQUIRED", "The trust command requires one of: status, grant, revoke.");
|
|
237
|
+
}
|
|
238
|
+
if (command === "task" && action === undefined) {
|
|
239
|
+
throw new CliArgumentError("CLI_ACTION_REQUIRED", "The task command requires one of: create, status, attach, complete, archive, export.");
|
|
240
|
+
}
|
|
241
|
+
const hasTaskTargetOptions = taskId !== undefined ||
|
|
242
|
+
sessionId !== undefined;
|
|
243
|
+
const hasTaskMutationOptions = title !== undefined ||
|
|
244
|
+
criteria.length > 0 ||
|
|
245
|
+
evidence.length > 0;
|
|
246
|
+
if (command !== "task" &&
|
|
247
|
+
command !== "verify" &&
|
|
248
|
+
command !== "review" &&
|
|
249
|
+
(hasTaskTargetOptions || hasTaskMutationOptions)) {
|
|
250
|
+
throw new CliArgumentError("CLI_OPTION_NOT_ALLOWED", "Task target options may be used only with task or verify.");
|
|
251
|
+
}
|
|
252
|
+
if (command !== "update" && targetVersion !== undefined) {
|
|
253
|
+
throw new CliArgumentError("CLI_OPTION_NOT_ALLOWED", "--target-version may be used only with update.");
|
|
254
|
+
}
|
|
255
|
+
if (command === "task") {
|
|
256
|
+
if (harness !== undefined ||
|
|
257
|
+
profiles.length > 0 ||
|
|
258
|
+
dryRun ||
|
|
259
|
+
yes) {
|
|
260
|
+
throw new CliArgumentError("CLI_OPTION_NOT_ALLOWED", "Task commands do not accept harness, profile, dry-run, or yes options.");
|
|
261
|
+
}
|
|
262
|
+
const taskOptionInvalid = (action === "create" &&
|
|
263
|
+
(taskId !== undefined ||
|
|
264
|
+
evidence.length > 0 ||
|
|
265
|
+
sessionId !== undefined)) ||
|
|
266
|
+
(action === "status" &&
|
|
267
|
+
(title !== undefined ||
|
|
268
|
+
criteria.length > 0 ||
|
|
269
|
+
evidence.length > 0 ||
|
|
270
|
+
(taskId !== undefined && sessionId !== undefined))) ||
|
|
271
|
+
(action === "attach" &&
|
|
272
|
+
(title !== undefined ||
|
|
273
|
+
criteria.length > 0 ||
|
|
274
|
+
evidence.length > 0)) ||
|
|
275
|
+
(action === "complete" &&
|
|
276
|
+
(title !== undefined ||
|
|
277
|
+
criteria.length > 0 ||
|
|
278
|
+
sessionId !== undefined)) ||
|
|
279
|
+
((action === "archive" || action === "export") &&
|
|
280
|
+
(title !== undefined ||
|
|
281
|
+
criteria.length > 0 ||
|
|
282
|
+
evidence.length > 0 ||
|
|
283
|
+
sessionId !== undefined));
|
|
284
|
+
if (taskOptionInvalid) {
|
|
285
|
+
throw new CliArgumentError("CLI_OPTION_NOT_ALLOWED", `Unsupported option for task ${action}.`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (command === "verify" &&
|
|
289
|
+
(harness !== undefined ||
|
|
290
|
+
profiles.length > 0 ||
|
|
291
|
+
title !== undefined ||
|
|
292
|
+
criteria.length > 0 ||
|
|
293
|
+
evidence.length > 0 ||
|
|
294
|
+
dryRun ||
|
|
295
|
+
yes ||
|
|
296
|
+
(taskId !== undefined && sessionId !== undefined))) {
|
|
297
|
+
throw new CliArgumentError("CLI_OPTION_NOT_ALLOWED", "Verify accepts only scope, task or session, and json options.");
|
|
298
|
+
}
|
|
299
|
+
if (command === "review" &&
|
|
300
|
+
(title !== undefined || sessionId !== undefined)) {
|
|
301
|
+
throw new CliArgumentError("CLI_OPTION_NOT_ALLOWED", "Review accepts harness, criteria, evidence, scope, dry-run, json, and yes options.");
|
|
302
|
+
}
|
|
303
|
+
if (command === "review" && harness === "both") {
|
|
304
|
+
invalidValue("--harness", harness);
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
command,
|
|
308
|
+
...(action === undefined ? {} : { action }),
|
|
309
|
+
...(scope === undefined ? {} : { scope }),
|
|
310
|
+
...(harness === undefined ? {} : { harness }),
|
|
311
|
+
profiles,
|
|
312
|
+
...(taskId === undefined ? {} : { taskId }),
|
|
313
|
+
...(targetVersion === undefined ? {} : { targetVersion }),
|
|
314
|
+
...(title === undefined ? {} : { title }),
|
|
315
|
+
...(criteria.length === 0 ? {} : { criteria }),
|
|
316
|
+
...(evidence.length === 0 ? {} : { evidence }),
|
|
317
|
+
...(sessionId === undefined ? {} : { sessionId }),
|
|
318
|
+
dryRun,
|
|
319
|
+
json,
|
|
320
|
+
yes
|
|
321
|
+
};
|
|
322
|
+
}
|