@polydeukes/core 0.3.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.
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `CanonicalTranscript` — the agent-neutral session-query seam (CORE-04).
3
+ *
4
+ * Layering (PRD §1): this seam does not replace `CovenantInput`. The IR (CORE-01) is
5
+ * the *data* a covenant judges; `CanonicalTranscript` is the *behavioral seam* that
6
+ * queries session data — CORE-04 sits on top of CORE-01, and the IR is one source it
7
+ * can wrap. Concrete transcript formats stay in adapters; the core knows only the
8
+ * query vocabulary. Pure types and functions, zero I/O.
9
+ */
10
+ /**
11
+ * The injection-absent default (PRD §4.2): every query answers "nothing happened".
12
+ * A witness consumer naturally converges to fail-closed — no evidence, no skip — and
13
+ * so does a precedent consumer (no evidence, gate stays shut).
14
+ */
15
+ export const noopTranscript = {
16
+ findSubagentInvocations: () => [],
17
+ findUserMessages: () => [],
18
+ findToolCalls: () => [],
19
+ };
20
+ /**
21
+ * Wrap a {@link CovenantInput} as a {@link CanonicalTranscript} (PRD §4.2).
22
+ *
23
+ * Exposes `subagentSpawns` as invocations (filtered when a kind is given) and
24
+ * `userMessages` with `timestampMs` omitted — the bare IR cannot prove freshness,
25
+ * and that absence is the *correct* fail-closed signal for a witness consumer.
26
+ * Order preserved; the input is never mutated, and every query returns fresh
27
+ * objects so consumers never hold live aliases into the shared IR.
28
+ *
29
+ * `findToolCalls` projects each call down to `{ name, args }` only: since CORE-06 a
30
+ * call element also carries `fileChange` evidence, and evidence is judgment input, not
31
+ * session history — the two vocabularies stay separate (COVENANT-13 §4.2). `succeeded`
32
+ * stays absent for the same reason it is left three-valued: these calls are the ones
33
+ * being judged right now, so they have not run, and a call can never be its own
34
+ * precedent (COVENANT-13b §4.1).
35
+ */
36
+ export function transcriptFromInput(input) {
37
+ return {
38
+ findSubagentInvocations: (kind) => input.subagentSpawns
39
+ .filter((spawn) => kind === undefined || spawn.kind === kind)
40
+ .map((spawn) => ({ kind: spawn.kind })),
41
+ findUserMessages: () => input.userMessages.map((message) => ({ text: message.text })),
42
+ findToolCalls: (name) => input.toolCalls
43
+ .filter((call) => name === undefined || call.name === name)
44
+ // Deep copy: args nest arbitrarily (real payloads are parsed JSON), and a shallow
45
+ // spread would leave nested values as live aliases into the IR the judges share.
46
+ .map((call) => ({ name: call.name, args: structuredClone(call.args ?? {}) })),
47
+ };
48
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@polydeukes/core",
3
+ "version": "0.3.0",
4
+ "description": "Polydeukes core — covenant protocol, config loader, and transcript interface. Domain- and agent-agnostic. Alpha.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/huskyhoochu/polydeukes.git",
9
+ "directory": "packages/core"
10
+ },
11
+ "type": "module",
12
+ "main": "./dist/index.js",
13
+ "module": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ },
20
+ "./schema.json": "./schema/polydeukes.schema.json"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "schema",
25
+ "README.md"
26
+ ],
27
+ "engines": {
28
+ "node": ">=24"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^24.0.0",
35
+ "ajv": "8.20.0",
36
+ "ajv-formats": "3.0.1",
37
+ "typescript": "7.0.2",
38
+ "vitest": "^4.1.0"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc -p tsconfig.build.json",
42
+ "typecheck": "tsc --noEmit",
43
+ "test": "vitest run"
44
+ }
45
+ }
@@ -0,0 +1,200 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Polydeukes config",
4
+ "description": "Schema v2 (config as data) — equivalent to the runtime defineConfig() validator; the equivalence is enforced by a contract test.",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["languages"],
8
+ "properties": {
9
+ "$schema": {
10
+ "description": "IDE schema reference — accepted and ignored by the runtime validator.",
11
+ "type": "string"
12
+ },
13
+ "languages": {
14
+ "description": "Language axis, first-class. Keys are user values ('typescript', 'python', ...).",
15
+ "type": "object",
16
+ "minProperties": 1,
17
+ "additionalProperties": { "$ref": "#/$defs/languageProfile" }
18
+ },
19
+ "protectedPaths": {
20
+ "description": "Raw protected path patterns — normalization happens at resolve time.",
21
+ "type": "array",
22
+ "items": { "type": "string" }
23
+ },
24
+ "adapters": {
25
+ "description": "Adapter namespaces — keys are adapter names, values are each adapter's own settings object (contents not validated by the core schema).",
26
+ "type": "object",
27
+ "additionalProperties": { "type": "object" }
28
+ },
29
+ "telemetry": { "$ref": "#/$defs/telemetry" },
30
+ "disciplines": {
31
+ "description": "User-declared disciplines — validated data the covenant package compiles. Fully identical entries are copy-paste duplicates (by-id uniqueness is enforced by the runtime validator).",
32
+ "type": "array",
33
+ "uniqueItems": true,
34
+ "items": { "$ref": "#/$defs/discipline" }
35
+ },
36
+ "witness": { "$ref": "#/$defs/witness" }
37
+ },
38
+ "$defs": {
39
+ "languageProfile": {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "required": ["productionGlob", "testCmd"],
43
+ "properties": {
44
+ "productionGlob": {
45
+ "description": "What counts as production source for this language.",
46
+ "anyOf": [
47
+ { "type": "string", "minLength": 1 },
48
+ {
49
+ "type": "array",
50
+ "minItems": 1,
51
+ "items": { "type": "string", "minLength": 1 }
52
+ }
53
+ ]
54
+ },
55
+ "testCmd": {
56
+ "description": "Shell command template that verifies the given scope — every literal {scope} token is substituted at resolve time.",
57
+ "type": "string",
58
+ "minLength": 1
59
+ }
60
+ }
61
+ },
62
+ "telemetry": {
63
+ "type": "object",
64
+ "additionalProperties": false,
65
+ "properties": {
66
+ "logPath": {
67
+ "description": "Telemetry log path. Defaults to .polydeukes/roi.log when omitted.",
68
+ "type": "string"
69
+ }
70
+ }
71
+ },
72
+ "witness": {
73
+ "description": "TTL witness settings — the agreed token and validity window (minutes) consumed by the covenant valve assembly (CONFIG-05).",
74
+ "type": "object",
75
+ "additionalProperties": false,
76
+ "required": ["token", "ttlMinutes"],
77
+ "properties": {
78
+ "token": {
79
+ "description": "The agreed phrase a human types alone on a message's first line — quoting it mid-sentence is a mention, not an invocation (COVENANT-15). Must be non-empty after trimming; the value itself is free.",
80
+ "type": "string",
81
+ "minLength": 1,
82
+ "pattern": "\\S"
83
+ },
84
+ "ttlMinutes": {
85
+ "description": "Validity window in minutes from the user message's timestamp. Must be a finite number > 0.",
86
+ "type": "number",
87
+ "exclusiveMinimum": 0
88
+ }
89
+ }
90
+ },
91
+ "disciplineId": {
92
+ "description": "Unique handle — telemetry label and verdict reason prefix.",
93
+ "type": "string",
94
+ "minLength": 1
95
+ },
96
+ "disciplineWhy": {
97
+ "description": "Prose rationale, documentation only — never judged.",
98
+ "type": "string"
99
+ },
100
+ "globOrGlobs": {
101
+ "anyOf": [
102
+ { "type": "string", "minLength": 1 },
103
+ {
104
+ "type": "array",
105
+ "minItems": 1,
106
+ "items": { "type": "string", "minLength": 1 }
107
+ }
108
+ ]
109
+ },
110
+ "requirePrecedent": {
111
+ "description": "Context family — the session evidence one edit requires beforehand. Exactly one evidence key. The core owns and fully validates 'command'; every other key is adapter vocabulary whose value passes through verbatim (unconstrained here, judged by that adapter).",
112
+ "type": "object",
113
+ "minProperties": 1,
114
+ "maxProperties": 1,
115
+ "properties": {
116
+ "command": {
117
+ "description": "Core evidence vocabulary — regex over the shell command strings observed in the session.",
118
+ "type": "string",
119
+ "minLength": 1,
120
+ "format": "regex"
121
+ }
122
+ }
123
+ },
124
+ "discipline": {
125
+ "description": "One discipline entry — exactly one predicate family (forbid | immutable | forbidCommand | requirePrecedent); in/except scope the forbid and requirePrecedent families, and when scopes requirePrecedent only.",
126
+ "oneOf": [
127
+ {
128
+ "type": "object",
129
+ "additionalProperties": false,
130
+ "required": ["id", "forbid"],
131
+ "properties": {
132
+ "id": { "$ref": "#/$defs/disciplineId" },
133
+ "why": { "$ref": "#/$defs/disciplineWhy" },
134
+ "in": { "$ref": "#/$defs/globOrGlobs" },
135
+ "except": { "$ref": "#/$defs/globOrGlobs" },
136
+ "forbid": {
137
+ "description": "Delta family — string shorthand is equivalent to { added }.",
138
+ "anyOf": [
139
+ { "type": "string", "format": "regex" },
140
+ {
141
+ "type": "object",
142
+ "additionalProperties": false,
143
+ "required": ["added"],
144
+ "properties": {
145
+ "added": { "type": "string", "format": "regex" }
146
+ }
147
+ }
148
+ ]
149
+ }
150
+ }
151
+ },
152
+ {
153
+ "type": "object",
154
+ "additionalProperties": false,
155
+ "required": ["id", "immutable"],
156
+ "properties": {
157
+ "id": { "$ref": "#/$defs/disciplineId" },
158
+ "why": { "$ref": "#/$defs/disciplineWhy" },
159
+ "immutable": {
160
+ "description": "Path family — its own glob is the scope.",
161
+ "$ref": "#/$defs/globOrGlobs"
162
+ }
163
+ }
164
+ },
165
+ {
166
+ "type": "object",
167
+ "additionalProperties": false,
168
+ "required": ["id", "forbidCommand"],
169
+ "properties": {
170
+ "id": { "$ref": "#/$defs/disciplineId" },
171
+ "why": { "$ref": "#/$defs/disciplineWhy" },
172
+ "forbidCommand": {
173
+ "description": "Command family — regex over shell command strings.",
174
+ "type": "string",
175
+ "format": "regex"
176
+ }
177
+ }
178
+ },
179
+ {
180
+ "type": "object",
181
+ "additionalProperties": false,
182
+ "required": ["id", "requirePrecedent"],
183
+ "properties": {
184
+ "id": { "$ref": "#/$defs/disciplineId" },
185
+ "why": { "$ref": "#/$defs/disciplineWhy" },
186
+ "in": { "$ref": "#/$defs/globOrGlobs" },
187
+ "except": { "$ref": "#/$defs/globOrGlobs" },
188
+ "when": {
189
+ "description": "Context-family trigger — added-direction delta regex. Absent means every in-scope change triggers.",
190
+ "type": "string",
191
+ "minLength": 1,
192
+ "format": "regex"
193
+ },
194
+ "requirePrecedent": { "$ref": "#/$defs/requirePrecedent" }
195
+ }
196
+ }
197
+ ]
198
+ }
199
+ }
200
+ }