@polydeukes/core 0.6.1 → 0.8.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/README.ko.md +1 -1
- package/README.md +1 -1
- package/dist/algebra.d.ts +9 -0
- package/dist/algebra.js +32 -1
- package/dist/catalogue.d.ts +7 -0
- package/dist/catalogue.js +12 -4
- package/dist/config.d.ts +15 -1
- package/dist/config.js +75 -10
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/protocol.d.ts +37 -0
- package/dist/transcript.d.ts +15 -0
- package/dist/transcript.js +26 -0
- package/package.json +4 -3
- package/schema/polydeukes.schema.json +12 -0
package/README.ko.md
CHANGED
|
@@ -47,4 +47,4 @@ const payload = parseInput('{"toolCalls":[],"subagentSpawns":[],"userMessages":[
|
|
|
47
47
|
|
|
48
48
|
- [`@polydeukes/core` 패키지 레퍼런스](../../docs/reference/packages/core.ko.md)
|
|
49
49
|
- [`설정 레퍼런스`](../../docs/reference/configuration/index.ko.md)
|
|
50
|
-
- [
|
|
50
|
+
- [판정기(`covenant` 모듈)](../../docs/reference/packages/polydeukes.ko.md#covenant-module)
|
package/README.md
CHANGED
|
@@ -47,4 +47,4 @@ const payload = parseInput('{"toolCalls":[],"subagentSpawns":[],"userMessages":[
|
|
|
47
47
|
|
|
48
48
|
- [`@polydeukes/core` package reference](../../docs/reference/packages/core.md)
|
|
49
49
|
- [`Configuration reference`](../../docs/reference/configuration/index.md)
|
|
50
|
-
- [
|
|
50
|
+
- [The judge (`covenant` module)](../../docs/reference/packages/polydeukes.md#covenant-module)
|
package/dist/algebra.d.ts
CHANGED
|
@@ -172,3 +172,12 @@ export type Witnesses = readonly Witness[];
|
|
|
172
172
|
* `location`, so a caller validating many declarations sees which one failed.
|
|
173
173
|
*/
|
|
174
174
|
export declare function validateAlgebraDeclaration(input: unknown, location?: string): AlgebraDeclaration;
|
|
175
|
+
/**
|
|
176
|
+
* `DeclarationChannel` — one evidence channel a declaration binds.
|
|
177
|
+
*
|
|
178
|
+
* `transcript` · `channel` · `command` · `actor` are what a live call carries and `changes`
|
|
179
|
+
* is what a finished change set carries, so the set a declaration reads decides which
|
|
180
|
+
* surfaces can observe it at all.
|
|
181
|
+
*/
|
|
182
|
+
export type DeclarationChannel = 'transcript' | 'channel' | 'command' | 'actor' | 'changes';
|
|
183
|
+
export declare function declarationChannels(body: Omit<AlgebraDeclaration, 'discipline'>): DeclarationChannel[];
|
package/dist/algebra.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* The module knows no judgment. It runs no extraction and evaluates no relation; the
|
|
6
6
|
* kernel expansion laws quoted on each relation branch below are comments, never code.
|
|
7
7
|
*/
|
|
8
|
-
import { validateMechanism } from './catalogue.js';
|
|
8
|
+
import { sourceNames, validateMechanism } from './catalogue.js';
|
|
9
9
|
import { isPlainObject } from './is-plain-object.js';
|
|
10
10
|
import { FIXED_SOURCE_NAMES } from './source-names.js';
|
|
11
11
|
import { ConfigValidationError, isNonEmptyString, isStringArray, rejectUncompilableRegex, rejectUnknownKeys, } from './validation.js';
|
|
@@ -436,3 +436,34 @@ export function validateAlgebraDeclaration(input, location = 'declaration') {
|
|
|
436
436
|
validateMechanism(declaration, location);
|
|
437
437
|
return declaration;
|
|
438
438
|
}
|
|
439
|
+
/** The fixed order of a derived channel list. */
|
|
440
|
+
const DECLARATION_CHANNELS = [
|
|
441
|
+
'transcript',
|
|
442
|
+
'channel',
|
|
443
|
+
'command',
|
|
444
|
+
'actor',
|
|
445
|
+
'changes',
|
|
446
|
+
];
|
|
447
|
+
export function declarationChannels(body) {
|
|
448
|
+
const found = new Set();
|
|
449
|
+
const sources = isPlainObject(body.sources) ? body.sources : {};
|
|
450
|
+
for (const binding of Object.values(sources)) {
|
|
451
|
+
if (!isPlainObject(binding))
|
|
452
|
+
continue;
|
|
453
|
+
if ('transcript' in binding)
|
|
454
|
+
found.add('transcript');
|
|
455
|
+
if ('sidecar' in binding)
|
|
456
|
+
found.add('channel');
|
|
457
|
+
}
|
|
458
|
+
if (isPlainObject(body.scope) && body.scope.source === 'command')
|
|
459
|
+
found.add('command');
|
|
460
|
+
for (const name of sourceNames(body)) {
|
|
461
|
+
if (name === 'command')
|
|
462
|
+
found.add('command');
|
|
463
|
+
if (name === 'actor')
|
|
464
|
+
found.add('actor');
|
|
465
|
+
if (name === 'changes')
|
|
466
|
+
found.add('changes');
|
|
467
|
+
}
|
|
468
|
+
return DECLARATION_CHANNELS.filter((channel) => found.has(channel));
|
|
469
|
+
}
|
package/dist/catalogue.d.ts
CHANGED
|
@@ -45,6 +45,13 @@ export type DerivedShape = {
|
|
|
45
45
|
};
|
|
46
46
|
/** Every name's spec. The `Record` type pins the keys to {@link MECHANISM_NAMES}. */
|
|
47
47
|
export declare const MECHANISM_SHAPES: Record<MechanismName, MechanismShape>;
|
|
48
|
+
/** Every source name the body and the valve read, in declaration order. */
|
|
49
|
+
export declare function sourceNames(declaration: {
|
|
50
|
+
extract?: unknown;
|
|
51
|
+
witness?: {
|
|
52
|
+
extract?: unknown;
|
|
53
|
+
} | undefined;
|
|
54
|
+
}): string[];
|
|
48
55
|
/**
|
|
49
56
|
* Read one declaration's shape from its syntax (pure).
|
|
50
57
|
*
|
package/dist/catalogue.js
CHANGED
|
@@ -101,12 +101,19 @@ function quotedList(names) {
|
|
|
101
101
|
function isTranscriptSource(binding) {
|
|
102
102
|
return isPlainObject(binding) && binding.transcript === true;
|
|
103
103
|
}
|
|
104
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* The source names one extract block's `source` steps name, in declaration order.
|
|
106
|
+
*
|
|
107
|
+
* Tolerant of an unvalidated block: a pipeline that is not a list, or a step that is not an
|
|
108
|
+
* object, names nothing here and is refused by the grammar validator with its location.
|
|
109
|
+
*/
|
|
105
110
|
function sourceNamesOf(extract) {
|
|
106
|
-
if (extract
|
|
111
|
+
if (!isPlainObject(extract))
|
|
107
112
|
return [];
|
|
108
113
|
const names = [];
|
|
109
114
|
for (const steps of Object.values(extract)) {
|
|
115
|
+
if (!Array.isArray(steps))
|
|
116
|
+
continue;
|
|
110
117
|
for (const step of steps) {
|
|
111
118
|
if (isPlainObject(step) && step.op === 'source' && typeof step.of === 'string') {
|
|
112
119
|
names.push(step.of);
|
|
@@ -116,8 +123,9 @@ function sourceNamesOf(extract) {
|
|
|
116
123
|
return names;
|
|
117
124
|
}
|
|
118
125
|
/** Every source name the body and the valve read, in declaration order. */
|
|
119
|
-
function sourceNames(declaration) {
|
|
120
|
-
|
|
126
|
+
export function sourceNames(declaration) {
|
|
127
|
+
const witness = isPlainObject(declaration.witness) ? declaration.witness : undefined;
|
|
128
|
+
return [...sourceNamesOf(declaration.extract), ...sourceNamesOf(witness?.extract)];
|
|
121
129
|
}
|
|
122
130
|
/**
|
|
123
131
|
* Read one declaration's shape from its syntax (pure).
|
package/dist/config.d.ts
CHANGED
|
@@ -95,8 +95,18 @@ export type PolydeukesConfig = {
|
|
|
95
95
|
/** conventional default applies when omitted */
|
|
96
96
|
logPath?: string;
|
|
97
97
|
};
|
|
98
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* user-declared disciplines both surfaces observe — every entry whose declaration binds
|
|
100
|
+
* no evidence channel, plus the drafts. Validated here, compiled by the covenant package
|
|
101
|
+
*/
|
|
99
102
|
disciplines?: (DisciplineEntry | DisciplineDraft)[];
|
|
103
|
+
/**
|
|
104
|
+
* disciplines only the session surface observes — every entry binding at least one of
|
|
105
|
+
* `transcript` · `channel` · `command` · `actor` and never `changes`
|
|
106
|
+
*/
|
|
107
|
+
sessionDisciplines?: DisciplineEntry[];
|
|
108
|
+
/** disciplines only the change-set surface observes — every entry binding `changes` */
|
|
109
|
+
changeSetDisciplines?: DisciplineEntry[];
|
|
100
110
|
/**
|
|
101
111
|
* TTL witness values for the covenant valve seam — consumed at assembly time,
|
|
102
112
|
* validated here
|
|
@@ -141,6 +151,10 @@ export type ResolvedConfig = {
|
|
|
141
151
|
* declared a `disciplines` array, holding exactly its judged entries in order.
|
|
142
152
|
*/
|
|
143
153
|
disciplines?: DisciplineEntry[];
|
|
154
|
+
/** validated session-surface entries, present whenever the input declared the list */
|
|
155
|
+
sessionDisciplines?: DisciplineEntry[];
|
|
156
|
+
/** validated change-set-surface entries, present whenever the input declared the list */
|
|
157
|
+
changeSetDisciplines?: DisciplineEntry[];
|
|
144
158
|
/** validated drafts in declaration order (absent when the input carries none) */
|
|
145
159
|
drafts?: DisciplineDraft[];
|
|
146
160
|
/** validated witness data, passed through verbatim (absent stays absent) */
|
package/dist/config.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* saw. It stays a pure function — no file I/O and no runtime dependencies: validation is
|
|
7
7
|
* hand-rolled, and the published JSON Schema is a sibling artifact this source never reads.
|
|
8
8
|
*/
|
|
9
|
-
import { validateAlgebraDeclaration } from './algebra.js';
|
|
9
|
+
import { declarationChannels, validateAlgebraDeclaration, } from './algebra.js';
|
|
10
10
|
import { isPlainObject } from './is-plain-object.js';
|
|
11
11
|
import { ConfigValidationError, isNonEmptyString, isStringArray, rejectUnknownKeys, } from './validation.js';
|
|
12
12
|
export { ConfigValidationError } from './validation.js';
|
|
@@ -21,6 +21,8 @@ const TOP_LEVEL_KEYS = new Set([
|
|
|
21
21
|
'adapters',
|
|
22
22
|
'telemetry',
|
|
23
23
|
'disciplines',
|
|
24
|
+
'sessionDisciplines',
|
|
25
|
+
'changeSetDisciplines',
|
|
24
26
|
'witness',
|
|
25
27
|
]);
|
|
26
28
|
const PROFILE_KEYS = new Set(['productionGlob', 'testCmd']);
|
|
@@ -94,26 +96,66 @@ function validateDeclareEntry(entry, location) {
|
|
|
94
96
|
}
|
|
95
97
|
validateAlgebraDeclaration({ discipline: entry.id, ...block }, `${location} declare`);
|
|
96
98
|
}
|
|
99
|
+
/** The three list names an entry can be written in — also the destinations of a misplacement. */
|
|
100
|
+
const DISCIPLINE_LISTS = ['disciplines', 'sessionDisciplines', 'changeSetDisciplines'];
|
|
101
|
+
/** The channels only a live call carries; `changes` is the one only a change set carries. */
|
|
102
|
+
const SESSION_CHANNELS = [
|
|
103
|
+
'transcript',
|
|
104
|
+
'channel',
|
|
105
|
+
'command',
|
|
106
|
+
'actor',
|
|
107
|
+
];
|
|
97
108
|
/**
|
|
98
|
-
*
|
|
109
|
+
* The list an entry's declaration belongs in, from the channels it binds — or `undefined`
|
|
110
|
+
* when it binds both a session channel and `changes`, which no surface observes at once.
|
|
111
|
+
*/
|
|
112
|
+
function listFor(channels) {
|
|
113
|
+
const readsSession = channels.some((channel) => SESSION_CHANNELS.includes(channel));
|
|
114
|
+
const readsChanges = channels.includes('changes');
|
|
115
|
+
if (readsSession && readsChanges)
|
|
116
|
+
return undefined;
|
|
117
|
+
if (readsSession)
|
|
118
|
+
return 'sessionDisciplines';
|
|
119
|
+
if (readsChanges)
|
|
120
|
+
return 'changeSetDisciplines';
|
|
121
|
+
return 'disciplines';
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Refuse a judged entry written in a list the surface it needs does not read. The channels
|
|
125
|
+
* its declaration binds are the whole answer, so the message names them and the destination:
|
|
126
|
+
* an author who is told only that the placement is wrong meets the same error again.
|
|
127
|
+
*/
|
|
128
|
+
function checkPlacement(entry, list, location) {
|
|
129
|
+
const channels = declarationChannels(entry.declare);
|
|
130
|
+
const destination = listFor(channels);
|
|
131
|
+
if (destination === undefined) {
|
|
132
|
+
throw new ConfigValidationError(`${location} reads ${channels.join(', ')}: no surface observes both changes and a session channel`);
|
|
133
|
+
}
|
|
134
|
+
if (destination !== list) {
|
|
135
|
+
const reads = channels.length === 0 ? 'no evidence channel' : channels.join(', ');
|
|
136
|
+
throw new ConfigValidationError(`${location} reads ${reads}: it belongs in ${destination}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Validate one discipline list and split judged entries from drafts. Throws
|
|
99
141
|
* {@link ConfigValidationError} naming the offending entry/key; the validated data passes
|
|
100
|
-
* through verbatim, in declaration order.
|
|
142
|
+
* through verbatim, in declaration order. `seenIds` spans the three lists and the meta
|
|
143
|
+
* labels, so a label the telemetry space already carries is refused wherever it is written.
|
|
101
144
|
*/
|
|
102
|
-
function validateDisciplines(disciplines) {
|
|
145
|
+
function validateDisciplines(disciplines, list, seenIds) {
|
|
103
146
|
if (!Array.isArray(disciplines)) {
|
|
104
|
-
throw new ConfigValidationError(
|
|
147
|
+
throw new ConfigValidationError(`${list} must be an array`);
|
|
105
148
|
}
|
|
106
149
|
const judged = [];
|
|
107
150
|
const drafts = [];
|
|
108
|
-
const seenIds = new Set();
|
|
109
151
|
disciplines.forEach((entry, index) => {
|
|
110
152
|
if (!isPlainObject(entry)) {
|
|
111
|
-
throw new ConfigValidationError(
|
|
153
|
+
throw new ConfigValidationError(`${list}[${index}] must be an object`);
|
|
112
154
|
}
|
|
113
155
|
if (typeof entry.id !== 'string' || entry.id.length === 0) {
|
|
114
|
-
throw new ConfigValidationError(
|
|
156
|
+
throw new ConfigValidationError(`${list}[${index}].id must be a non-empty string`);
|
|
115
157
|
}
|
|
116
|
-
const location =
|
|
158
|
+
const location = `${list}[${index}] ('${entry.id}')`;
|
|
117
159
|
if (seenIds.has(entry.id)) {
|
|
118
160
|
throw new ConfigValidationError(`${location} duplicates the id of an earlier entry`);
|
|
119
161
|
}
|
|
@@ -127,10 +169,20 @@ function validateDisciplines(disciplines) {
|
|
|
127
169
|
// Selected by the marker's value, so an explicit `draft: undefined` is absence,
|
|
128
170
|
// like every other optional key in this validator.
|
|
129
171
|
if (entry.draft !== undefined) {
|
|
172
|
+
// A draft carries no declaration, so it binds no channel and there is nothing for a
|
|
173
|
+
// surface list to observe.
|
|
174
|
+
if (list !== 'disciplines') {
|
|
175
|
+
throw new ConfigValidationError(`${location} a draft belongs in disciplines`);
|
|
176
|
+
}
|
|
130
177
|
drafts.push(validateDraft(entry, entry.id, location));
|
|
131
178
|
return;
|
|
132
179
|
}
|
|
133
180
|
validateEntryHead(entry, location);
|
|
181
|
+
// Placement first: the derivation is syntactic, so an entry in the wrong list is told
|
|
182
|
+
// where it belongs rather than meeting a grammar error the move would not fix.
|
|
183
|
+
if (isPlainObject(entry.declare)) {
|
|
184
|
+
checkPlacement(entry, list, location);
|
|
185
|
+
}
|
|
134
186
|
validateDeclareEntry(entry, location);
|
|
135
187
|
judged.push(entry);
|
|
136
188
|
});
|
|
@@ -250,7 +302,18 @@ export function defineConfig(config) {
|
|
|
250
302
|
const resolvedLanguages = validateLanguages(config.languages);
|
|
251
303
|
const protectedPaths = config.protectedPaths !== undefined ? validateProtectedPaths(config.protectedPaths) : undefined;
|
|
252
304
|
const adapters = config.adapters !== undefined ? validateAdapters(config.adapters) : undefined;
|
|
253
|
-
|
|
305
|
+
// One id space across the three lists and the meta labels: `explain` and every
|
|
306
|
+
// label-keyed telemetry reader index by the label alone.
|
|
307
|
+
const seenIds = new Set();
|
|
308
|
+
const split = config.disciplines !== undefined
|
|
309
|
+
? validateDisciplines(config.disciplines, 'disciplines', seenIds)
|
|
310
|
+
: undefined;
|
|
311
|
+
const sessionDisciplines = config.sessionDisciplines !== undefined
|
|
312
|
+
? validateDisciplines(config.sessionDisciplines, 'sessionDisciplines', seenIds).judged
|
|
313
|
+
: undefined;
|
|
314
|
+
const changeSetDisciplines = config.changeSetDisciplines !== undefined
|
|
315
|
+
? validateDisciplines(config.changeSetDisciplines, 'changeSetDisciplines', seenIds).judged
|
|
316
|
+
: undefined;
|
|
254
317
|
const disciplines = split?.judged;
|
|
255
318
|
const drafts = split !== undefined && split.drafts.length > 0 ? split.drafts : undefined;
|
|
256
319
|
const logPath = config.telemetry !== undefined ? validateTelemetry(config.telemetry) : undefined;
|
|
@@ -263,6 +326,8 @@ export function defineConfig(config) {
|
|
|
263
326
|
logPath: logPath ?? DEFAULT_TELEMETRY_LOG_PATH,
|
|
264
327
|
},
|
|
265
328
|
...(disciplines !== undefined && { disciplines }),
|
|
329
|
+
...(sessionDisciplines !== undefined && { sessionDisciplines }),
|
|
330
|
+
...(changeSetDisciplines !== undefined && { changeSetDisciplines }),
|
|
266
331
|
...(drafts !== undefined && { drafts }),
|
|
267
332
|
...(witness !== undefined && { witness }),
|
|
268
333
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (appendRecord / readRecords / appendRecordFailOpen).
|
|
7
7
|
* See https://github.com/huskyhoochu/polydeukes
|
|
8
8
|
*/
|
|
9
|
-
export { type AlgebraDeclaration, BINARY_COMBINATOR_NAMES, type BinaryStep, type ExtractBlock, type ExtractStep, RELATION_NAMES, type RelateEntry, type RelationDecl, type RelationName, type ScopeBlock, SUPPLY_POLICIES, type SupplyBlock, type UnaryStep, validateAlgebraDeclaration, type Witness, type WitnessBlock, type Witnesses, } from './algebra.ts';
|
|
9
|
+
export { type AlgebraDeclaration, BINARY_COMBINATOR_NAMES, type BinaryStep, type DeclarationChannel, declarationChannels, type ExtractBlock, type ExtractStep, RELATION_NAMES, type RelateEntry, type RelationDecl, type RelationName, type ScopeBlock, SUPPLY_POLICIES, type SupplyBlock, type UnaryStep, validateAlgebraDeclaration, type Witness, type WitnessBlock, type Witnesses, } from './algebra.ts';
|
|
10
10
|
export { AXIS_NAMES, type Axis, type DerivableDeclaration, deriveShape, MECHANISM_NAMES, MECHANISM_SHAPES, type MechanismName, type MechanismShape, } from './catalogue.ts';
|
|
11
11
|
export { type AlgebraDeclarationBody, ConfigValidationError, DEFAULT_TELEMETRY_LOG_PATH, type DisciplineDraft, type DisciplineEntry, defineConfig, type EnforceLevel, type LanguageProfile, type PolydeukesConfig, type ResolvedConfig, type ResolvedLanguageProfile, } from './config.ts';
|
|
12
12
|
export { EXIT_BREAK_BLOCKING, EXIT_BREAK_NON_BLOCKING, EXIT_UPHOLD, } from './exit-codes.ts';
|
|
@@ -15,4 +15,4 @@ export { isPlainObject } from './is-plain-object.ts';
|
|
|
15
15
|
export { normalizeProtectedPaths } from './protected-paths.ts';
|
|
16
16
|
export { allFileChanges, type ChannelReader, type CovenantInput, type CovenantVerdict, type DispatchOutcome, type FileChange, parseInput, type SourceReader, verdictToExitCode, } from './protocol.ts';
|
|
17
17
|
export { aggregateGain, appendRecord, appendRecordFailOpen, formatRecordLine, type GainSummary, parseRecordLine, readRecords, runGain, SKIP_REASONS, type SkipReason, type TelemetryEvent, type TelemetryRecord, } from './telemetry.ts';
|
|
18
|
-
export { type CanonicalTranscript, noopTranscript, type TranscriptToolCall, type TranscriptUserMessage, transcriptFromInput, } from './transcript.ts';
|
|
18
|
+
export { type CanonicalTranscript, noopTranscript, type TranscriptToolCall, type TranscriptUserMessage, transcriptFromInput, transcriptFromSession, } from './transcript.ts';
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (appendRecord / readRecords / appendRecordFailOpen).
|
|
7
7
|
* See https://github.com/huskyhoochu/polydeukes
|
|
8
8
|
*/
|
|
9
|
-
export { BINARY_COMBINATOR_NAMES, RELATION_NAMES, SUPPLY_POLICIES, validateAlgebraDeclaration, } from './algebra.js';
|
|
9
|
+
export { BINARY_COMBINATOR_NAMES, declarationChannels, RELATION_NAMES, SUPPLY_POLICIES, validateAlgebraDeclaration, } from './algebra.js';
|
|
10
10
|
export { AXIS_NAMES, deriveShape, MECHANISM_NAMES, MECHANISM_SHAPES, } from './catalogue.js';
|
|
11
11
|
export { ConfigValidationError, DEFAULT_TELEMETRY_LOG_PATH, defineConfig, } from './config.js';
|
|
12
12
|
export { EXIT_BREAK_BLOCKING, EXIT_BREAK_NON_BLOCKING, EXIT_UPHOLD, } from './exit-codes.js';
|
|
@@ -15,4 +15,4 @@ export { isPlainObject } from './is-plain-object.js';
|
|
|
15
15
|
export { normalizeProtectedPaths } from './protected-paths.js';
|
|
16
16
|
export { allFileChanges, parseInput, verdictToExitCode, } from './protocol.js';
|
|
17
17
|
export { aggregateGain, appendRecord, appendRecordFailOpen, formatRecordLine, parseRecordLine, readRecords, runGain, SKIP_REASONS, } from './telemetry.js';
|
|
18
|
-
export { noopTranscript, transcriptFromInput, } from './transcript.js';
|
|
18
|
+
export { noopTranscript, transcriptFromInput, transcriptFromSession, } from './transcript.js';
|
package/dist/protocol.d.ts
CHANGED
|
@@ -91,6 +91,43 @@ export type CovenantInput = {
|
|
|
91
91
|
* declaration's own supply policy.
|
|
92
92
|
*/
|
|
93
93
|
actor?: Actor;
|
|
94
|
+
/**
|
|
95
|
+
* The host's tool roster — values, never vocabulary: `mutating` names the tools whose
|
|
96
|
+
* calls change a file, `shell` the ones carrying a command line, and `commandArgs` the
|
|
97
|
+
* argument keys that command line travels in. Absence leaves the runner on its own
|
|
98
|
+
* default roster.
|
|
99
|
+
*/
|
|
100
|
+
tools?: {
|
|
101
|
+
mutating: string[];
|
|
102
|
+
shell: string[];
|
|
103
|
+
commandArgs: string[];
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The evidence a live agent session carries that the repository's disk does not. Absence
|
|
107
|
+
* is the absence of a session; a session whose lists are empty is a host that named its
|
|
108
|
+
* evidence and could not deliver it.
|
|
109
|
+
*
|
|
110
|
+
* `evidencePath` is where that evidence was read from, so a surface can protect the file
|
|
111
|
+
* the session is judged from. `userMessages` carries `timestampMs` because a session can
|
|
112
|
+
* prove freshness a bare IR cannot, and `toolCalls` carries `succeeded` because a session
|
|
113
|
+
* can prove a call's outcome. `channels` is the host's own evidence channel text — a
|
|
114
|
+
* runner lifts it into the world it dispatches.
|
|
115
|
+
*/
|
|
116
|
+
session?: {
|
|
117
|
+
evidencePath?: string;
|
|
118
|
+
userMessages: {
|
|
119
|
+
text: string;
|
|
120
|
+
timestampMs?: number;
|
|
121
|
+
}[];
|
|
122
|
+
toolCalls: {
|
|
123
|
+
name: string;
|
|
124
|
+
args?: Record<string, unknown>;
|
|
125
|
+
succeeded?: boolean;
|
|
126
|
+
}[];
|
|
127
|
+
channels?: {
|
|
128
|
+
sidecar?: string;
|
|
129
|
+
};
|
|
130
|
+
};
|
|
94
131
|
};
|
|
95
132
|
/**
|
|
96
133
|
* `CovenantVerdict` — the result a covenant body produces.
|
package/dist/transcript.d.ts
CHANGED
|
@@ -64,3 +64,18 @@ export declare const noopTranscript: CanonicalTranscript;
|
|
|
64
64
|
* being judged right now: they have not run, and a call can never be its own precedent.
|
|
65
65
|
*/
|
|
66
66
|
export declare function transcriptFromInput(input: CovenantInput): CanonicalTranscript;
|
|
67
|
+
/**
|
|
68
|
+
* Wrap a {@link CovenantInput}'s `session` as a {@link CanonicalTranscript}.
|
|
69
|
+
*
|
|
70
|
+
* Differs from {@link transcriptFromInput} on exactly the two facts a session proves and a
|
|
71
|
+
* bare IR cannot: `findUserMessages` carries `timestampMs` through, so a witness consumer
|
|
72
|
+
* can read freshness, and `findToolCalls` carries `succeeded` through, so a precedent
|
|
73
|
+
* consumer can read outcome. Both keys stay ABSENT where the session had none — a filled-in
|
|
74
|
+
* timestamp would open a valve from nothing, and a filled-in outcome would turn a call
|
|
75
|
+
* nobody observed into evidence. An absent `args` reads as `{}` because the transcript type
|
|
76
|
+
* requires the field.
|
|
77
|
+
*
|
|
78
|
+
* Order preserved; the input is never mutated, and every query returns fresh objects — args
|
|
79
|
+
* deep-copied — so consumers never hold live aliases into the shared IR.
|
|
80
|
+
*/
|
|
81
|
+
export declare function transcriptFromSession(session: NonNullable<CovenantInput['session']>): CanonicalTranscript;
|
package/dist/transcript.js
CHANGED
|
@@ -38,3 +38,29 @@ export function transcriptFromInput(input) {
|
|
|
38
38
|
.map((call) => ({ name: call.name, args: structuredClone(call.args ?? {}) })),
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Wrap a {@link CovenantInput}'s `session` as a {@link CanonicalTranscript}.
|
|
43
|
+
*
|
|
44
|
+
* Differs from {@link transcriptFromInput} on exactly the two facts a session proves and a
|
|
45
|
+
* bare IR cannot: `findUserMessages` carries `timestampMs` through, so a witness consumer
|
|
46
|
+
* can read freshness, and `findToolCalls` carries `succeeded` through, so a precedent
|
|
47
|
+
* consumer can read outcome. Both keys stay ABSENT where the session had none — a filled-in
|
|
48
|
+
* timestamp would open a valve from nothing, and a filled-in outcome would turn a call
|
|
49
|
+
* nobody observed into evidence. An absent `args` reads as `{}` because the transcript type
|
|
50
|
+
* requires the field.
|
|
51
|
+
*
|
|
52
|
+
* Order preserved; the input is never mutated, and every query returns fresh objects — args
|
|
53
|
+
* deep-copied — so consumers never hold live aliases into the shared IR.
|
|
54
|
+
*/
|
|
55
|
+
export function transcriptFromSession(session) {
|
|
56
|
+
return {
|
|
57
|
+
findUserMessages: () => session.userMessages.map((message) => ({ ...message })),
|
|
58
|
+
findToolCalls: (name) => session.toolCalls
|
|
59
|
+
.filter((call) => name === undefined || call.name === name)
|
|
60
|
+
.map((call) => ({
|
|
61
|
+
name: call.name,
|
|
62
|
+
args: structuredClone(call.args ?? {}),
|
|
63
|
+
...(call.succeeded === undefined ? {} : { succeeded: call.succeeded }),
|
|
64
|
+
})),
|
|
65
|
+
};
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polydeukes/core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Polydeukes core — covenant protocol, config loader, and transcript interface. Domain- and agent-agnostic.
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "Polydeukes core — covenant protocol, config loader, and transcript interface. Domain- and agent-agnostic. Beta.",
|
|
5
|
+
"author": "huskyhoochu <dfg1499@gmail.com>",
|
|
5
6
|
"license": "MIT",
|
|
6
7
|
"repository": {
|
|
7
8
|
"type": "git",
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
"ajv": "8.20.0",
|
|
37
38
|
"ajv-formats": "3.0.1",
|
|
38
39
|
"typescript": "7.0.2",
|
|
39
|
-
"vitest": "^
|
|
40
|
+
"vitest": "^5.0.0"
|
|
40
41
|
},
|
|
41
42
|
"scripts": {
|
|
42
43
|
"build": "tsc -p tsconfig.build.json",
|
|
@@ -33,6 +33,18 @@
|
|
|
33
33
|
"uniqueItems": true,
|
|
34
34
|
"items": { "$ref": "#/$defs/discipline" }
|
|
35
35
|
},
|
|
36
|
+
"sessionDisciplines": {
|
|
37
|
+
"description": "Disciplines only the session surface observes — every entry whose declaration binds a transcript, channel, command, or actor evidence channel. Fully identical entries are copy-paste duplicates (by-id uniqueness and the placement rule are enforced by the runtime validator).",
|
|
38
|
+
"type": "array",
|
|
39
|
+
"uniqueItems": true,
|
|
40
|
+
"items": { "$ref": "#/$defs/discipline" }
|
|
41
|
+
},
|
|
42
|
+
"changeSetDisciplines": {
|
|
43
|
+
"description": "Disciplines only the change-set surface observes — every entry whose declaration binds the changes source. Fully identical entries are copy-paste duplicates (by-id uniqueness and the placement rule are enforced by the runtime validator).",
|
|
44
|
+
"type": "array",
|
|
45
|
+
"uniqueItems": true,
|
|
46
|
+
"items": { "$ref": "#/$defs/discipline" }
|
|
47
|
+
},
|
|
36
48
|
"witness": { "$ref": "#/$defs/witness" }
|
|
37
49
|
},
|
|
38
50
|
"$defs": {
|