@skillstate/opencode 3.0.0 → 3.0.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.md +196 -131
- package/dist/feedback.d.ts +178 -0
- package/dist/feedback.d.ts.map +1 -0
- package/dist/feedback.js +235 -0
- package/dist/feedback.js.map +1 -0
- package/dist/index.d.ts +33 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -3
- package/dist/index.js.map +1 -1
- package/dist/mode.d.ts +97 -0
- package/dist/mode.d.ts.map +1 -0
- package/dist/mode.js +111 -0
- package/dist/mode.js.map +1 -0
- package/dist/opencode-adapter.d.ts +4 -3
- package/dist/opencode-adapter.d.ts.map +1 -1
- package/dist/opencode-adapter.js.map +1 -1
- package/dist/paper-mode.d.ts +421 -0
- package/dist/paper-mode.d.ts.map +1 -0
- package/dist/paper-mode.js +445 -0
- package/dist/paper-mode.js.map +1 -0
- package/dist/plugin.d.ts +158 -8
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +788 -21
- package/dist/plugin.js.map +1 -1
- package/dist/response-sink.d.ts +208 -0
- package/dist/response-sink.d.ts.map +1 -0
- package/dist/response-sink.js +243 -0
- package/dist/response-sink.js.map +1 -0
- package/dist/runtime.d.ts +203 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +332 -0
- package/dist/runtime.js.map +1 -0
- package/dist/spec-loader.d.ts +81 -0
- package/dist/spec-loader.d.ts.map +1 -0
- package/dist/spec-loader.js +163 -0
- package/dist/spec-loader.js.map +1 -0
- package/dist/step-boundary.d.ts +91 -0
- package/dist/step-boundary.d.ts.map +1 -0
- package/dist/step-boundary.js +109 -0
- package/dist/step-boundary.js.map +1 -0
- package/dist/system-hint.d.ts +70 -3
- package/dist/system-hint.d.ts.map +1 -1
- package/dist/system-hint.js +90 -11
- package/dist/system-hint.js.map +1 -1
- package/dist/tools.d.ts +35 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +16 -0
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
package/dist/feedback.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Corrective feedback for a rejected state patch, in paper mode.
|
|
3
|
+
*
|
|
4
|
+
* ── The hole this closes ─────────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* `PaperStateSink` computed a {@link SinkOutcome} for every assistant text
|
|
7
|
+
* block and `plugin.ts` discarded it. All seven rejection reasons were
|
|
8
|
+
* calculated and thrown away, so a model whose `state_patch` failed to parse
|
|
9
|
+
* received a byte-identical next prompt and no indication that anything had
|
|
10
|
+
* gone wrong.
|
|
11
|
+
*
|
|
12
|
+
* The consequences were not subtle. Σₜ stops moving — a model that has been
|
|
13
|
+
* silently failing for ten steps sees the same stale state each time and
|
|
14
|
+
* keeps producing output the integration cannot accept. On a long-horizon
|
|
15
|
+
* task, which is the entire reason the paper exists, that is total failure
|
|
16
|
+
* that looks like the model refusing to work.
|
|
17
|
+
*
|
|
18
|
+
* `SkillStateRuntime` does not have this problem: it owns the loop, so
|
|
19
|
+
* `runtime.ts:404` can re-prompt the model with `withRetryFeedback` and try
|
|
20
|
+
* again inside the same step. A host plugin cannot do that. It cannot invoke
|
|
21
|
+
* a tool on the model's behalf, and the v2 session API has no response hook
|
|
22
|
+
* to re-enter the model from.
|
|
23
|
+
*
|
|
24
|
+
* ── Where the feedback goes, and why there ───────────────────────────────
|
|
25
|
+
*
|
|
26
|
+
* Appendix A.4 gives the model exactly three things: P (instructions), Σₜ
|
|
27
|
+
* (state), and Oₜ (latest observation). A rejected patch is a fact about the
|
|
28
|
+
* environment — the integration refused it and can say why. That is an
|
|
29
|
+
* OBSERVATION, not an instruction, and Oₜ is where observations go.
|
|
30
|
+
*
|
|
31
|
+
* Putting it there rather than in P is not a stylistic choice:
|
|
32
|
+
*
|
|
33
|
+
* - P is the specification. Appending a correction to P would make the
|
|
34
|
+
* prompt shape drift from A.4 and, worse, would inject a *behavioural*
|
|
35
|
+
* instruction into the one surface that is supposed to be the operator's
|
|
36
|
+
* spec. `tests/opencode/system-hint.test.ts` exists precisely to keep
|
|
37
|
+
* behavioural instructions out of the model's view.
|
|
38
|
+
* - Oₜ is already the mechanism by which the host tells the model what
|
|
39
|
+
* happened. Using it keeps the change inside the paper's own shape instead
|
|
40
|
+
* of around it.
|
|
41
|
+
* - The next step's Oₜ is the tool result. Prepending the rejection to it
|
|
42
|
+
* means the model reads, in order: what you did was rejected, and here is
|
|
43
|
+
* the environment's response, and here is the tool output. That is the
|
|
44
|
+
* order the events happened in.
|
|
45
|
+
*
|
|
46
|
+
* ── Why the reason is shown once ─────────────────────────────────────────
|
|
47
|
+
*
|
|
48
|
+
* A correction that repeats forever becomes wallpaper. By step ten the model
|
|
49
|
+
* has seen the same complaint nine times and it carries no more information
|
|
50
|
+
* than a constant line in the prompt would. So a rejection is delivered to
|
|
51
|
+
* exactly the next prompt and then dropped: if the model fails the same way
|
|
52
|
+
* again, that is a fresh rejection with a fresh reason, and a reader counting
|
|
53
|
+
* the prompts can see the failure is ongoing rather than stale.
|
|
54
|
+
*
|
|
55
|
+
* This also means feedback is *not* a retry mechanism. It does not re-prompt,
|
|
56
|
+
* it does not roll back, and it does not count attempts. The host's agent
|
|
57
|
+
* loop remains the executor, and §7's bounded retry cycle stays where the
|
|
58
|
+
* paper put it — inside a runtime that can actually own the loop.
|
|
59
|
+
*
|
|
60
|
+
* @non-paper — a host-integration affordance. It uses the paper's Oₜ slot but
|
|
61
|
+
* is not prescribed by the paper.
|
|
62
|
+
*/
|
|
63
|
+
import { invalidPatchObservation } from '@skillstate/core';
|
|
64
|
+
/**
|
|
65
|
+
* Human-readable correction per rejection reason.
|
|
66
|
+
*
|
|
67
|
+
* Every reason is addressed to the model's own action, and each says what to
|
|
68
|
+
* do differently rather than merely what went wrong. A message that only
|
|
69
|
+
* reports failure gives the model nothing to correct against.
|
|
70
|
+
*
|
|
71
|
+
* `write_failed` is deliberately not here: it describes an environment fault
|
|
72
|
+
* (disk, lock, permissions), not a mistake in the model's output, and telling
|
|
73
|
+
* a model to "fix" its patch when the disk rejected the write would point it
|
|
74
|
+
* at the wrong problem.
|
|
75
|
+
*/
|
|
76
|
+
const FEEDBACK_BY_REASON = {
|
|
77
|
+
not_a_text_block: 'Your last response was not read as a completed text block, so no state patch was applied.',
|
|
78
|
+
duplicate: 'Your previous state patch was already applied and was not repeated.',
|
|
79
|
+
no_block: 'Your previous response contained no JSON block, so no state patch was applied. Respond with a ```json block holding exactly two keys: state_patch and action.',
|
|
80
|
+
malformed_json: 'The JSON block in your previous response did not parse, so no state patch was applied. Emit valid JSON inside a ```json fence.',
|
|
81
|
+
missing_state_patch: 'The JSON block in your previous response had no state_patch key, so nothing was applied. The block must have exactly two keys: state_patch and action.',
|
|
82
|
+
missing_action: 'The JSON block in your previous response had no string action key, so nothing was applied. The block must have exactly two keys: state_patch and action.',
|
|
83
|
+
schema_invalid: 'The state_patch in your previous response did not match this project\'s schema, so nothing was applied. Use only the fields the schema defines, with their declared types.',
|
|
84
|
+
empty_patch: 'Your previous state_patch was empty, so there was nothing to apply. Include at least one field you want to change, or omit the block if you have nothing to record.',
|
|
85
|
+
write_failed: 'Your previous state patch was valid but could not be written to disk, so the state is unchanged. This is an environment fault, not a problem with your patch.',
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* §6.4: the synthetic observation a failed step produces.
|
|
89
|
+
*
|
|
90
|
+
* Verbatim in shape from the paper — `Invalid state patch after N attempts:
|
|
91
|
+
* <last error>` — and the reason it exists rather than a retry continuing is
|
|
92
|
+
* that a step which has spent its attempts is a different event from one which
|
|
93
|
+
* is still trying. The model needs to know the step is over and the state was
|
|
94
|
+
* not written, or it has no way to tell a stalled loop from a slow one.
|
|
95
|
+
*
|
|
96
|
+
* Returns `''` when there is nothing to report, because `attempts` below one
|
|
97
|
+
* means no attempt was made and a synthetic observation describing zero
|
|
98
|
+
* attempts would be a sentence about nothing.
|
|
99
|
+
*/
|
|
100
|
+
/**
|
|
101
|
+
* The correction text for one rejection.
|
|
102
|
+
*
|
|
103
|
+
* Returns `''` for a reason with no entry rather than throwing or returning
|
|
104
|
+
* `undefined`. `SinkRejection` is a closed union today, so the table is total
|
|
105
|
+
* — but it is a `Record` over a type that grows, and a reason added without a
|
|
106
|
+
* message must degrade to "no correction" instead of throwing. This runs
|
|
107
|
+
* inside the plugin's event loop, where a throw would end the subscription and
|
|
108
|
+
* silently stop session scoping for the rest of the process's life.
|
|
109
|
+
*/
|
|
110
|
+
export function feedbackFor(rejection) {
|
|
111
|
+
return FEEDBACK_BY_REASON[rejection] ?? '';
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Holds at most one pending correction per session.
|
|
115
|
+
*
|
|
116
|
+
* Keyed by session, because sub-agents each write their own scope: a
|
|
117
|
+
* correction for one agent's rejected patch must not be shown to another.
|
|
118
|
+
*
|
|
119
|
+
* Bounded by construction — one string per session, overwritten by the next
|
|
120
|
+
* rejection, dropped once delivered. A long-lived server running many
|
|
121
|
+
* sessions accumulates one entry per session that has failed, which is the
|
|
122
|
+
* set of sessions worth reporting on anyway, and never more per session.
|
|
123
|
+
*/
|
|
124
|
+
export class FeedbackQueue {
|
|
125
|
+
pending = new Map();
|
|
126
|
+
/**
|
|
127
|
+
* Record the outcome of one block.
|
|
128
|
+
*
|
|
129
|
+
* An applied patch CLEARS any pending correction: the model did the right
|
|
130
|
+
* thing, so a stale complaint must not be carried into the next prompt
|
|
131
|
+
* alongside good news. Anything else leaves the previous correction in
|
|
132
|
+
* place, because a second failure before the first was delivered is still
|
|
133
|
+
* a failure, and the newest reason is the most useful one.
|
|
134
|
+
*/
|
|
135
|
+
record(sessionID, outcome) {
|
|
136
|
+
if (outcome.applied) {
|
|
137
|
+
this.pending.delete(sessionID);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (outcome.rejection === undefined)
|
|
141
|
+
return;
|
|
142
|
+
const message = feedbackFor(outcome.rejection);
|
|
143
|
+
// A rejection with no mapped message must not clear a deliverable one:
|
|
144
|
+
// showing a slightly stale reason beats showing none.
|
|
145
|
+
if (message.length > 0)
|
|
146
|
+
this.pending.set(sessionID, message);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Take the pending correction for a session, if any, and clear it.
|
|
150
|
+
*
|
|
151
|
+
* Consuming on read is what makes the correction show up exactly once. A
|
|
152
|
+
* caller that only ever peeked would turn a one-step correction into a
|
|
153
|
+
* permanent line in the prompt.
|
|
154
|
+
*/
|
|
155
|
+
take(sessionID) {
|
|
156
|
+
const message = this.pending.get(sessionID);
|
|
157
|
+
if (message === undefined)
|
|
158
|
+
return undefined;
|
|
159
|
+
this.pending.delete(sessionID);
|
|
160
|
+
return message;
|
|
161
|
+
}
|
|
162
|
+
/** Peek without consuming. For diagnostics and tests. */
|
|
163
|
+
peek(sessionID) {
|
|
164
|
+
return this.pending.get(sessionID);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Take the pending correction only if no synthetic observation is owed.
|
|
168
|
+
*
|
|
169
|
+
* §6.4: when every attempt fails, the step's observation is the synthetic
|
|
170
|
+
* `Invalid state patch after N attempts: <last error>` — not the running
|
|
171
|
+
* correction, and not nothing. Delivering both would show the model two
|
|
172
|
+
* complaints, one of which is stale by definition: the correction belongs to
|
|
173
|
+
* the attempt that just ended, while the synthetic observation reports the
|
|
174
|
+
* whole step.
|
|
175
|
+
*
|
|
176
|
+
* The correction is still cleared when it is dropped. Holding it would put
|
|
177
|
+
* the same reason in front of the model a second time, on the next step,
|
|
178
|
+
* where it would be describing a step that is over.
|
|
179
|
+
*/
|
|
180
|
+
takeUnlessInvalidated(sessionID, attempts, lastError) {
|
|
181
|
+
const message = this.pending.get(sessionID);
|
|
182
|
+
this.pending.delete(sessionID);
|
|
183
|
+
// `||` and not `??`: a synthetic observation for zero attempts is the empty
|
|
184
|
+
// string, and `'' ?? message` keeps the empty string. That would silence a
|
|
185
|
+
// real correction with a sentence about nothing, which is the one outcome
|
|
186
|
+
// this method exists to avoid.
|
|
187
|
+
return invalidPatchObservation(attempts, lastError) || message;
|
|
188
|
+
}
|
|
189
|
+
/** Forget everything (test isolation, plugin reload). */
|
|
190
|
+
clear() {
|
|
191
|
+
this.pending.clear();
|
|
192
|
+
}
|
|
193
|
+
/** How many sessions currently hold a pending correction. */
|
|
194
|
+
get size() {
|
|
195
|
+
return this.pending.size;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Prepend a correction to an observation.
|
|
200
|
+
*
|
|
201
|
+
* The observation is a single line in A.4 (`Latest Observation: …`), so the
|
|
202
|
+
* two are joined on one line rather than separated by a blank line that the
|
|
203
|
+
* template does not have. The correction is marked so the model can tell it
|
|
204
|
+
* apart from environment output — without a marker, a correction would be
|
|
205
|
+
* indistinguishable from a tool result, and the model could reasonably read
|
|
206
|
+
* it as data rather than as a report about its own last turn.
|
|
207
|
+
*
|
|
208
|
+
* A blank observation is left to carry the correction alone rather than
|
|
209
|
+
* becoming `"prefix: "`, which would read as a message addressed to nobody.
|
|
210
|
+
*/
|
|
211
|
+
export function applyFeedback(observation, feedback) {
|
|
212
|
+
if (feedback === undefined || feedback.length === 0)
|
|
213
|
+
return observation;
|
|
214
|
+
return applyObservation(observation, '[state patch rejected]', feedback);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Prepend a line from the environment to the observation slot.
|
|
218
|
+
*
|
|
219
|
+
* Shared by the two things the environment has to say to the model — a patch
|
|
220
|
+
* it refused, and an action it is carrying out — because they need the same
|
|
221
|
+
* shape and must not be told apart by accident.
|
|
222
|
+
*
|
|
223
|
+
* The marker is a parameter for exactly that reason. An earlier version reused
|
|
224
|
+
* {@link applyFeedback} for both, and the hard-coded
|
|
225
|
+
* `[state patch rejected]` would have told the model its patch was refused at
|
|
226
|
+
* the very moment the runtime was accepting it and asking for the next step —
|
|
227
|
+
* a message not merely useless but actively false, and the kind of false that
|
|
228
|
+
* makes a model re-derive state it has already recorded.
|
|
229
|
+
*/
|
|
230
|
+
export function applyObservation(observation, marker, line) {
|
|
231
|
+
if (line.length === 0)
|
|
232
|
+
return observation;
|
|
233
|
+
return observation.length === 0 ? `${marker} ${line}` : `${marker} ${line}\n${observation}`;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.js","sourceRoot":"","sources":["../src/feedback.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* module and calls `setup(ctx)`. Everything else is exported for tests and
|
|
7
7
|
* for embedders that want the pieces without the plugin lifecycle.
|
|
8
8
|
*
|
|
9
|
-
* See `plugin.ts` for the design contract, in particular
|
|
10
|
-
*
|
|
9
|
+
* See `plugin.ts` for the design contract, in particular that notes mode
|
|
10
|
+
* (the default) never mutates `event.messages`.
|
|
11
11
|
*/
|
|
12
12
|
export { SkillStatePlugin, PLUGIN_ID, default } from './plugin.js';
|
|
13
13
|
/**
|
|
@@ -22,8 +22,38 @@ export { SessionRegistry, stateScopeFor, DEFAULT_SESSION_TTL_MS, } from './sessi
|
|
|
22
22
|
export type { SessionRecord, SessionRegistryOptions } from './session-registry.js';
|
|
23
23
|
export { ProjectStateStore, diffDocuments, mergeDocuments, statePathFor, } from './state-store.js';
|
|
24
24
|
export type { StateChanges, StateDocument, ProjectStateStoreOptions, } from './state-store.js';
|
|
25
|
-
export { buildStateHint, renderStateForHint, ADVERTISED_TOOLS, MAX_INLINE_STATE_CHARS, } from './system-hint.js';
|
|
25
|
+
export { buildStateHint, renderStateForHint, ADVERTISED_TOOLS, DRIFT_NOTICE_AFTER_TURNS, MAX_INLINE_STATE_CHARS, } from './system-hint.js';
|
|
26
26
|
export type { StateHintOptions } from './system-hint.js';
|
|
27
27
|
export { registerTools, normalizePatch, MAX_PATCH_BYTES } from './tools.js';
|
|
28
28
|
export type { MergeValue, ReadValue, ToolDeps, ToolError, ToolOk, ToolResult, UpdateValue, } from './tools.js';
|
|
29
|
+
/**
|
|
30
|
+
* Paper mode — the A.4 context replacement. Pure functions plus the two
|
|
31
|
+
* halves of the write (`buildPaperPrompt` reads, `applyPaperContext`
|
|
32
|
+
* writes); the plugin composes them in `plugin.ts`.
|
|
33
|
+
*/
|
|
34
|
+
export { PAPER_MESSAGE_ID, applyPaperContext, HOST_ACTION_NOTE, buildPaperPrompt, currentInstruction, latestObservation, proceduralSpecWithTask, } from './paper-mode.js';
|
|
35
|
+
export type { ObservationSource, PaperContextEvent, PaperMessage, PaperObservation, PaperPrompt, PaperPromptOptions, } from './paper-mode.js';
|
|
36
|
+
/** The Σₜ sink that closes the paper transition in the OpenCode host. */
|
|
37
|
+
export { DEFAULT_DEDUPE_CAPACITY, PaperStateSink, isTextEnded } from './response-sink.js';
|
|
38
|
+
export type { PaperStateSinkOptions, SinkOutcome, SinkRejection } from './response-sink.js';
|
|
39
|
+
/** Corrective feedback for a rejected patch, carried in the A.4 observation. */
|
|
40
|
+
export { FeedbackQueue, applyFeedback, applyObservation, feedbackFor } from './feedback.js';
|
|
41
|
+
export type { PendingFeedback } from './feedback.js';
|
|
42
|
+
/** `SKILLSTATE_DEBUG_PROMPT` diagnostic — what the host actually handed us. */
|
|
43
|
+
export { dumpPromptShape, dumpDrift } from './plugin.js';
|
|
44
|
+
/** `SKILLSTATE_DEBUG_STEPS` diagnostic — what the paper step loop did, per step. */
|
|
45
|
+
export { dumpStepTrace } from './plugin.js';
|
|
46
|
+
/** `SKILLSTATE_MAX_STEPS` — the runtime-driven step ceiling, or the default. */
|
|
47
|
+
export { maxStepsFromEnv } from './plugin.js';
|
|
48
|
+
/** The runtime that owns the paper-mode step loop. */
|
|
49
|
+
export { RuntimeDriver, DEFAULT_MAX_STEPS, DEFAULT_VALIDATION_RETRIES, INVALID_PATCH, } from './runtime.js';
|
|
50
|
+
/** §5.1's one-observation-per-step boundary, enforced by withholding tools. */
|
|
51
|
+
export { StepBoundary, isTerminalAction } from './step-boundary.js';
|
|
52
|
+
export type { RuntimeDriverOptions, RuntimeStep } from './runtime.js';
|
|
53
|
+
/** Mode resolution — `SKILLSTATE_MODE` over `skillstate.json` over default. */
|
|
54
|
+
export { DEFAULT_PLUGIN_MODE, MODE_ENV_VAR, PLUGIN_MODES, asPluginMode, resolvePluginMode, } from './mode.js';
|
|
55
|
+
export type { ModeResolution, ModeSource, PluginMode, ResolveModeOptions } from './mode.js';
|
|
56
|
+
/** Resolving P for paper mode. */
|
|
57
|
+
export { SPEC_FILE_NAME, SpecResolver, parseSpec } from './spec-loader.js';
|
|
58
|
+
export type { SpecResolution, SpecSource } from './spec-loader.js';
|
|
29
59
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACnE;;;;;;GAMG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,aAAa,EACb,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,YAAY,EACZ,aAAa,EACb,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5E,YAAY,EACV,UAAU,EACV,SAAS,EACT,QAAQ,EACR,SAAS,EACT,MAAM,EACN,UAAU,EACV,WAAW,GACZ,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACnE;;;;;;GAMG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,aAAa,EACb,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,YAAY,EACZ,aAAa,EACb,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5E,YAAY,EACV,UAAU,EACV,SAAS,EACT,QAAQ,EACR,SAAS,EACT,MAAM,EACN,UAAU,EACV,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB;;;;GAIG;AACH,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,yEAAyE;AACzE,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC1F,YAAY,EAAE,qBAAqB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC5F,gFAAgF;AAChF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5F,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,+EAA+E;AAC/E,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,oFAAoF;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,sDAAsD;AACtD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,0BAA0B,EAC1B,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACpE,YAAY,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACtE,+EAA+E;AAC/E,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC5F,kCAAkC;AAClC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC3E,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* module and calls `setup(ctx)`. Everything else is exported for tests and
|
|
7
7
|
* for embedders that want the pieces without the plugin lifecycle.
|
|
8
8
|
*
|
|
9
|
-
* See `plugin.ts` for the design contract, in particular
|
|
10
|
-
*
|
|
9
|
+
* See `plugin.ts` for the design contract, in particular that notes mode
|
|
10
|
+
* (the default) never mutates `event.messages`.
|
|
11
11
|
*/
|
|
12
12
|
export { SkillStatePlugin, PLUGIN_ID, default } from './plugin.js';
|
|
13
13
|
/**
|
|
@@ -20,6 +20,30 @@ export { SkillStatePlugin, PLUGIN_ID, default } from './plugin.js';
|
|
|
20
20
|
export { OpenCodeAdapter } from './opencode-adapter.js';
|
|
21
21
|
export { SessionRegistry, stateScopeFor, DEFAULT_SESSION_TTL_MS, } from './session-registry.js';
|
|
22
22
|
export { ProjectStateStore, diffDocuments, mergeDocuments, statePathFor, } from './state-store.js';
|
|
23
|
-
export { buildStateHint, renderStateForHint, ADVERTISED_TOOLS, MAX_INLINE_STATE_CHARS, } from './system-hint.js';
|
|
23
|
+
export { buildStateHint, renderStateForHint, ADVERTISED_TOOLS, DRIFT_NOTICE_AFTER_TURNS, MAX_INLINE_STATE_CHARS, } from './system-hint.js';
|
|
24
24
|
export { registerTools, normalizePatch, MAX_PATCH_BYTES } from './tools.js';
|
|
25
|
+
/**
|
|
26
|
+
* Paper mode — the A.4 context replacement. Pure functions plus the two
|
|
27
|
+
* halves of the write (`buildPaperPrompt` reads, `applyPaperContext`
|
|
28
|
+
* writes); the plugin composes them in `plugin.ts`.
|
|
29
|
+
*/
|
|
30
|
+
export { PAPER_MESSAGE_ID, applyPaperContext, HOST_ACTION_NOTE, buildPaperPrompt, currentInstruction, latestObservation, proceduralSpecWithTask, } from './paper-mode.js';
|
|
31
|
+
/** The Σₜ sink that closes the paper transition in the OpenCode host. */
|
|
32
|
+
export { DEFAULT_DEDUPE_CAPACITY, PaperStateSink, isTextEnded } from './response-sink.js';
|
|
33
|
+
/** Corrective feedback for a rejected patch, carried in the A.4 observation. */
|
|
34
|
+
export { FeedbackQueue, applyFeedback, applyObservation, feedbackFor } from './feedback.js';
|
|
35
|
+
/** `SKILLSTATE_DEBUG_PROMPT` diagnostic — what the host actually handed us. */
|
|
36
|
+
export { dumpPromptShape, dumpDrift } from './plugin.js';
|
|
37
|
+
/** `SKILLSTATE_DEBUG_STEPS` diagnostic — what the paper step loop did, per step. */
|
|
38
|
+
export { dumpStepTrace } from './plugin.js';
|
|
39
|
+
/** `SKILLSTATE_MAX_STEPS` — the runtime-driven step ceiling, or the default. */
|
|
40
|
+
export { maxStepsFromEnv } from './plugin.js';
|
|
41
|
+
/** The runtime that owns the paper-mode step loop. */
|
|
42
|
+
export { RuntimeDriver, DEFAULT_MAX_STEPS, DEFAULT_VALIDATION_RETRIES, INVALID_PATCH, } from './runtime.js';
|
|
43
|
+
/** §5.1's one-observation-per-step boundary, enforced by withholding tools. */
|
|
44
|
+
export { StepBoundary, isTerminalAction } from './step-boundary.js';
|
|
45
|
+
/** Mode resolution — `SKILLSTATE_MODE` over `skillstate.json` over default. */
|
|
46
|
+
export { DEFAULT_PLUGIN_MODE, MODE_ENV_VAR, PLUGIN_MODES, asPluginMode, resolvePluginMode, } from './mode.js';
|
|
47
|
+
/** Resolving P for paper mode. */
|
|
48
|
+
export { SPEC_FILE_NAME, SpecResolver, parseSpec } from './spec-loader.js';
|
|
25
49
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACnE;;;;;;GAMG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,aAAa,EACb,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACnE;;;;;;GAMG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,aAAa,EACb,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAU5E;;;;GAIG;AACH,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AASzB,yEAAyE;AACzE,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE1F,gFAAgF;AAChF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5F,+EAA+E;AAC/E,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,oFAAoF;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,sDAAsD;AACtD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,0BAA0B,EAC1B,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEpE,+EAA+E;AAC/E,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,kCAAkC;AAClC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/mode.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which integration the plugin runs as.
|
|
3
|
+
*
|
|
4
|
+
* ── Why this is a first-class, resolved value ─────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* The two modes are not variants of one behaviour; they are different
|
|
7
|
+
* contracts with the model, and picking the wrong one is a defect:
|
|
8
|
+
*
|
|
9
|
+
* - **`notes`** (default) contributes one additive, bounded fragment to
|
|
10
|
+
* `event.system` and never touches `event.messages`. The transcript is the
|
|
11
|
+
* host's; the agent sees its own history the way the host intends. This is
|
|
12
|
+
* the mode that fixed the v1 failure, and it is the default for exactly
|
|
13
|
+
* that reason.
|
|
14
|
+
* - **`paper`** replaces the model-facing context with Aₜ = (P, Σₜ, Oₜ) and
|
|
15
|
+
* applies the `state_patch` the model emits. That is the paper's
|
|
16
|
+
* specification, and it is a real behavioural change: the model stops
|
|
17
|
+
* seeing its own transcript. It is opt-in.
|
|
18
|
+
*
|
|
19
|
+
* The default therefore has to be `notes`, and resolving it must be
|
|
20
|
+
* deterministic and inspectable — a plugin that silently picks paper mode
|
|
21
|
+
* because of a stray environment variable in a CI image would reproduce the
|
|
22
|
+
* exact failure this package exists to prevent.
|
|
23
|
+
*
|
|
24
|
+
* ── Precedence ───────────────────────────────────────────────────────────
|
|
25
|
+
*
|
|
26
|
+
* `SKILLSTATE_MODE` (environment) > `mode` in `<project>/skillstate.json`
|
|
27
|
+
* (file) > {@link DEFAULT_PLUGIN_MODE}. Environment wins, matching every
|
|
28
|
+
* other `SKILLSTATE_*` variable in `packages/core/src/config.ts`.
|
|
29
|
+
*
|
|
30
|
+
* ── Invalid values are reported, not swallowed ────────────────────────────
|
|
31
|
+
*
|
|
32
|
+
* A typo must not quietly select a mode nobody asked for. An unrecognised
|
|
33
|
+
* value falls back to the default AND is recorded in
|
|
34
|
+
* {@link ModeResolution.rejected}, so a caller (or a test) can see that the
|
|
35
|
+
* request was not honoured. Nothing throws: a bad config file must never
|
|
36
|
+
* stop the agent loop.
|
|
37
|
+
*/
|
|
38
|
+
/** The integration modes the plugin can run as. */
|
|
39
|
+
export type PluginMode = 'notes' | 'paper';
|
|
40
|
+
/** Every accepted mode value, in documentation order. */
|
|
41
|
+
export declare const PLUGIN_MODES: readonly PluginMode[];
|
|
42
|
+
/**
|
|
43
|
+
* The mode used when nothing valid selects one.
|
|
44
|
+
*
|
|
45
|
+
* `notes`, deliberately. Paper mode discards the transcript, and a
|
|
46
|
+
* default that discards the user's task is the v1 bug with a new name.
|
|
47
|
+
*/
|
|
48
|
+
export declare const DEFAULT_PLUGIN_MODE: PluginMode;
|
|
49
|
+
/** The environment variable that selects the mode. */
|
|
50
|
+
export declare const MODE_ENV_VAR = "SKILLSTATE_MODE";
|
|
51
|
+
/** Where the resolved value came from. */
|
|
52
|
+
export type ModeSource = 'default' | 'file' | 'env';
|
|
53
|
+
/** The outcome of {@link resolvePluginMode}. */
|
|
54
|
+
export interface ModeResolution {
|
|
55
|
+
/** The mode to run. Always a valid {@link PluginMode}. */
|
|
56
|
+
readonly mode: PluginMode;
|
|
57
|
+
/** Which input won. */
|
|
58
|
+
readonly source: ModeSource;
|
|
59
|
+
/** The winning input verbatim, for diagnostics. Absent for the default. */
|
|
60
|
+
readonly raw?: string;
|
|
61
|
+
/**
|
|
62
|
+
* A value that was present but not understood, and therefore ignored.
|
|
63
|
+
* Set when a higher-precedence input was invalid — the fallback is
|
|
64
|
+
* reported here rather than applied silently.
|
|
65
|
+
*/
|
|
66
|
+
readonly rejected?: string;
|
|
67
|
+
/** True when `rejected` came from a higher-precedence input than `raw`. */
|
|
68
|
+
readonly rejectedOverridesValid?: boolean;
|
|
69
|
+
}
|
|
70
|
+
/** Narrow an arbitrary value to a {@link PluginMode}. */
|
|
71
|
+
export declare function asPluginMode(value: unknown): PluginMode | undefined;
|
|
72
|
+
/** Options for {@link resolvePluginMode}. */
|
|
73
|
+
export interface ResolveModeOptions {
|
|
74
|
+
/** The project directory holding `skillstate.json`. */
|
|
75
|
+
readonly directory: string;
|
|
76
|
+
/**
|
|
77
|
+
* Environment to read. Defaults to `process.env`; tests pass their own so
|
|
78
|
+
* resolution is deterministic and never leaks between test cases.
|
|
79
|
+
*/
|
|
80
|
+
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the plugin mode for one project.
|
|
84
|
+
*
|
|
85
|
+
* Never throws: a missing file, a corrupt file, a non-string `mode`, an
|
|
86
|
+
* unknown mode and a non-string environment value all resolve to
|
|
87
|
+
* {@link DEFAULT_PLUGIN_MODE}, and every rejected value is reported in the
|
|
88
|
+
* result so a caller can surface it.
|
|
89
|
+
*
|
|
90
|
+
* An invalid environment value does NOT fall through to the file. The
|
|
91
|
+
* environment is the higher-precedence input; if it says something
|
|
92
|
+
* unrecognised, quietly honouring a lower-precedence source instead would
|
|
93
|
+
* make the effective mode depend on a value the operator did not set. The
|
|
94
|
+
* default is used and the rejection is recorded.
|
|
95
|
+
*/
|
|
96
|
+
export declare function resolvePluginMode(options: ResolveModeOptions): ModeResolution;
|
|
97
|
+
//# sourceMappingURL=mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode.d.ts","sourceRoot":"","sources":["../src/mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAKH,mDAAmD;AACnD,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC;AAE3C,yDAAyD;AACzD,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAAuB,CAAC;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAAoB,CAAC;AAEvD,sDAAsD;AACtD,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAE9C,0CAA0C;AAC1C,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC;AAEpD,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,uBAAuB;IACvB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAC3C;AAED,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAMnE;AAmBD,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;CAC7D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,cAAc,CAkB7E"}
|
package/dist/mode.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which integration the plugin runs as.
|
|
3
|
+
*
|
|
4
|
+
* ── Why this is a first-class, resolved value ─────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* The two modes are not variants of one behaviour; they are different
|
|
7
|
+
* contracts with the model, and picking the wrong one is a defect:
|
|
8
|
+
*
|
|
9
|
+
* - **`notes`** (default) contributes one additive, bounded fragment to
|
|
10
|
+
* `event.system` and never touches `event.messages`. The transcript is the
|
|
11
|
+
* host's; the agent sees its own history the way the host intends. This is
|
|
12
|
+
* the mode that fixed the v1 failure, and it is the default for exactly
|
|
13
|
+
* that reason.
|
|
14
|
+
* - **`paper`** replaces the model-facing context with Aₜ = (P, Σₜ, Oₜ) and
|
|
15
|
+
* applies the `state_patch` the model emits. That is the paper's
|
|
16
|
+
* specification, and it is a real behavioural change: the model stops
|
|
17
|
+
* seeing its own transcript. It is opt-in.
|
|
18
|
+
*
|
|
19
|
+
* The default therefore has to be `notes`, and resolving it must be
|
|
20
|
+
* deterministic and inspectable — a plugin that silently picks paper mode
|
|
21
|
+
* because of a stray environment variable in a CI image would reproduce the
|
|
22
|
+
* exact failure this package exists to prevent.
|
|
23
|
+
*
|
|
24
|
+
* ── Precedence ───────────────────────────────────────────────────────────
|
|
25
|
+
*
|
|
26
|
+
* `SKILLSTATE_MODE` (environment) > `mode` in `<project>/skillstate.json`
|
|
27
|
+
* (file) > {@link DEFAULT_PLUGIN_MODE}. Environment wins, matching every
|
|
28
|
+
* other `SKILLSTATE_*` variable in `packages/core/src/config.ts`.
|
|
29
|
+
*
|
|
30
|
+
* ── Invalid values are reported, not swallowed ────────────────────────────
|
|
31
|
+
*
|
|
32
|
+
* A typo must not quietly select a mode nobody asked for. An unrecognised
|
|
33
|
+
* value falls back to the default AND is recorded in
|
|
34
|
+
* {@link ModeResolution.rejected}, so a caller (or a test) can see that the
|
|
35
|
+
* request was not honoured. Nothing throws: a bad config file must never
|
|
36
|
+
* stop the agent loop.
|
|
37
|
+
*/
|
|
38
|
+
import * as fs from 'node:fs';
|
|
39
|
+
import * as path from 'node:path';
|
|
40
|
+
/** Every accepted mode value, in documentation order. */
|
|
41
|
+
export const PLUGIN_MODES = ['notes', 'paper'];
|
|
42
|
+
/**
|
|
43
|
+
* The mode used when nothing valid selects one.
|
|
44
|
+
*
|
|
45
|
+
* `notes`, deliberately. Paper mode discards the transcript, and a
|
|
46
|
+
* default that discards the user's task is the v1 bug with a new name.
|
|
47
|
+
*/
|
|
48
|
+
export const DEFAULT_PLUGIN_MODE = 'notes';
|
|
49
|
+
/** The environment variable that selects the mode. */
|
|
50
|
+
export const MODE_ENV_VAR = 'SKILLSTATE_MODE';
|
|
51
|
+
/** Narrow an arbitrary value to a {@link PluginMode}. */
|
|
52
|
+
export function asPluginMode(value) {
|
|
53
|
+
if (typeof value !== 'string')
|
|
54
|
+
return undefined;
|
|
55
|
+
const normalized = value.trim().toLowerCase();
|
|
56
|
+
return PLUGIN_MODES.includes(normalized)
|
|
57
|
+
? normalized
|
|
58
|
+
: undefined;
|
|
59
|
+
}
|
|
60
|
+
function readModeFromFile(directory) {
|
|
61
|
+
let raw;
|
|
62
|
+
try {
|
|
63
|
+
raw = fs.readFileSync(path.join(directory, 'skillstate.json'), 'utf-8');
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(raw);
|
|
70
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
71
|
+
return undefined;
|
|
72
|
+
const mode = parsed.mode;
|
|
73
|
+
return typeof mode === 'string' ? mode : undefined;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Resolve the plugin mode for one project.
|
|
81
|
+
*
|
|
82
|
+
* Never throws: a missing file, a corrupt file, a non-string `mode`, an
|
|
83
|
+
* unknown mode and a non-string environment value all resolve to
|
|
84
|
+
* {@link DEFAULT_PLUGIN_MODE}, and every rejected value is reported in the
|
|
85
|
+
* result so a caller can surface it.
|
|
86
|
+
*
|
|
87
|
+
* An invalid environment value does NOT fall through to the file. The
|
|
88
|
+
* environment is the higher-precedence input; if it says something
|
|
89
|
+
* unrecognised, quietly honouring a lower-precedence source instead would
|
|
90
|
+
* make the effective mode depend on a value the operator did not set. The
|
|
91
|
+
* default is used and the rejection is recorded.
|
|
92
|
+
*/
|
|
93
|
+
export function resolvePluginMode(options) {
|
|
94
|
+
const { directory, env = process.env } = options;
|
|
95
|
+
const fromEnv = env[MODE_ENV_VAR];
|
|
96
|
+
if (typeof fromEnv === 'string') {
|
|
97
|
+
const mode = asPluginMode(fromEnv);
|
|
98
|
+
if (mode !== undefined)
|
|
99
|
+
return { mode, source: 'env', raw: fromEnv };
|
|
100
|
+
return { mode: DEFAULT_PLUGIN_MODE, source: 'env', rejected: fromEnv };
|
|
101
|
+
}
|
|
102
|
+
const fromFile = readModeFromFile(directory);
|
|
103
|
+
if (fromFile !== undefined) {
|
|
104
|
+
const mode = asPluginMode(fromFile);
|
|
105
|
+
if (mode !== undefined)
|
|
106
|
+
return { mode, source: 'file', raw: fromFile };
|
|
107
|
+
return { mode: DEFAULT_PLUGIN_MODE, source: 'file', rejected: fromFile };
|
|
108
|
+
}
|
|
109
|
+
return { mode: DEFAULT_PLUGIN_MODE, source: 'default' };
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=mode.js.map
|
package/dist/mode.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode.js","sourceRoot":"","sources":["../src/mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAKlC,yDAAyD;AACzD,MAAM,CAAC,MAAM,YAAY,GAA0B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAe,OAAO,CAAC;AAEvD,sDAAsD;AACtD,MAAM,CAAC,MAAM,YAAY,GAAG,iBAAiB,CAAC;AAuB9C,yDAAyD;AACzD,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9C,OAAQ,YAAkC,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC7D,CAAC,CAAE,UAAyB;QAC5B,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB;IACzC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC;QACpE,MAAM,IAAI,GAAI,MAA6B,CAAC,IAAI,CAAC;QACjD,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAaD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;IAEjD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC;IAClC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;QACrE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACzE,CAAC;IAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;QACvE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAC3E,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC1D,CAAC"}
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
* Host glue is NO LONGER GENERATED by this adapter:
|
|
9
9
|
* - the plugin is the npm package `@skillstate/opencode` itself, loaded
|
|
10
10
|
* directly from the project `opencode.json`
|
|
11
|
-
* `"
|
|
12
|
-
* `
|
|
13
|
-
*
|
|
11
|
+
* `"plugins": ["@skillstate/opencode"]` (see `SkillStatePlugin` in
|
|
12
|
+
* `src/plugin.ts` — project-local and inert when the project has no
|
|
13
|
+
* skillstate state). NOTE: this adapter is the PAPER surface only; it is
|
|
14
|
+
* not the host integration, and the v2 plugin does not call it;
|
|
14
15
|
* - skill markdown (SKILL.md) generation is host-neutral and lives in the
|
|
15
16
|
* CLI, not in the platform adapters.
|
|
16
17
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-adapter.d.ts","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"opencode-adapter.d.ts","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACX,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAI1B;;GAEG;AACH,qBAAa,eAAgB,YAAW,eAAe;IACrD,QAAQ,CAAC,IAAI,cAAc;IAE3B,OAAO,CAAC,WAAW,CAAmD;IAEtE;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,GAAG,MAAM,CAe3D;IAED;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAEhD;IAED;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7C;IAED;;;;;OAKG;IACH,YAAY,CACV,KAAK,EAAE,UAAU,EACjB,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,cAAc,GACnB,MAAM,CAER;CAOF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-adapter.js","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"opencode-adapter.js","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExE;;GAEG;AACH,MAAM,OAAO,eAAe;IACjB,IAAI,GAAG,UAAU,CAAC;IAEnB,WAAW,GAAG,IAAI,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAEtE;;;;OAIG;IACH,WAAW,CAAC,KAAiB,EAAE,IAAoB;QACjD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE/C,OAAO,gBAAgB,IAAI,CAAC,EAAE;gBAClB,IAAI,CAAC,YAAY;EAC/B,UAAU;;EAEV,SAAS;;;;;;EAMT,oBAAoB,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,QAAgB;QAC3B,OAAO,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,QAAgB;QAC5B,OAAO,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAClD,CAAC;IAED;;;;;OAKG;IACH,YAAY,CACV,KAAiB,EACjB,WAAwB,EACxB,IAAoB;QAEpB,OAAO,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IACtE,CAAC;CAOF"}
|