polydeukes 0.6.1 → 0.7.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/README.ko.md +14 -28
- package/README.md +14 -28
- package/dist/baseline.d.ts +37 -1
- package/dist/baseline.js +68 -1
- package/dist/bin.d.ts +3 -4
- package/dist/bin.js +73 -90
- package/dist/covenant/bash-line.d.ts +130 -0
- package/dist/covenant/bash-line.js +566 -0
- package/dist/covenant/declaration-engine.d.ts +108 -0
- package/dist/covenant/declaration-engine.js +415 -0
- package/dist/covenant/discipline.d.ts +103 -0
- package/dist/covenant/discipline.js +667 -0
- package/dist/covenant/dispatch.d.ts +153 -0
- package/dist/covenant/dispatch.js +237 -0
- package/dist/covenant/extract-steps.d.ts +122 -0
- package/dist/covenant/extract-steps.js +0 -0
- package/dist/covenant/mention.d.ts +117 -0
- package/dist/covenant/mention.js +209 -0
- package/dist/covenant/module.d.ts +25 -0
- package/dist/covenant/module.js +23 -0
- package/dist/covenant/mutation-rules.d.ts +40 -0
- package/dist/covenant/mutation-rules.js +146 -0
- package/dist/covenant/relations.d.ts +46 -0
- package/dist/covenant/relations.js +68 -0
- package/dist/covenant/run-covenant.d.ts +95 -0
- package/dist/covenant/run-covenant.js +164 -0
- package/dist/covenant/self-mod.d.ts +55 -0
- package/dist/covenant/self-mod.js +84 -0
- package/dist/covenant/shell-evidence.d.ts +38 -0
- package/dist/covenant/shell-evidence.js +247 -0
- package/dist/covenant/shell-mod.d.ts +84 -0
- package/dist/covenant/shell-mod.js +213 -0
- package/dist/covenant/supply.d.ts +54 -0
- package/dist/covenant/supply.js +50 -0
- package/dist/covenant/transcript-mod.d.ts +60 -0
- package/dist/covenant/transcript-mod.js +254 -0
- package/dist/covenant/ttl-witness.d.ts +47 -0
- package/dist/covenant/ttl-witness.js +80 -0
- package/dist/covenant-check.d.ts +72 -39
- package/dist/covenant-check.js +260 -121
- package/dist/diff-ir.d.ts +28 -0
- package/dist/diff-ir.js +310 -0
- package/dist/docs/README.ko.md +8 -8
- package/dist/docs/README.md +8 -8
- package/dist/docs/catalog.json +44 -28
- package/dist/docs/concepts/judgment.ko.md +2 -2
- package/dist/docs/concepts/judgment.md +2 -2
- package/dist/docs/how-to/configure-project.ko.md +16 -16
- package/dist/docs/how-to/configure-project.md +15 -12
- package/dist/docs/how-to/connect-surfaces.ko.md +39 -34
- package/dist/docs/how-to/connect-surfaces.md +36 -33
- package/dist/docs/how-to/write-disciplines.ko.md +61 -6
- package/dist/docs/how-to/write-disciplines.md +62 -6
- package/dist/docs/index.json +607 -373
- package/dist/docs/reference/cli/covenant-check.ko.md +112 -65
- package/dist/docs/reference/cli/covenant-check.md +114 -59
- package/dist/docs/reference/cli/docs.ko.md +2 -2
- package/dist/docs/reference/cli/docs.md +2 -2
- package/dist/docs/reference/cli/explain.ko.md +14 -9
- package/dist/docs/reference/cli/explain.md +15 -10
- package/dist/docs/reference/cli/init.ko.md +52 -52
- package/dist/docs/reference/cli/init.md +43 -55
- package/dist/docs/reference/configuration/index.ko.md +171 -66
- package/dist/docs/reference/configuration/index.md +178 -71
- package/dist/docs/reference/packages/adapter-claude-code.ko.md +38 -11
- package/dist/docs/reference/packages/adapter-claude-code.md +38 -14
- package/dist/docs/reference/packages/adapter-grok.ko.md +77 -0
- package/dist/docs/reference/packages/adapter-grok.md +79 -0
- package/dist/docs/reference/packages/core.ko.md +49 -3
- package/dist/docs/reference/packages/core.md +54 -5
- package/dist/docs/reference/packages/polydeukes.ko.md +138 -77
- package/dist/docs/reference/packages/polydeukes.md +146 -81
- package/dist/docs/reference/packages/sdk-ts.ko.md +161 -0
- package/dist/docs/reference/packages/sdk-ts.md +164 -0
- package/dist/docs/troubleshooting.ko.md +17 -15
- package/dist/docs/troubleshooting.md +18 -14
- package/dist/docs/tutorials/first-judgment.ko.md +2 -2
- package/dist/docs/tutorials/first-judgment.md +2 -2
- package/dist/explain.d.ts +1 -1
- package/dist/explain.js +37 -22
- package/dist/load-config.d.ts +1 -1
- package/dist/load-config.js +1 -1
- package/dist/pre-state-reader.d.ts +1 -1
- package/dist/pre-state-reader.js +1 -1
- package/dist/scaffold-project.d.ts +2 -2
- package/dist/scaffold-project.js +9 -3
- package/dist/schema/polydeukes.schema.json +12 -0
- package/dist/worktree-reader.d.ts +19 -0
- package/dist/worktree-reader.js +30 -0
- package/package.json +3 -17
- package/dist/claude-code-hook.d.ts +0 -79
- package/dist/claude-code-hook.js +0 -372
- package/dist/claude-code.d.ts +0 -6
- package/dist/claude-code.js +0 -6
- package/dist/covenant-module.d.ts +0 -25
- package/dist/covenant-module.js +0 -42
- package/dist/docs/reference/packages/adapter-git.ko.md +0 -101
- package/dist/docs/reference/packages/adapter-git.md +0 -108
- package/dist/docs/reference/packages/covenant.ko.md +0 -115
- package/dist/docs/reference/packages/covenant.md +0 -123
- package/dist/index.d.ts +0 -22
- package/dist/index.js +0 -21
- package/dist/init-claude-code.d.ts +0 -52
- package/dist/init-claude-code.js +0 -586
- package/dist/init-grok.d.ts +0 -51
- package/dist/init-grok.js +0 -242
|
@@ -2,63 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
**English** · [한국어](./polydeukes.ko.md)
|
|
4
4
|
|
|
5
|
-
The umbrella package is the only package a consumer installs. It
|
|
6
|
-
|
|
7
|
-
artifact.
|
|
5
|
+
The umbrella package is the only package a consumer installs. It ships the `pdks` bin, the
|
|
6
|
+
judge, both surfaces' composition roots, the session-surface runner subpath, and the bundled
|
|
7
|
+
schema artifact.
|
|
8
8
|
|
|
9
9
|
<a id="polydeukes-entry-points"></a>
|
|
10
10
|
## Entry points
|
|
11
11
|
|
|
12
|
-
| Specifier | What it
|
|
12
|
+
| Specifier | What it is |
|
|
13
13
|
|---|---|
|
|
14
|
-
| `polydeukes` |
|
|
15
|
-
| `polydeukes/claude-code` | `runClaudeCodeHook` and its spec/outcome types |
|
|
14
|
+
| `pdks` / `polydeukes` | The executable. One CLI under two names in `bin` |
|
|
16
15
|
| `polydeukes/schema.json` | The bundled config JSON Schema |
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
There is no `.` entry point. `import 'polydeukes'` fails with `ERR_PACKAGE_PATH_NOT_EXPORTED`;
|
|
18
|
+
what a consumer reaches is the bin and the schema file. A session surface reaches this
|
|
19
|
+
package the same way a shell does — by spawning `pdks covenant check` — so an agent adapter
|
|
20
|
+
takes it as a peer dependency rather than importing it.
|
|
19
21
|
|
|
20
22
|
<a id="polydeukes-bin"></a>
|
|
21
23
|
## CLI surface
|
|
22
24
|
|
|
23
25
|
| Command | Purpose |
|
|
24
26
|
|---|---|
|
|
25
|
-
| `pdks covenant check` | Judge
|
|
26
|
-
| `pdks init
|
|
27
|
-
| `pdks init grok` | Install the Grok session surface |
|
|
27
|
+
| `pdks covenant check` | Judge an input IR (default, the session surface) or a unified diff (`--diff`, the change-set surface) from stdin |
|
|
28
|
+
| `pdks init` | Create the project scaffold: config file and telemetry ignore line |
|
|
28
29
|
| `pdks explain` | Render the assembled registration table without judging |
|
|
29
30
|
| `pdks docs [topic]` | Read a bundled topic |
|
|
30
31
|
| `pdks docs search <query>` | Search the bundled docs |
|
|
31
32
|
| `pdks docs show <document-id>` | Show one bundled document or section |
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
exit codes are in [`pdks docs`](../cli/docs.md).
|
|
34
|
+
Session-surface installers live on the adapters: `pdks-claude-code init` and `pdks-grok init`.
|
|
35
35
|
|
|
36
|
-
<a id="
|
|
37
|
-
|
|
36
|
+
<a id="surface-from-input-mode"></a>
|
|
37
|
+
### The input mode is the surface
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
`covenant check` reads its surface off how the input arrived, never off the input's own keys.
|
|
40
|
+
An IR on stdin is one call a host observed before it ran, so the run is the **session surface**;
|
|
41
|
+
`--diff` is a finished change set from some producer, so the run is the **change-set surface**.
|
|
42
|
+
Each surface compiles the shared list plus its own:
|
|
41
43
|
|
|
42
|
-
|
|
|
44
|
+
| Input | Surface | Lists compiled |
|
|
43
45
|
|---|---|---|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
| `ResolvedConfig` | type | Re-export from `@polydeukes/core`. |
|
|
47
|
-
| `LoadConfigSpec`, `LoadedConfig` | types | Configuration loader input and result. |
|
|
48
|
-
| `CovenantCheckSpec`, `CovenantCheckOutcome`, `CheckDomain` | types | Commit runner input, result, and observation selection. |
|
|
46
|
+
| an input IR on stdin | `session` | `disciplines`, then `sessionDisciplines` |
|
|
47
|
+
| a unified diff on stdin under `--diff` | `changeSet` | `disciplines`, then `changeSetDisciplines` |
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
The IR's `session` key says something else: what the host proved about the call — the witness
|
|
50
|
+
valve's human turns, the transcript axis, and the pre-state channel shell-write evidence needs.
|
|
51
|
+
A host that carries no session (the Grok adapter) is still judged on the session surface, and
|
|
52
|
+
what it lacks is the evidence those three read, not the surface. `pdks explain` prints each
|
|
53
|
+
surface with its two list names and counts.
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
| `runClaudeCodeHook` | function | Runs the session-surface runner and resolves to `{ exitCode: 0 \| 2 }`. |
|
|
56
|
-
| `ClaudeCodeHookSpec` | type | Input for the session runner. |
|
|
57
|
-
| `ClaudeCodeHookOutcome` | type | Session runner result. |
|
|
55
|
+
`pdks docs` is offline. It reads the installed package, not the network. Flags, JSON, and
|
|
56
|
+
exit codes are in [`pdks docs`](../cli/docs.md).
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
call that will never use them.
|
|
58
|
+
<a id="polydeukes-export-map"></a>
|
|
59
|
+
## Export map
|
|
62
60
|
|
|
63
61
|
<a id="schema-export"></a>
|
|
64
62
|
### `./schema.json`
|
|
@@ -67,67 +65,134 @@ call that will never use them.
|
|
|
67
65
|
|---|---|
|
|
68
66
|
| `polydeukes.schema.json` | The config schema copy that ships with the umbrella package. |
|
|
69
67
|
|
|
70
|
-
<a id="
|
|
71
|
-
##
|
|
68
|
+
<a id="covenant-module"></a>
|
|
69
|
+
## The judge (`covenant` module)
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
The judge is the umbrella's `src/covenant/` module. Everything that turns a declared promise
|
|
72
|
+
into a verdict lives there, and both composition roots plus `pdks explain` import it directly.
|
|
73
|
+
There is nothing to install, nothing to import, and no peer to satisfy: what you reach is its
|
|
74
|
+
behaviour, through the `disciplines:` block in your config and the rows it writes to
|
|
75
|
+
`.polydeukes/roi.log`.
|
|
75
76
|
|
|
76
|
-
|
|
77
|
+
<a id="ownership"></a>
|
|
78
|
+
### What the module owns
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
80
|
+
| Unit | What it does |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `runCovenant` wrapper | Runs a judge body, translates its non-blocking `1` into the blocking `2`, and logs every call. No covenant runs unmeasured |
|
|
83
|
+
| Path-routing dispatcher | Registers covenants against protected paths and runs *every* matching one — no short-circuit, so the telemetry never under-counts |
|
|
84
|
+
| Meta-covenants | Three registrations that protect the judging chain itself |
|
|
85
|
+
| TTL witness | The time-boxed human valve, consulted only after a verdict blocked |
|
|
86
|
+
| Delta layer | New-violation-only judgment over a file's before/after pair |
|
|
87
|
+
| Discipline library | Config `disciplines:` entries become enforcement without a line of code |
|
|
88
|
+
|
|
89
|
+
<a id="disciplines-and-meta-covenants"></a>
|
|
90
|
+
### Discipline families and meta-covenants
|
|
91
|
+
|
|
92
|
+
**A `disciplines:` entry is one declaration** — `judge = relate ∘ extract` over the
|
|
93
|
+
observation as a world. What the declaration's sources bind decides what evidence the
|
|
94
|
+
judgment needs, which is also what decides whether it can be judged on a given surface.
|
|
95
|
+
|
|
96
|
+
| Sources | Judges | Evidence needed | List |
|
|
97
|
+
|---|---|---|---|
|
|
98
|
+
| the fixed names `target.path` · `pre` · `post` · `state` | The change itself | A file change | `disciplines` |
|
|
99
|
+
| the fixed name `changes` | The observation's whole change set | A finished change set | `changeSetDisciplines` |
|
|
100
|
+
| the fixed name `command` | The shell call's command line | A shell call — an Edit carries none | `sessionDisciplines` |
|
|
101
|
+
| the fixed name `actor` | Who made the observation | An actor the host proved | `sessionDisciplines` |
|
|
102
|
+
| `{ transcript: true }` | Session history — was a qualifying call actually executed *before* this one | A session | `sessionDisciplines` |
|
|
103
|
+
| `{ file: … }` | Another file | The surface's reader for it | `disciplines` |
|
|
104
|
+
| `{ sidecar: true }` | The spawn-record channel | The surface's channel reader | `sessionDisciplines` |
|
|
105
|
+
|
|
106
|
+
The writing guide for these entries is [the configuration reference's `disciplines`
|
|
107
|
+
section](../configuration/index.md#disciplines); the declaration grammar is the core's
|
|
108
|
+
`algebra-declaration.schema.json`.
|
|
109
|
+
|
|
110
|
+
**Three meta-covenants** protect the judging chain. They are covenants like any other; the
|
|
111
|
+
vocabulary below applies to them unchanged.
|
|
112
|
+
|
|
113
|
+
| Registration | Axis | Judges |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| self-mod | Tool | Mutations to protected paths through editing tools. Only the call's proven mutation target is compared — a protected path inside an edit's *content* is a mention and passes |
|
|
116
|
+
| shell-mod | Shell | The same, through a command line. A command mentioning a protected path passes only if its leading word proves it read-only |
|
|
117
|
+
| transcript-mod | Transcript | Writes to the live session transcript, judged by whole-path **equality** — never as a protected ancestor |
|
|
110
118
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
**Six words** are the telemetry contract — five verdicts and one observation. A row in
|
|
120
|
+
`.polydeukes/roi.log` carries exactly one of them, and the CLI, the docs, and the tests use
|
|
121
|
+
the same word for the same event. How to read a row is in
|
|
122
|
+
[troubleshooting](../../troubleshooting.md#reading-a-verdict).
|
|
114
123
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
124
|
+
| Verdict | Means |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `passed` | The call was judged and upheld the covenant |
|
|
127
|
+
| `blocked` | The call was judged and broke it |
|
|
128
|
+
| `witnessed` | A **blocked** verdict a human opened in person. Never silent, never a clean call |
|
|
129
|
+
| `advised` | A break recorded without stopping the call — the default for every discipline entry on both surfaces, unless the entry itself says `enforce: block` |
|
|
130
|
+
| `skipped` | The call reached a registration that could not judge it. **Not a pass** — the recorded absence of a judgment |
|
|
131
|
+
| `unattributed` | A protected entry's on-disk state moved and no judgment row explains it. **Not a verdict** — no call is blocked or passed by it; the session surface writes it after comparing state against a stored baseline |
|
|
132
|
+
|
|
133
|
+
`unattributed` answers a question the other five cannot. They are all written by a judge
|
|
134
|
+
about a call it was handed, so a write that arrives without a declared call — through an
|
|
135
|
+
interpreter, a test runner's child process, a script that assembles the path from its own
|
|
136
|
+
arguments — leaves no row at all. The comparison observes the result rather than the
|
|
137
|
+
spelling, so it records that write after the fact. It never blocks: the write already
|
|
138
|
+
happened, and the comparison fails open on both sides of the verdict.
|
|
139
|
+
|
|
140
|
+
<a id="consumer-contract"></a>
|
|
141
|
+
### Where the consumer touches it
|
|
142
|
+
|
|
143
|
+
- **The `disciplines:` block** in your config. One entry compiles into one registration,
|
|
144
|
+
carrying its own telemetry label.
|
|
145
|
+
- **`protectedPaths`**, which the path-routing dispatcher matches against.
|
|
146
|
+
- **The `witness` block**, which arms the TTL valve.
|
|
147
|
+
- **`.polydeukes/roi.log`**, where every judgment lands as one row.
|
|
148
|
+
|
|
149
|
+
No import. The umbrella assembles the module for both surfaces.
|
|
150
|
+
|
|
151
|
+
<a id="limits"></a>
|
|
152
|
+
### Declared limits
|
|
153
|
+
|
|
154
|
+
- **The shell axis leaves `skipped` rows, and that row is the contract.** Predicting a
|
|
155
|
+
shell command's target from its text is undecidable, so the invariant this axis holds is
|
|
156
|
+
not "nothing gets through" — it is that **no call passes unrecorded**. A new spelling
|
|
157
|
+
landing in `skipped` is the declared limit showing itself. A pass with no row at all, or
|
|
158
|
+
one recorded `passed` without a judgment, is the defect class.
|
|
159
|
+
- **A session-only declaration on a host that proves no session records `skipped`.** The
|
|
160
|
+
entry is compiled — it is on the session surface — but the transcript the declaration binds
|
|
161
|
+
is absent, and the entry's own `supply: pass` disposes of that with a `skipped` row carrying
|
|
162
|
+
the reason `supply-pass`. With no policy the missing session is unjudgeable (exit 2), not an
|
|
163
|
+
automatic skip.
|
|
164
|
+
- **A surface never registers the other surface's list.** A `command` or transcript
|
|
165
|
+
declaration is not compiled for a change set, and a `changes` declaration is not compiled for
|
|
166
|
+
one call, so neither leaves a row on the surface that does not observe it. Which entries a
|
|
167
|
+
surface carries is read from `pdks explain` and from the config's own list names, not from
|
|
168
|
+
the telemetry log.
|
|
169
|
+
- **A declaration the compiler cannot resolve compiles to a skip registration** — routing
|
|
170
|
+
intact, no body: a step outside the registry, an argument outside a step's keys, a pattern
|
|
171
|
+
that does not compile, a paired/single mismatch. Assembly therefore never throws: one
|
|
172
|
+
unresolvable entry cannot take down its siblings, the meta-covenants, and the valve, which
|
|
173
|
+
would leave no way to fix the config that caused it. A reserved mechanism, or one whose
|
|
174
|
+
axes and relations the catalogue refuses, is a different stage: config loading rejects the
|
|
175
|
+
file (exit 2), and no skip row is written. A source the world lacks at judgment time is a
|
|
176
|
+
third case — the declaration's own `supply` policy disposes of it, and with no policy the
|
|
177
|
+
body answers unjudgeable (exit 2), never upheld.
|
|
178
|
+
- **Complete containment is a non-goal.** There are no blocklists here — enumerating bypass
|
|
179
|
+
spellings is always one step behind, so the logic is inverted: a mention of a protected
|
|
180
|
+
path blocks unless proven safe. Residual vectors such as indirect path computation are
|
|
181
|
+
telemetry targets, not block targets. The two friction valves — the read-only allowlist
|
|
182
|
+
and the TTL witness — both leave a measurable trace.
|
|
183
|
+
- **The valve stands after the verdict.** Only a judgment that actually blocked can be
|
|
184
|
+
witnessed open, a mid-sentence mention of the token does not arm it, and an AI can never
|
|
185
|
+
open the valve for itself.
|
|
119
186
|
|
|
120
187
|
<a id="polydeukes-failure-boundaries"></a>
|
|
121
188
|
## Failure boundaries
|
|
122
189
|
|
|
123
|
-
- `
|
|
124
|
-
- `runCovenantCheck()` and `runClaudeCodeHook()` never throw; they resolve to `{ exitCode: 0 \| 2
|
|
125
|
-
}`.
|
|
190
|
+
- `runCovenantCheck()` never throws; it resolves to `{ exitCode: 0 \| 2 }`.
|
|
126
191
|
- The numeric codes are `EXIT_UPHOLD` (`0`), `EXIT_BREAK_NON_BLOCKING` (`1`), and
|
|
127
192
|
`EXIT_BREAK_BLOCKING` (`2`) from `@polydeukes/core`. The umbrella runners expose only `0` or
|
|
128
193
|
`2`; they never return `1`.
|
|
129
|
-
- `pdks covenant check` prompts
|
|
130
|
-
|
|
194
|
+
- `pdks covenant check` never prompts. It reads stdin and exits 0 or 2; the caller decides what
|
|
195
|
+
that exit code means.
|
|
131
196
|
- `pdks docs` and `pdks explain` print nothing partial on failure.
|
|
132
197
|
|
|
133
198
|
<a id="polydeukes-see-also"></a>
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# `@polydeukes/sdk-ts`
|
|
2
|
+
|
|
3
|
+
[English](sdk-ts.md) · **한국어**
|
|
4
|
+
|
|
5
|
+
> **TypeScript에서 판정기로 가는 동사 하나**입니다. 약속(covenant) 입력 IR을
|
|
6
|
+
> `pdks covenant check`에 건네고 판정 결과를 값으로 돌려받습니다.
|
|
7
|
+
>
|
|
8
|
+
> 알파입니다. `polydeukes` · `@polydeukes/core`와 함께 설치하며, 둘 다 이 패키지의
|
|
9
|
+
> `peerDependencies`입니다.
|
|
10
|
+
|
|
11
|
+
<a id="ownership"></a>
|
|
12
|
+
## 담당하는 기능
|
|
13
|
+
|
|
14
|
+
스폰과, 종료 상태를 값으로 옮기는 일이 전부입니다. 판정받는 프로젝트의 `polydeukes` 설치를
|
|
15
|
+
찾고, 그 실행 파일에 입력을 표준 입력으로 넣어 돌린 뒤, 자식이 답한 것을 돌려줍니다. 판정
|
|
16
|
+
코드는 여기에 없습니다. 분기는 우산 패키지를 찾았는지와 자식이 어떤 상태로 끝났는지뿐입니다.
|
|
17
|
+
|
|
18
|
+
| 단위 | 하는 일 |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `checkCovenant` | 판정받는 프로젝트에서 `pdks covenant check`를 스폰하고 판정 결과를 돌려줍니다 |
|
|
21
|
+
| 우산 해소 | `repoRoot`의 설치 그래프에서 `polydeukes`를 찾아 `pdks` 실행 파일을 읽습니다 |
|
|
22
|
+
| 판정 결과 변환 | 종료 코드 `0`은 `upheld`, `2`는 `blocked`, 그 밖은 모두 `unjudged`입니다 |
|
|
23
|
+
|
|
24
|
+
이 패키지는 텔레메트리 행을 쓰지 않습니다. 실행이 남기는 행은 모두 판정이 일어난 자식
|
|
25
|
+
프로세스가 쓰므로, 호출 하나에 행 하나는 그대로입니다.
|
|
26
|
+
|
|
27
|
+
<a id="install"></a>
|
|
28
|
+
## 설치
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
pnpm add @polydeukes/sdk-ts polydeukes @polydeukes/core
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
실행 파일도 설치 단계도 없습니다. 우산 패키지가 SDK가 스폰할 판정기를 공급하고, 코어가
|
|
35
|
+
호출자가 채우는 `CovenantInput` 타입을 공급합니다.
|
|
36
|
+
|
|
37
|
+
<a id="verb"></a>
|
|
38
|
+
## 동사
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { checkCovenant } from '@polydeukes/sdk-ts';
|
|
42
|
+
|
|
43
|
+
const verdict = await checkCovenant({
|
|
44
|
+
repoRoot: '/path/to/the/project',
|
|
45
|
+
input: {
|
|
46
|
+
toolCalls: [
|
|
47
|
+
{
|
|
48
|
+
name: 'writeFile',
|
|
49
|
+
args: { path: 'src/index.ts', content: 'export const answer = 42;\n' },
|
|
50
|
+
fileChange: {
|
|
51
|
+
kind: 'modify',
|
|
52
|
+
path: 'src/index.ts',
|
|
53
|
+
pre: 'export const answer = 41;\n',
|
|
54
|
+
post: 'export const answer = 42;\n',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
subagentSpawns: [],
|
|
59
|
+
userMessages: [],
|
|
60
|
+
tools: { mutating: ['writeFile', 'rm'], shell: ['exec'], commandArgs: ['command'] },
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
IR은 호출자의 것입니다. 이 패키지는 IR을 읽지도 채우지도 않습니다. `session`도 `actor`도
|
|
66
|
+
자기 명부도 더하지 않으며, 위의 `tools` 값도 호출자 자신의 도구 이름입니다. `subagentSpawns`와
|
|
67
|
+
`userMessages`는 필수 배열이므로 둘 다 없는 호출자는 빈 배열을 보냅니다. `world` 키는 판정기가
|
|
68
|
+
거부합니다. 러너가 세계를 디스크의 프로젝트에서 읽으며, 클라이언트가 세계를 고르면 무엇을
|
|
69
|
+
판정할지를 고르는 것이 되기 때문입니다.
|
|
70
|
+
|
|
71
|
+
<a id="spec"></a>
|
|
72
|
+
## 스펙
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
type CheckCovenantSpec = {
|
|
76
|
+
repoRoot: string;
|
|
77
|
+
input: CovenantInput;
|
|
78
|
+
enforce?: 'advise' | 'block';
|
|
79
|
+
spawn?: (spec: CheckCovenantSpawnSpec) => Promise<{ status: number | null; stderr: string }>;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
type CheckCovenantSpawnSpec = { command: string; args: string[]; cwd: string; stdin: string };
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| 필드 | 무엇인가 |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `repoRoot` | 판정받는 프로젝트입니다. 설정 발견, 세계 축, 자식의 cwd, 우산 패키지를 찾는 설치 그래프가 모두 여기 걸립니다 |
|
|
88
|
+
| `input` | 호출자 자신의 IR이며 자식의 표준 입력으로 원문 그대로 갑니다 |
|
|
89
|
+
| `enforce` | 실행 전체에 대한 관측자의 기본 자세입니다. **적지 않으면 `block`입니다** |
|
|
90
|
+
| `spawn` | 주입하는 스폰 이음매입니다. 없으면 이 프로세스의 node 실행 파일로 자식을 띄웁니다 |
|
|
91
|
+
|
|
92
|
+
**`enforce`의 기본값은 `block`입니다.** 이것은 표면의 강제 수준이지 항목의 것이 아닙니다.
|
|
93
|
+
보호 경로와 `enforce: block`을 단 항목이 호출을 멈추고, 나머지 위반은 종료 코드 0에
|
|
94
|
+
`advised`로 기록됩니다. 항목 자신의 강제 수준은 다른 표면에서와 같이 느슨한 쪽이 이기도록
|
|
95
|
+
조합됩니다. `@polydeukes/adapter-claude-code`와 `@polydeukes/adapter-grok`도 같은 수준으로
|
|
96
|
+
판정기를 스폰합니다.
|
|
97
|
+
|
|
98
|
+
기본 스폰은 파일 서술자를 하나도 상속하지 않습니다. 호출자가 자기 서술자를 갖지 않을 수 있고,
|
|
99
|
+
상속한 stdout이 닫혀 있으면 자식이 답하기 전에 EPIPE로 죽기 때문입니다. stderr는 모아서
|
|
100
|
+
돌려주고, 판정기가 stdout에는 판정 결과를 쓰지 않으므로 stdout은 흘려보내고 버립니다.
|
|
101
|
+
|
|
102
|
+
<a id="verdicts"></a>
|
|
103
|
+
## 판정 결과 셋
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
type CheckCovenantVerdict =
|
|
107
|
+
| { verdict: 'upheld'; advisories: string }
|
|
108
|
+
| { verdict: 'blocked'; reason: string }
|
|
109
|
+
| { verdict: 'unjudged'; reason: string };
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| 판정 결과 | 자식의 상태 | 호출자에게 뜻하는 것 |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `upheld` | `0` | 호출이 판정을 받았고 아무것도 막지 않았습니다. `advisories`는 자식의 stderr 원문이며 그 실행이 낸 권고 줄을 싣습니다. 진행하면 됩니다 |
|
|
115
|
+
| `blocked` | `2` | 호출이 판정을 받았고 무언가 막았습니다. `reason`은 자식의 stderr 원문입니다. 진행하지 않습니다 |
|
|
116
|
+
| `unjudged` | 그 밖의 상태이거나 우산 패키지가 없음 | 판정이 일어나지 않았습니다. `reason`이 어느 쪽인지 말합니다. 이것을 통과로 읽으면 판정기가 설치되지 않은 프로젝트에서 모든 호출이 지나갑니다 |
|
|
117
|
+
|
|
118
|
+
**밸브가 없고 그 자리를 사유가 대신합니다.** 무인 실시간 호출자에게는 TTY도 사람의 턴도
|
|
119
|
+
없으므로, 이 패키지는 증인 인자를 받지 않고 세션을 지어내지도 않습니다. 대신
|
|
120
|
+
`blocked.reason`과 `upheld.advisories`가 데이터로 돌아오고, 그 텍스트를 이슈나 로그에 적을지
|
|
121
|
+
모델에게 돌려줄지는 소비자가 정합니다. 설정 저자와 소비자를 위한 기본 자세 규칙은
|
|
122
|
+
[규율 작성하기](../../how-to/write-disciplines.ko.md#posture)에 있습니다.
|
|
123
|
+
|
|
124
|
+
<a id="failure"></a>
|
|
125
|
+
## 실패 예제
|
|
126
|
+
|
|
127
|
+
프로젝트에 `polydeukes`가 설치돼 있지 않으면 스폰할 것이 없고, 동사는 `upheld`로 답하는 대신
|
|
128
|
+
그 사실을 말합니다.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const verdict = await checkCovenant({ repoRoot: '/tmp/project-without-polydeukes', input });
|
|
132
|
+
|
|
133
|
+
// {
|
|
134
|
+
// verdict: 'unjudged',
|
|
135
|
+
// reason: 'no polydeukes in the install graph of /tmp/project-without-polydeukes:
|
|
136
|
+
// install it to have this input judged',
|
|
137
|
+
// }
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
자식 프로세스는 돌지 않고 텔레메트리 로그에도 아무것도 더해지지 않습니다. 행은 판정이
|
|
141
|
+
일어나는 자리에 쓰이는데, 판정이 일어나지 않았기 때문입니다.
|
|
142
|
+
|
|
143
|
+
<a id="limits"></a>
|
|
144
|
+
## 선언된 한계
|
|
145
|
+
|
|
146
|
+
- **IR은 호출자가 만듭니다.** 도구 명부와 변경 전 상태와 봉투는 호스트가 아는 사실이므로,
|
|
147
|
+
그것을 아는 소비자가 채웁니다. 이 패키지는 그중 무엇도 공급하지 않습니다.
|
|
148
|
+
- **SDK가 여는 것은 세션 표면뿐입니다.** 입력이 표준 입력의 IR로 가고, 그것이 이 실행을 세션
|
|
149
|
+
표면 판정으로 만듭니다. 끝난 변경 집합을 가진 호출자는 대신 셸에서
|
|
150
|
+
`pdks covenant check --diff`에 통합 diff를 파이프합니다.
|
|
151
|
+
- **여기서는 텔레메트리 행을 쓰지 않습니다.** 행은 모두 자식이 씁니다.
|
|
152
|
+
- **`unjudged`는 통과가 아닙니다.** 판정기가 답하지 않았다는 사실을 기록하며, 판정기가 없는
|
|
153
|
+
프로젝트에서 무엇을 허용할지는 소비자가 정합니다.
|
|
154
|
+
|
|
155
|
+
<a id="see-also"></a>
|
|
156
|
+
## 함께 보기
|
|
157
|
+
|
|
158
|
+
- [`pdks covenant check`](../cli/covenant-check.ko.md)
|
|
159
|
+
- [`polydeukes`](polydeukes.ko.md)
|
|
160
|
+
- [`@polydeukes/core`](core.ko.md)
|
|
161
|
+
- [설정 참조](../configuration/index.ko.md)
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# `@polydeukes/sdk-ts`
|
|
2
|
+
|
|
3
|
+
**English** · [한국어](sdk-ts.ko.md)
|
|
4
|
+
|
|
5
|
+
> **One verb from TypeScript to the judge** — hand a covenant input IR to
|
|
6
|
+
> `pdks covenant check` and read the verdict back as a value.
|
|
7
|
+
>
|
|
8
|
+
> Alpha. Install it next to `polydeukes` and `@polydeukes/core`, which it names as
|
|
9
|
+
> `peerDependencies`.
|
|
10
|
+
|
|
11
|
+
<a id="ownership"></a>
|
|
12
|
+
## What this package owns
|
|
13
|
+
|
|
14
|
+
The spawn and the translation of an exit status into a value, and nothing else. It locates the
|
|
15
|
+
`polydeukes` install of the project being judged, runs its bin with the input on stdin, and
|
|
16
|
+
returns what the child answered. No judgment logic lives here: the branches are whether the
|
|
17
|
+
umbrella resolved and what status the child left with.
|
|
18
|
+
|
|
19
|
+
| Unit | What it does |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `checkCovenant` | Spawns `pdks covenant check` in the judged project and returns the verdict |
|
|
22
|
+
| Umbrella resolution | Finds `polydeukes` in the install graph of `repoRoot` and reads its `pdks` bin |
|
|
23
|
+
| Verdict translation | Exit `0` is `upheld`, exit `2` is `blocked`, everything else is `unjudged` |
|
|
24
|
+
|
|
25
|
+
This package writes no telemetry row. Every row a run leaves is written by the child process,
|
|
26
|
+
where the judgment happened, so one call still leaves one row.
|
|
27
|
+
|
|
28
|
+
<a id="install"></a>
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
pnpm add @polydeukes/sdk-ts polydeukes @polydeukes/core
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
There is no bin and no install step. The umbrella supplies the judge the SDK spawns, and the
|
|
36
|
+
core supplies the `CovenantInput` type the caller fills in.
|
|
37
|
+
|
|
38
|
+
<a id="verb"></a>
|
|
39
|
+
## The verb
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { checkCovenant } from '@polydeukes/sdk-ts';
|
|
43
|
+
|
|
44
|
+
const verdict = await checkCovenant({
|
|
45
|
+
repoRoot: '/path/to/the/project',
|
|
46
|
+
input: {
|
|
47
|
+
toolCalls: [
|
|
48
|
+
{
|
|
49
|
+
name: 'writeFile',
|
|
50
|
+
args: { path: 'src/index.ts', content: 'export const answer = 42;\n' },
|
|
51
|
+
fileChange: {
|
|
52
|
+
kind: 'modify',
|
|
53
|
+
path: 'src/index.ts',
|
|
54
|
+
pre: 'export const answer = 41;\n',
|
|
55
|
+
post: 'export const answer = 42;\n',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
subagentSpawns: [],
|
|
60
|
+
userMessages: [],
|
|
61
|
+
tools: { mutating: ['writeFile', 'rm'], shell: ['exec'], commandArgs: ['command'] },
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The IR is the caller's. This package neither reads it nor completes it: it adds no `session`,
|
|
67
|
+
no `actor`, and no roster of its own, and the `tools` values above are the caller's own tool
|
|
68
|
+
names. `subagentSpawns` and `userMessages` are required collections, so a caller with neither
|
|
69
|
+
sends the empty arrays. A `world` key is refused by the judge — the runner reads the world from
|
|
70
|
+
the project on disk, and a client choosing the world would be choosing what is judged.
|
|
71
|
+
|
|
72
|
+
<a id="spec"></a>
|
|
73
|
+
## The spec
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
type CheckCovenantSpec = {
|
|
77
|
+
repoRoot: string;
|
|
78
|
+
input: CovenantInput;
|
|
79
|
+
enforce?: 'advise' | 'block';
|
|
80
|
+
spawn?: (spec: CheckCovenantSpawnSpec) => Promise<{ status: number | null; stderr: string }>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
type CheckCovenantSpawnSpec = { command: string; args: string[]; cwd: string; stdin: string };
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
| Field | What it is |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `repoRoot` | The project being judged: config discovery, the world axis, the child's cwd, and the install graph the umbrella is found in |
|
|
89
|
+
| `input` | The caller's own IR, sent verbatim as the child's stdin |
|
|
90
|
+
| `enforce` | The observer's posture for the whole run. **Absent is `block`** |
|
|
91
|
+
| `spawn` | An injected spawn seam. Absent, the child runs under this process's node executable |
|
|
92
|
+
|
|
93
|
+
**`enforce` defaults to `block`.** That is the surface's level, not an entry's: protected paths
|
|
94
|
+
and entries carrying `enforce: block` stop the call, and every other break is recorded
|
|
95
|
+
`advised` at exit 0. An entry's own level composes with it lenient-side-wins, as on every other
|
|
96
|
+
surface. `@polydeukes/adapter-claude-code` and `@polydeukes/adapter-grok` spawn the judge at
|
|
97
|
+
the same level.
|
|
98
|
+
|
|
99
|
+
The default spawn inherits no file descriptor. A caller may hold none of its own, and an
|
|
100
|
+
inherited stdout that is closed would kill the child with EPIPE before it answered. stderr is
|
|
101
|
+
collected and returned; stdout is drained and dropped, because the judge writes no verdict
|
|
102
|
+
there.
|
|
103
|
+
|
|
104
|
+
<a id="verdicts"></a>
|
|
105
|
+
## The three verdicts
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
type CheckCovenantVerdict =
|
|
109
|
+
| { verdict: 'upheld'; advisories: string }
|
|
110
|
+
| { verdict: 'blocked'; reason: string }
|
|
111
|
+
| { verdict: 'unjudged'; reason: string };
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
| Verdict | Child status | What it means for the caller |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| `upheld` | `0` | The call was judged and nothing blocked it. `advisories` is the child's stderr verbatim, carrying any advisory lines the run produced. Proceed |
|
|
117
|
+
| `blocked` | `2` | The call was judged and something blocked it. `reason` is the child's stderr verbatim. Do not proceed |
|
|
118
|
+
| `unjudged` | anything else, or no umbrella | No judgment happened. `reason` says which. Reading it as an uphold would let an uninstalled judge pass every call |
|
|
119
|
+
|
|
120
|
+
**There is no valve, and the reason is the substitute.** An unattended real-time caller has no
|
|
121
|
+
TTY and no human turn, so this package takes no witness argument and invents no session.
|
|
122
|
+
`blocked.reason` and `upheld.advisories` come back as data instead, and the consumer decides
|
|
123
|
+
where the text goes — an issue, a log, or back to the model. The posture rules for a config
|
|
124
|
+
author and for a consumer are in [write disciplines](../../how-to/write-disciplines.md#posture).
|
|
125
|
+
|
|
126
|
+
<a id="failure"></a>
|
|
127
|
+
## A failure example
|
|
128
|
+
|
|
129
|
+
When the project has no `polydeukes` installed there is nothing to spawn, and the verb says so
|
|
130
|
+
rather than answering `upheld`:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
const verdict = await checkCovenant({ repoRoot: '/tmp/project-without-polydeukes', input });
|
|
134
|
+
|
|
135
|
+
// {
|
|
136
|
+
// verdict: 'unjudged',
|
|
137
|
+
// reason: 'no polydeukes in the install graph of /tmp/project-without-polydeukes:
|
|
138
|
+
// install it to have this input judged',
|
|
139
|
+
// }
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
No child process runs, and the telemetry log gains nothing: the row is written where the
|
|
143
|
+
judgment happens, and no judgment happened.
|
|
144
|
+
|
|
145
|
+
<a id="limits"></a>
|
|
146
|
+
## Declared limits
|
|
147
|
+
|
|
148
|
+
- **The caller builds the IR.** The tool roster, the pre-state, and the envelope are the
|
|
149
|
+
host's facts, so a consumer that knows them fills them in. This package supplies none of
|
|
150
|
+
them.
|
|
151
|
+
- **The SDK exposes the session surface only.** The input travels as an IR on stdin, which is
|
|
152
|
+
what makes the run a session-surface judgment. A caller that has a finished change set pipes
|
|
153
|
+
a unified diff to `pdks covenant check --diff` from its shell instead.
|
|
154
|
+
- **No telemetry row is written here.** Every row comes from the child.
|
|
155
|
+
- **An `unjudged` verdict is not a pass.** It records that the judge did not answer, and the
|
|
156
|
+
consumer decides what a project without a judge is allowed to do.
|
|
157
|
+
|
|
158
|
+
<a id="see-also"></a>
|
|
159
|
+
## See also
|
|
160
|
+
|
|
161
|
+
- [`pdks covenant check`](../cli/covenant-check.md)
|
|
162
|
+
- [`polydeukes`](polydeukes.md)
|
|
163
|
+
- [`@polydeukes/core`](core.md)
|
|
164
|
+
- [Configuration reference](../configuration/index.md)
|