@supersuit/superskill 0.3.1 → 0.4.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 +14 -0
- package/README.md +1 -1
- package/SPEC.md +2 -2
- package/package.json +1 -1
- package/src/commands/approve.mjs +20 -3
- package/src/goldens.mjs +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 (2026-09-29)
|
|
4
|
+
|
|
5
|
+
**Approve from your phone.** `superskill approve` worked only at an interactive terminal, so an
|
|
6
|
+
operator who reviews on a phone had to find a laptop to say yes. (Gary Sheng: *"The best way for
|
|
7
|
+
me to approve it is to click yes, approve, not you telling me to go to my terminal. I'm normally
|
|
8
|
+
mobile first."*) Away from a terminal it now accepts `--approved-by "<the person>"` and
|
|
9
|
+
`--via "<where they said yes>"`, after that person approved with a tap on a board or a review page.
|
|
10
|
+
Both are required and both are recorded (`via` on the approval), so an approval an agent relayed is
|
|
11
|
+
always distinguishable from one typed at a terminal, and an agent still cannot approve with no
|
|
12
|
+
named person and no channel. A rationale is required either way.
|
|
13
|
+
|
|
14
|
+
- Tests: refused with no name, refused with a name and no channel, refused with no rationale;
|
|
15
|
+
recorded with person, channel and basis. The channel requirement was mutated out and went red.
|
|
16
|
+
|
|
3
17
|
## 0.3.1 (2026-09-29)
|
|
4
18
|
|
|
5
19
|
The 0.3.0 changes below, released. The v0.3.0 tag's publish refused on a red test (SPEC.md still
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ Every rule and threshold is in [SPEC.md](SPEC.md).
|
|
|
54
54
|
| `superskill init <skill> --from-session <transcript>` | Turn the session where you did the job by hand into the first eval and a golden candidate (Claude Code `.jsonl`, or any text file as the request). |
|
|
55
55
|
| `superskill miss <skill> "<what happened>" [--expected "..."]` | Log a time the skill got it wrong. |
|
|
56
56
|
| `superskill fix <skill> <miss-id> --eval <id> [--commit <sha>]` | Close a miss. Refuses without an eval that exists. |
|
|
57
|
-
| `superskill approve <skill> <golden> [--basis judgment\|outcome] [--rationale ...] [--evidence ...]` | A person signs off on a golden, saying why and what it rests on: `judgment` (it reads right) or `outcome` (it produced a checkable result, with evidence).
|
|
57
|
+
| `superskill approve <skill> <golden> [--basis judgment\|outcome] [--rationale ...] [--evidence ...]` | A person signs off on a golden, saying why and what it rests on: `judgment` (it reads right) or `outcome` (it produced a checkable result, with evidence). At a terminal it asks for your name; from your phone, an agent records your tap with `--approved-by` and `--via`. Approvals accumulate. |
|
|
58
58
|
| `superskill collection <folder...> [--budget <chars>] [--overlap 0.5]` | Listing budget used, descriptions that get cut off, pairs of skills an agent could confuse (with near-miss triggers to add). |
|
|
59
59
|
| `superskill miss import <skill> --freedom-ledger [--ledger <file>]` | Import runs that needed correcting from Freedom's run ledger. |
|
|
60
60
|
| `superskill snippet` | Print a block for `AGENTS.md` / `CLAUDE.md` that teaches any agent these habits. |
|
package/SPEC.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The superskill standard
|
|
2
2
|
|
|
3
|
-
**Version 0.
|
|
3
|
+
**Version 0.4.0** (2026-09-29). The reference checker is `@supersuit/superskill`; where this
|
|
4
4
|
document and the checker disagree, the checker has a bug.
|
|
5
5
|
|
|
6
6
|
A **superskill** runs on frontier intelligence, is checked against examples a person approved,
|
|
@@ -157,7 +157,7 @@ A bare array of cases is accepted on read, as is `assertions` for `expectations`
|
|
|
157
157
|
- `input.md`: the real request.
|
|
158
158
|
- `output.md` (or any other file that is not `input.*` or `APPROVAL.json`): the output a person
|
|
159
159
|
said was right.
|
|
160
|
-
- `APPROVAL.json`, written only by `superskill approve
|
|
160
|
+
- `APPROVAL.json`, written only by `superskill approve`: at an interactive terminal, or relayed by an agent with `--approved-by` and `--via` after the person approved with a tap (the `via` field records where):
|
|
161
161
|
|
|
162
162
|
```json
|
|
163
163
|
{ "approvals": [
|
package/package.json
CHANGED
package/src/commands/approve.mjs
CHANGED
|
@@ -8,8 +8,10 @@ import { readGoldens, approvalEntry, withApproval, BASES } from "../goldens.mjs"
|
|
|
8
8
|
|
|
9
9
|
export const help = `superskill approve <skill> <golden-id> [--rationale "<why it is right>"] [--basis judgment|outcome] [--evidence "<what happened, where to check>"]
|
|
10
10
|
|
|
11
|
-
Record that a person checked goldens/<id>/ and signs off on its output.
|
|
12
|
-
|
|
11
|
+
Record that a person checked goldens/<id>/ and signs off on its output. At a terminal it asks
|
|
12
|
+
for your name. From an agent (a phone tap on a board or review page), pass --approved-by
|
|
13
|
+
"<the person>" and --via "<where they said yes>": both are required and both are recorded, so an
|
|
14
|
+
approval an agent relayed is always distinguishable from one typed at a terminal.
|
|
13
15
|
|
|
14
16
|
Every approval says WHY (--rationale, or asked) and WHAT IT RESTS ON (--basis, or asked):
|
|
15
17
|
judgment you read it and it is right (the default)
|
|
@@ -24,10 +26,25 @@ export async function run(argv) {
|
|
|
24
26
|
const dir = skillDir(a._[0], "approve");
|
|
25
27
|
const id = a._[1];
|
|
26
28
|
if (!id) throw new UsageError("approve needs a golden id");
|
|
27
|
-
if (!(process.stdin.isTTY && process.stdout.isTTY)) return refuse("approval needs a person at a terminal. Run this yourself, not through an agent.");
|
|
28
29
|
const g = readGoldens(dir).find((x) => x.id === id);
|
|
29
30
|
if (!g) return refuse(`no goldens/${id}/`);
|
|
30
31
|
if (g.input === null || g.output === null || !g.output.trim()) return refuse(`goldens/${id}/ needs an input file and a non-empty output file before it can be approved`);
|
|
32
|
+
if (!(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
33
|
+
// Mobile first: a person approves with a tap (a board, a review page) and an agent records it.
|
|
34
|
+
// The record names the person AND the channel, so an approval relayed by an agent is never
|
|
35
|
+
// mistaken for one typed at a terminal. Without both, an agent could approve its own output.
|
|
36
|
+
const name = String(a.flags["approved-by"] || "").trim();
|
|
37
|
+
const via = String(a.flags.via || "").trim();
|
|
38
|
+
if (!name || !via) return refuse("approval needs a person. At a terminal it asks for your name; from an agent, pass --approved-by \"<the person>\" and --via \"<where they approved: the tap, the page, the message>\", after that person said yes");
|
|
39
|
+
const sha = createHash("sha256").update(readFileSync(join(dir, "SKILL.md"))).digest("hex");
|
|
40
|
+
const made = approvalEntry({ name, rationale: a.flags.rationale || a.flags.note, basis: a.flags.basis || "judgment", evidence: a.flags.evidence, at: clock(a.flags).toISOString(), sha });
|
|
41
|
+
if (made.error) return refuse(made.error);
|
|
42
|
+
const p = join(dir, "goldens", id, "APPROVAL.json");
|
|
43
|
+
const existed = existsSync(p);
|
|
44
|
+
writeFileSync(p, JSON.stringify(withApproval(existed ? g.approval : null, { ...made.entry, via }), null, 2) + "\n");
|
|
45
|
+
process.stdout.write(`${existed ? "added an approval to" : "approved"} goldens/${id}/ by ${name} (${made.entry.basis}, via ${via})\n`);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
31
48
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
32
49
|
try {
|
|
33
50
|
process.stdout.write(`\n--- goldens/${id}/${g.outputFile} ---\n${g.output.slice(0, 2000)}${g.output.length > 2000 ? "\n[...]" : ""}\n---\n`);
|
package/src/goldens.mjs
CHANGED