@sunstack/cli 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +141 -47
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
This pre-1.0 minor release cuts over the lint configuration and rulebook format.
|
|
6
|
+
|
|
7
|
+
- Replace lint's `rule_sets` configuration with marked Markdown `rulebook` pairs,
|
|
8
|
+
checked-file globs, an ast-grep evidence project and `decision_model`. Rule
|
|
9
|
+
entries run explicit mechanical and model decision steps on evidence pieces;
|
|
10
|
+
asking rules always require a configured model and credential.
|
|
11
|
+
- Add `sunstack lint --check` for credential-free admission and rule listing,
|
|
12
|
+
and `--evidence [KIND]` for inspecting picked evidence without model requests.
|
|
13
|
+
`--init` writes a generic configuration skeleton.
|
|
14
|
+
- Report uncertain decisions with their step, sent state and answers. Exit 5
|
|
15
|
+
means uncertainty when cancellation, incomplete work or failing findings do
|
|
16
|
+
not take precedence.
|
|
17
|
+
- Remove native RuleSet `rule_sources`, `marker_prefix` and `max_question_words`.
|
|
18
|
+
Native JSONL `rule_paths` and conversation operations remain supported. Existing
|
|
19
|
+
lint configurations must migrate to the [current configuration](README.md#repository-lint);
|
|
20
|
+
removed keys are refused with replacement guidance.
|
package/README.md
CHANGED
|
@@ -1,4 +1,87 @@
|
|
|
1
|
-
# sunstack
|
|
1
|
+
# sunstack
|
|
2
|
+
|
|
3
|
+
Lint repository documents with a marked rulebook, ast-grep evidence and explicit
|
|
4
|
+
decision steps. Use `sunstack exec` for the native JSON protocol.
|
|
5
|
+
|
|
6
|
+
## Repository lint
|
|
7
|
+
|
|
8
|
+
Create a configuration skeleton with `sunstack lint --init`, then add the
|
|
9
|
+
referenced Markdown rulebook, JSON rule entries and ast-grep project. Init writes
|
|
10
|
+
only `sunstack.lint.json` and refuses to overwrite an existing file.
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"rulebook": [{ "markdown": "rulebook.md", "rules": "rulebook.rules.json" }],
|
|
15
|
+
"marker_prefix": "K",
|
|
16
|
+
"check": { "files": ["docs/**/*.md"], "ignore": ["docs/archive/**"] },
|
|
17
|
+
"evidence": {
|
|
18
|
+
"ast_grep": "evidence/sgconfig.yml",
|
|
19
|
+
"kinds": {
|
|
20
|
+
"piece": {
|
|
21
|
+
"rule": "your-rule-id",
|
|
22
|
+
"fields": { "body": { "from": "remainder" } }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"decision_model": { "model": "jev-latest" }
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Replace `your-rule-id` with a rule in your ast-grep project. An end-of-line marker
|
|
31
|
+
such as `<!-- K001 -->` binds a Markdown standard to its `K001` JSON entry.
|
|
32
|
+
Each entry names an evidence kind and a decision graph. Steps can check fields
|
|
33
|
+
mechanically, ask authored questions, combine answers and route to pass or a
|
|
34
|
+
finding. Questions reach the model as authored, with one piece's bounded field
|
|
35
|
+
view. The binary embeds six generic Markdown utilities; rulebooks, questions and
|
|
36
|
+
domain-specific evidence rules belong to the caller.
|
|
37
|
+
|
|
38
|
+
Rulebook and ast-grep project paths resolve relative to the configuration file.
|
|
39
|
+
Checked-file globs resolve from its Git repository root, or from the config
|
|
40
|
+
directory outside Git. Without `--config`, lint searches the current directory
|
|
41
|
+
and its parents for `sunstack.lint.json`.
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
sunstack lint --config sunstack.lint.json --check
|
|
45
|
+
sunstack lint --config sunstack.lint.json --all --evidence
|
|
46
|
+
sunstack lint --config sunstack.lint.json --all --evidence piece
|
|
47
|
+
sunstack lint --config sunstack.lint.json --all --format json
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`--check` validates configuration, the rulebook and evidence project, then lists
|
|
51
|
+
the assembled rules as JSON. It reads no checked files and sends no model
|
|
52
|
+
requests. `--evidence [KIND]` prints picked evidence and its fields as JSON without
|
|
53
|
+
asking the model. Both routes work without a credential.
|
|
54
|
+
|
|
55
|
+
An ordinary lint run uses changed evidence by default and requires Git for that
|
|
56
|
+
default scope. Use `--all` for every configured target, `--since REV` for changes
|
|
57
|
+
since a revision including worktree edits, or name files or directories for full
|
|
58
|
+
scope within those paths. Findings retain their rule, marker and source
|
|
59
|
+
location. Available output formats are `default`, `json`, `github` and `sarif`.
|
|
60
|
+
The JSON report includes `results`, one entry per evaluated rule/piece pair in
|
|
61
|
+
logical report order. Each entry has the rule's `name` and marker, the piece's
|
|
62
|
+
file and first and last line, its outcome (`pass`, `finding`, `not_applicable`,
|
|
63
|
+
`uncertain` or `incomplete`) and its ending `step` (null before any step ran).
|
|
64
|
+
|
|
65
|
+
The decision model is always configured and enabled for asking rules; there is
|
|
66
|
+
no model-off switch. Ordinary runs with asking rules require an OpenRouter
|
|
67
|
+
credential before checked-file acquisition, even if a later mechanical branch
|
|
68
|
+
would avoid an ask. Mechanical-only rules need no key. Credential lookup and
|
|
69
|
+
saving are described below under the native protocol.
|
|
70
|
+
|
|
71
|
+
Lint exits 0 for clean or nothing selected, 1 for error findings or warnings over
|
|
72
|
+
`--max-warnings`, 2 for invalid input, 3 for incomplete work, 4 for cancellation,
|
|
73
|
+
and 5 for uncertain decisions. Uncertainty retains the decision step, sent state
|
|
74
|
+
and answers for the caller to inspect. Cancellation takes precedence over
|
|
75
|
+
incomplete work, then findings, then uncertainty. A warning alone does not fail
|
|
76
|
+
unless it exceeds `--max-warnings`.
|
|
77
|
+
|
|
78
|
+
See the checked-in [worked configuration](tests/fixtures/rulebook-lint/skill-rules.config.json)
|
|
79
|
+
and its [rulebook entries](tests/fixtures/rulebook-lint/rulebook/steering.rules.json)
|
|
80
|
+
for a complete test example. Copy the fixture directory to an isolated root to
|
|
81
|
+
try it; its checked-file globs are relative to that root. The example's
|
|
82
|
+
skill-specific rules are test content.
|
|
83
|
+
|
|
84
|
+
## Native JSON protocol
|
|
2
85
|
|
|
3
86
|
Run `sunstack exec` (or `cargo run -p sunstack -- exec` from the repository root).
|
|
4
87
|
One process consumes one JSON request on stdin and writes one JSON response on
|
|
@@ -6,7 +89,7 @@ stdout. Relative input paths resolve from the process working directory. Run
|
|
|
6
89
|
from the repository root when using the reviewed examples.
|
|
7
90
|
|
|
8
91
|
```json
|
|
9
|
-
{"protocol_version":1,"operation":"evaluate_rules","input":{}}
|
|
92
|
+
{ "protocol_version": 1, "operation": "evaluate_rules", "input": {} }
|
|
10
93
|
```
|
|
11
94
|
|
|
12
95
|
Replace `input` with the native operation input. Supported operations are
|
|
@@ -29,7 +112,7 @@ package bindings. A relative repository root resolves from this process's CWD.
|
|
|
29
112
|
For example, select current unstaged changes on a repository binding with:
|
|
30
113
|
|
|
31
114
|
```json
|
|
32
|
-
{"change_scope":{"kind":"uncommitted","layers":["unstaged"]}}
|
|
115
|
+
{ "change_scope": { "kind": "uncommitted", "layers": ["unstaged"] } }
|
|
33
116
|
```
|
|
34
117
|
|
|
35
118
|
This is a binding fragment, not a complete invocation. ChangeSet selectors need
|
|
@@ -45,8 +128,22 @@ Preparing rules sends no model request. A waiting gate leaves target comparison
|
|
|
45
128
|
pending; evaluation resolves it only when the native gate permits the work.
|
|
46
129
|
The CLI forwards these native outcomes and uses the same exit meanings above.
|
|
47
130
|
|
|
48
|
-
The
|
|
49
|
-
|
|
131
|
+
The binary uses a non-empty `OPENROUTER_API_KEY` first, otherwise the OS credential
|
|
132
|
+
store (`sunstack` / `openrouter-api-key`): macOS login Keychain or Linux Secret
|
|
133
|
+
Service. When the environment key is present, a run never reads or writes the store.
|
|
134
|
+
Runs never save credentials automatically. Use `sunstack credentials save` to save
|
|
135
|
+
the current environment key explicitly; it is listed in `sunstack --help`.
|
|
136
|
+
The command reports its destination without printing the key and refuses a missing
|
|
137
|
+
or empty variable. Set
|
|
138
|
+
`SUNSTACK_CREDENTIAL_STORE=off` to disable both lookup and saving (for CI or a one-off
|
|
139
|
+
key). Library callers pass the key as a value to `sunstack_lint::run`.
|
|
140
|
+
Without a terminal on stdin, macOS access that needs Keychain approval is treated
|
|
141
|
+
as unavailable immediately. Run once from a terminal to approve a changed build,
|
|
142
|
+
or supply the environment key. Interactive terminal runs may show the Keychain dialog.
|
|
143
|
+
On Linux, a locked Secret Service collection may prompt during fallback lookup or explicit saving;
|
|
144
|
+
use `SUNSTACK_CREDENTIAL_STORE=off` for unattended runs.
|
|
145
|
+
|
|
146
|
+
Credentials never come from stdin. Rule preparation uses the selected backend for encoding and accounting
|
|
50
147
|
when model work is reachable; it sends no provider request. Local-only rule
|
|
51
148
|
preparation and evaluation construct no backend and need no credential. A
|
|
52
149
|
model-based judgment, applicability gate or Router still requires valid backend
|
|
@@ -63,41 +160,20 @@ It accepts no backend, attempt or request-budget settings. A clean check exits 0
|
|
|
63
160
|
refusals exit 2 with definition file, line and column. Printed rules are returned
|
|
64
161
|
only after a clean check and include each native definition and its source.
|
|
65
162
|
|
|
66
|
-
RuleSets
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
entry in the strict rules object. Entry `name` becomes the native rule ID;
|
|
71
|
-
`target.input` is always explicit, and optional `context` uses native evidence
|
|
72
|
-
declarations. The target declaration reserves ID `target`. The assembled question
|
|
73
|
-
uses visible Markdown wording, with a default cap of 400 words configurable by
|
|
74
|
-
`max_question_words`. Both the Markdown and rules file are definition dependencies.
|
|
75
|
-
|
|
76
|
-
At runtime, invalid source entries are listed in `skipped_rules`, while valid
|
|
77
|
-
rules continue. An unreadable or malformed source contributes one source-level
|
|
78
|
-
skip. `rule_coverage` is `full`, `partial` or `none`; partial runs can complete
|
|
79
|
-
with exit 0, while no valid rule yields incomplete exit 3. Measurements keep
|
|
80
|
-
`invalid_rule_entries` and `skipped_rule_sources` separate from applicability's
|
|
81
|
-
`rules_skipped`. Existing JSONL, RuleSet-header and invocation errors retain
|
|
82
|
-
their strict refusal behavior.
|
|
83
|
-
|
|
84
|
-
Run the complete credential-free check/print example from the repository root:
|
|
85
|
-
|
|
86
|
-
```sh
|
|
87
|
-
scripts/cargo-debug-signing-runner.sh target/debug/sunstack exec \
|
|
88
|
-
< docs/specs/2026-10-12-rust-rule-engine/examples/marked-standards.check.request.json
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
The [check input schema](../../docs/specs/2026-10-12-rust-rule-engine/schemas/check-rules-input.schema.json)
|
|
92
|
-
and [rules-object schema](../../docs/specs/2026-10-12-rust-rule-engine/schemas/rule-source.schema.json)
|
|
93
|
-
describe these boundaries. Preparation and evaluation reports now require coverage,
|
|
94
|
-
rule evaluations, skipped rules and their counters; strict report consumers must
|
|
95
|
-
update together.
|
|
163
|
+
Native RuleSets load `rule_paths` JSONL files, with paths relative to the RuleSet
|
|
164
|
+
file. Use the repository lint route above for marked Markdown rulebooks. Native
|
|
165
|
+
preparation and evaluation retain their coverage, rule evaluations, skipped rules
|
|
166
|
+
and counters. JSONL, RuleSet-header and invocation errors remain strict refusals.
|
|
96
167
|
|
|
97
168
|
Document targets can select Markdown units independently:
|
|
98
169
|
|
|
99
170
|
```json
|
|
100
|
-
{
|
|
171
|
+
{
|
|
172
|
+
"kind": "markdown_units",
|
|
173
|
+
"mode": "call_site",
|
|
174
|
+
"units": ["paragraph", "list_item"],
|
|
175
|
+
"pattern": "\\bMUST\\s+load\\b"
|
|
176
|
+
}
|
|
101
177
|
```
|
|
102
178
|
|
|
103
179
|
`mode: unit` produces one occurrence per requested section, paragraph or list
|
|
@@ -126,24 +202,48 @@ The evidence library also supports `frontmatter_field` with a literal top-level
|
|
|
126
202
|
field. Missing or malformed blocks yield explicit unavailable data without an
|
|
127
203
|
invented span. Noul and composite rules reject this mechanical-only target.
|
|
128
204
|
|
|
129
|
-
A rules entry can
|
|
205
|
+
A rules entry can use a native mechanical verdict. Put the check under
|
|
206
|
+
`verdict.check` and select the checked field in the evidence declaration:
|
|
130
207
|
|
|
131
208
|
```json
|
|
132
|
-
{
|
|
209
|
+
{
|
|
210
|
+
"rule_id": "skill.description",
|
|
211
|
+
"evidence": [
|
|
212
|
+
{
|
|
213
|
+
"id": "description",
|
|
214
|
+
"input": "subject",
|
|
215
|
+
"requirement": "required",
|
|
216
|
+
"select": { "kind": "frontmatter_field", "field": "description" }
|
|
217
|
+
}
|
|
218
|
+
],
|
|
219
|
+
"target": "description",
|
|
220
|
+
"applicability": [],
|
|
221
|
+
"questions": {},
|
|
222
|
+
"verdict": {
|
|
223
|
+
"kind": "mechanical",
|
|
224
|
+
"explanation": "Description names when to use the skill.",
|
|
225
|
+
"check": { "kind": "expect", "expect": { "starts_with": "Use when" } }
|
|
226
|
+
},
|
|
227
|
+
"severity": "error"
|
|
228
|
+
}
|
|
133
229
|
```
|
|
134
230
|
|
|
135
|
-
|
|
231
|
+
Save each native definition as one JSONL line in a RuleSet's `rule_paths`, and
|
|
232
|
+
declare its `subject` input as a document in the RuleSet header. Bind that input
|
|
233
|
+
to the document when calling `check_rules` or `evaluate_rules`.
|
|
234
|
+
|
|
235
|
+
`verdict.check.expect` accepts exactly one of `matches`, `not_matches`, `starts_with` or
|
|
136
236
|
`present: true`. Text predicates use the unit's rendered-visible text, excluding
|
|
137
237
|
inline code. A frontmatter string uses its decoded text; other values use
|
|
138
238
|
canonical JSON text. Null is present. Every predicate fails on an absent field;
|
|
139
239
|
a missing or malformed header is unresolved.
|
|
140
240
|
|
|
241
|
+
For an AST check, use `verdict.check: {"kind":"ast_grep","ast_grep":{...}}`.
|
|
141
242
|
`ast_grep` accepts a native rule object validated by ast-grep-config 0.51.0.
|
|
142
243
|
It sees the full original Markdown syntax tree, including ancestors outside
|
|
143
244
|
the unit. A match fully contained in the target unit is a failure; sibling
|
|
144
245
|
matches outside it are excluded. Frontmatter fields use `expect`; runtime unit
|
|
145
|
-
kinds do not select the metadata block.
|
|
146
|
-
result's explanation and is not sent to a model.
|
|
246
|
+
kinds do not select the metadata block. Local checks send no model request.
|
|
147
247
|
|
|
148
248
|
Reports use `checked` occurrences with `completed` pass/fail, `unresolved` or
|
|
149
249
|
`cancelled` local outcomes. A failed check retains its declared severity and
|
|
@@ -151,12 +251,6 @@ can complete with exit 0. Unresolved checks make the report incomplete. Local
|
|
|
151
251
|
checks create no model answers, references, receipts or confidence and consume
|
|
152
252
|
no model question/request budget. Applicability and routing still govern them.
|
|
153
253
|
|
|
154
|
-
The [mechanical invocation](../../docs/specs/2026-10-12-rust-rule-engine/examples/mechanical.invocation.json)
|
|
155
|
-
checks a description and a load instruction without a credential. Wrap that
|
|
156
|
-
native input in the usual `evaluate_rules` protocol frame. The companion
|
|
157
|
-
[check request](../../docs/specs/2026-10-12-rust-rule-engine/examples/mechanical.check.request.json)
|
|
158
|
-
validates and prints both standards without reading the reviewed skill.
|
|
159
|
-
|
|
160
254
|
Rust callers supply `RuleBackendFactory` in `RuleExecutionContext`. Selection
|
|
161
255
|
is credential-free; the invocation calls `prepare` once when its first model
|
|
162
256
|
request reaches encoding and caches the result. Concrete built backends already
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"hasInstallScript": true,
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"name": "@sunstack/cli",
|
|
22
|
-
"version": "0.
|
|
22
|
+
"version": "0.2.0"
|
|
23
23
|
},
|
|
24
24
|
"node_modules/detect-libc": {
|
|
25
25
|
"engines": {
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"requires": true,
|
|
51
|
-
"version": "0.
|
|
51
|
+
"version": "0.2.0"
|
|
52
52
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"artifactDownloadUrls": [
|
|
3
|
-
"https://github.com/ShravanSunder/sunstack-tools/releases/download/v0.
|
|
3
|
+
"https://github.com/ShravanSunder/sunstack-tools/releases/download/v0.2.0"
|
|
4
4
|
],
|
|
5
5
|
"bin": {
|
|
6
6
|
"sunstack": "run-sunstack.js"
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"zipExt": ".tar.gz"
|
|
89
89
|
}
|
|
90
90
|
},
|
|
91
|
-
"version": "0.
|
|
91
|
+
"version": "0.2.0",
|
|
92
92
|
"volta": {
|
|
93
93
|
"node": "18.14.1",
|
|
94
94
|
"npm": "9.5.0"
|