@skillstate/opencode 2.0.6 → 2.1.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/dist/opencode-adapter.d.ts +0 -4
- package/dist/opencode-adapter.d.ts.map +1 -1
- package/dist/opencode-adapter.js +7 -34
- package/dist/opencode-adapter.js.map +1 -1
- package/dist/plugin.d.ts +18 -26
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +24 -84
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
|
@@ -79,9 +79,5 @@ export declare class OpenCodeAdapter implements PlatformAdapter {
|
|
|
79
79
|
* Returns the absolute destination path.
|
|
80
80
|
*/
|
|
81
81
|
savePluginCode(target: string | StatePathRef, options?: GeneratePluginOptions): Promise<string>;
|
|
82
|
-
/**
|
|
83
|
-
* Describe the schema fields for inclusion in prompts.
|
|
84
|
-
*/
|
|
85
|
-
private describeSchema;
|
|
86
82
|
}
|
|
87
83
|
//# sourceMappingURL=opencode-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-adapter.d.ts","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACX,eAAe,EAChB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"opencode-adapter.d.ts","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACX,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAW1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,8DAA8D;AAC9D,MAAM,WAAW,qBAAqB;IACpC,0DAA0D;IAC1D,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;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;IAED;;;;;;;OAOG;IACH,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAkChE;IAED;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAa1D;IAED;;;;;OAKG;IACG,cAAc,CAClB,MAAM,EAAE,MAAM,GAAG,YAAY,EAC7B,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAOjB;CAKF"}
|
package/dist/opencode-adapter.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PromptTransformer } from '@skillstate/core';
|
|
2
|
-
import { atomicWriteFile, resolveStatePath, } from '@skillstate/core';
|
|
2
|
+
import { atomicWriteFile, describeSchema, REASONING_DISCARDED_NOTE, resolveStatePath, STATE_PATCH_CONTRACT, } from '@skillstate/core';
|
|
3
3
|
/**
|
|
4
4
|
* OpenCode platform adapter (@non-paper; see module doc).
|
|
5
5
|
*/
|
|
@@ -13,7 +13,7 @@ export class OpenCodeAdapter {
|
|
|
13
13
|
*/
|
|
14
14
|
injectState(state, spec) {
|
|
15
15
|
const stateJson = JSON.stringify(state);
|
|
16
|
-
const schemaDesc =
|
|
16
|
+
const schemaDesc = describeSchema(spec.schema);
|
|
17
17
|
return `<skill name="${spec.id}">
|
|
18
18
|
<instructions>${spec.instructions}</instructions>
|
|
19
19
|
${schemaDesc}
|
|
@@ -22,16 +22,9 @@ ${stateJson}
|
|
|
22
22
|
</state>
|
|
23
23
|
</skill>
|
|
24
24
|
|
|
25
|
-
Respond with
|
|
25
|
+
Respond with:
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
"state_patch": { "key": "new_value", "obsolete_key": null },
|
|
30
|
-
"action": "your_action_here"
|
|
31
|
-
}
|
|
32
|
-
\`\`\`
|
|
33
|
-
|
|
34
|
-
In \`state_patch\`, set keys to null to delete them. Only include fields you want to change. Omit fields to leave them unchanged.`;
|
|
27
|
+
${STATE_PATCH_CONTRACT}`;
|
|
35
28
|
}
|
|
36
29
|
/**
|
|
37
30
|
* Extract the state_patch from an LLM response containing a fenced JSON block.
|
|
@@ -89,20 +82,12 @@ plugin; only the current state and the latest observation matter.
|
|
|
89
82
|
1. Read the current state from the state file.
|
|
90
83
|
2. Observe the result of your last action.
|
|
91
84
|
3. Reason about what to do next, given the state and the observation.
|
|
92
|
-
4. Respond with
|
|
85
|
+
4. Respond with:
|
|
93
86
|
|
|
94
|
-
|
|
95
|
-
{
|
|
96
|
-
"state_patch": { "key": "new_value", "obsolete_key": null },
|
|
97
|
-
"action": "next_action_name"
|
|
98
|
-
}
|
|
99
|
-
\`\`\`
|
|
87
|
+
${STATE_PATCH_CONTRACT}
|
|
100
88
|
|
|
101
|
-
- In \`state_patch\`, set keys to null to delete them. Only include fields you
|
|
102
|
-
want to change. Omit fields to leave them unchanged.
|
|
103
89
|
- \`action\` names what you will do next (e.g. "continue", "done").
|
|
104
|
-
-
|
|
105
|
-
into \`state_patch\`.`;
|
|
90
|
+
- ${REASONING_DISCARDED_NOTE}`;
|
|
106
91
|
}
|
|
107
92
|
/**
|
|
108
93
|
* Generate an OpenCode plugin file.
|
|
@@ -147,17 +132,5 @@ export default createSkillStatePlugin({
|
|
|
147
132
|
await atomicWriteFile(dest, this.generatePluginCode(options));
|
|
148
133
|
return dest;
|
|
149
134
|
}
|
|
150
|
-
/* ------------------------------------------------------------------ */
|
|
151
|
-
/* Internal helpers */
|
|
152
|
-
/* ------------------------------------------------------------------ */
|
|
153
|
-
/**
|
|
154
|
-
* Describe the schema fields for inclusion in prompts.
|
|
155
|
-
*/
|
|
156
|
-
describeSchema(schema) {
|
|
157
|
-
const fields = Object.entries(schema)
|
|
158
|
-
.map(([name, field]) => `- ${name} (${field.type}): ${field.description ?? 'no description'}`)
|
|
159
|
-
.join('\n');
|
|
160
|
-
return `## Schema\n${fields}`;
|
|
161
|
-
}
|
|
162
135
|
}
|
|
163
136
|
//# sourceMappingURL=opencode-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-adapter.js","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EACL,eAAe,EACf,gBAAgB,
|
|
1
|
+
{"version":3,"file":"opencode-adapter.js","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EACL,eAAe,EACf,cAAc,EACd,wBAAwB,EACxB,gBAAgB,EAChB,oBAAoB,GAGrB,MAAM,kBAAkB,CAAC;AAS1B;;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;IAED;;;;;;;OAOG;IACH,eAAe,CAAC,IAAoB,EAAE,SAAkB;QACtD,MAAM,iBAAiB,GAAG,SAAS,IAAI,oBAAoB,CAAC;QAE5D,OAAO;QACH,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;eAClB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC;WACrC,IAAI,CAAC,OAAO;;gBAEP,iBAAiB;;;;IAI7B,IAAI,CAAC,IAAI;;EAEX,IAAI,CAAC,YAAY;;;;yCAIsB,iBAAiB;;;;;;;;;;;;EAYxD,oBAAoB;;;IAGlB,wBAAwB,EAAE,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,CAAC,OAA+B;QAChD,MAAM,UAAU,GAAG,OAAO,EAAE,kBAAkB,IAAI,CAAC,CAAC;QACpD,OAAO;;;;;;;;wBAQa,UAAU;;CAEjC,CAAC;IACA,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,cAAc,CAClB,MAA6B,EAC7B,OAA+B;QAE/B,MAAM,IAAI,GACR,OAAO,MAAM,KAAK,QAAQ;YACxB,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IACd,CAAC;CAKF"}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,50 +1,42 @@
|
|
|
1
|
+
import { mergePatch, resolveHostStateForCwd } from '@skillstate/core';
|
|
1
2
|
import type { SkillStatePlugin } from './plugin-types.js';
|
|
2
3
|
export * from './plugin-types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the per-project state file for a session working directory
|
|
6
|
+
* (`cwd` of the current opencode session) — the core single source of
|
|
7
|
+
* truth (`resolveHostStateForCwd`): `<cwd>/.skillstate/skillstate.json`,
|
|
8
|
+
* or the global bucket `<home>/.skillstate/global/skillstate.json` when
|
|
9
|
+
* cwd equals home. Pure path arithmetic via `path.resolve`, no filesystem
|
|
10
|
+
* access.
|
|
11
|
+
*/
|
|
12
|
+
export { resolveHostStateForCwd as resolveStatePathForCwd };
|
|
13
|
+
export { mergePatch };
|
|
3
14
|
/** Options for {@link createSkillStatePlugin}. */
|
|
4
15
|
export interface SkillStatePluginOptions {
|
|
5
16
|
/** Non-system messages kept in the prompt (default 3). */
|
|
6
17
|
maxHistoryMessages?: number;
|
|
7
18
|
}
|
|
8
|
-
/**
|
|
9
|
-
* Resolve the per-project state file for a session working directory
|
|
10
|
-
* (`cwd` of the current opencode session):
|
|
11
|
-
*
|
|
12
|
-
* - `cwd === home` — a session launched straight from `$HOME` has no single
|
|
13
|
-
* project, so state goes to the global bucket
|
|
14
|
-
* `<home>/.skillstate/global/skillstate.json`;
|
|
15
|
-
* - any other cwd (including subdirectories of `$HOME`) — the state lives in
|
|
16
|
-
* the project: `<cwd>/.skillstate/skillstate.json`.
|
|
17
|
-
*
|
|
18
|
-
* Pure path arithmetic: both arguments are normalized via `path.resolve`
|
|
19
|
-
* before comparison, and there is NO filesystem access. The same project
|
|
20
|
-
* directory therefore always maps to the same state file no matter where
|
|
21
|
-
* the host was launched from, while different projects never share state.
|
|
22
|
-
* Zero-dep by design (node builtins only) so generated plugins and the MCP
|
|
23
|
-
* server can inline the same semantics. Keep any copy in sync.
|
|
24
|
-
*/
|
|
25
|
-
export declare function resolveStatePathForCwd(cwd: string, home: string): string;
|
|
26
19
|
/**
|
|
27
20
|
* Read the state file. Missing or corrupt files yield `{}` (best-effort).
|
|
28
21
|
* The on-disk envelope is `{ version: 1, state }` (migrations-compatible);
|
|
29
|
-
* a bare object is tolerated and treated as the state itself.
|
|
22
|
+
* a bare object is tolerated and treated as the state itself. Thin fs
|
|
23
|
+
* adapter over the core hook-runtime {@link readStateEnvelope}.
|
|
30
24
|
*/
|
|
31
25
|
export declare function readSkillState(statePath: string): Record<string, unknown>;
|
|
32
26
|
/**
|
|
33
27
|
* Persist the state file (best-effort: read-only environments are ignored).
|
|
34
28
|
* Creates the parent directory when missing (the per-project resolver may
|
|
35
29
|
* target a fresh `<cwd>/.skillstate/`). Writes the `{ version: 1, state }`
|
|
36
|
-
* envelope so `migrate()`/runtime resume read the same file
|
|
30
|
+
* envelope so `migrate()`/runtime resume read the same file — via the core
|
|
31
|
+
* hook-runtime {@link saveStateEnvelope}.
|
|
37
32
|
*/
|
|
38
33
|
export declare function saveSkillState(statePath: string, state: Record<string, unknown>): void;
|
|
39
|
-
/**
|
|
40
|
-
* Paper ⊕ merge: `null` deletes a key, nested plain objects merge
|
|
41
|
-
* recursively, everything else replaces.
|
|
42
|
-
*/
|
|
43
|
-
export declare function mergePatch(base: Record<string, unknown>, patch: Record<string, unknown>): Record<string, unknown>;
|
|
44
34
|
/**
|
|
45
35
|
* Extract the `state_patch` object from an LLM response's fenced ```json
|
|
46
36
|
* block; `null` when there is no block, it is malformed, or it carries no
|
|
47
|
-
* object-shaped `state_patch`.
|
|
37
|
+
* object-shaped `state_patch`. Thin adapter over the core hook-runtime
|
|
38
|
+
* {@link findFencedPatch} (the invalid/truncated outcomes collapse to
|
|
39
|
+
* `null`, preserving the legacy boolean contract).
|
|
48
40
|
*/
|
|
49
41
|
export declare function extractPatch(response: string): Record<string, unknown> | null;
|
|
50
42
|
/**
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAsBA,OAAO,EAEL,UAAU,EAEV,sBAAsB,EAEvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAGV,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAE3B,cAAc,mBAAmB,CAAC;AAElC;;;;;;;GAOG;AACH,OAAO,EAAE,sBAAsB,IAAI,sBAAsB,EAAE,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,kDAAkD;AAClD,MAAM,WAAW,uBAAuB;IACtC,0DAA0D;IAC1D,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAOtF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAG7E;AAKD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB,CAgF9F"}
|
package/dist/plugin.js
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* Static OpenCode plugin — the SINGLE SOURCE OF TRUTH for the skillstate
|
|
3
3
|
* host integration. `OpenCodeAdapter.generatePluginCode` emits a thin loader
|
|
4
4
|
* that imports `createSkillStatePlugin` from this module; the per-project
|
|
5
|
-
* state resolution lives
|
|
5
|
+
* state resolution lives in `@skillstate/core`
|
|
6
|
+
* (`resolveHostStateForCwd`, re-exported here) and the hook logic
|
|
7
|
+
* (envelope read/write, ⊕ merge, patch extraction) in the core
|
|
8
|
+
* hook-runtime — this module only adapts it to the OpenCode hooks.
|
|
6
9
|
*
|
|
7
10
|
* Hooks (opencode 1.17 contract, verified on host):
|
|
8
11
|
* - `experimental.chat.messages.transform` — entries are `{ info, parts }`
|
|
@@ -17,116 +20,53 @@
|
|
|
17
20
|
import * as fs from 'node:fs';
|
|
18
21
|
import * as os from 'node:os';
|
|
19
22
|
import * as path from 'node:path';
|
|
23
|
+
import { findFencedPatch, mergePatch, readStateEnvelope, resolveHostStateForCwd, saveStateEnvelope, } from '@skillstate/core';
|
|
20
24
|
export * from './plugin-types.js';
|
|
21
25
|
/**
|
|
22
26
|
* Resolve the per-project state file for a session working directory
|
|
23
|
-
* (`cwd` of the current opencode session)
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* - any other cwd (including subdirectories of `$HOME`) — the state lives in
|
|
29
|
-
* the project: `<cwd>/.skillstate/skillstate.json`.
|
|
30
|
-
*
|
|
31
|
-
* Pure path arithmetic: both arguments are normalized via `path.resolve`
|
|
32
|
-
* before comparison, and there is NO filesystem access. The same project
|
|
33
|
-
* directory therefore always maps to the same state file no matter where
|
|
34
|
-
* the host was launched from, while different projects never share state.
|
|
35
|
-
* Zero-dep by design (node builtins only) so generated plugins and the MCP
|
|
36
|
-
* server can inline the same semantics. Keep any copy in sync.
|
|
27
|
+
* (`cwd` of the current opencode session) — the core single source of
|
|
28
|
+
* truth (`resolveHostStateForCwd`): `<cwd>/.skillstate/skillstate.json`,
|
|
29
|
+
* or the global bucket `<home>/.skillstate/global/skillstate.json` when
|
|
30
|
+
* cwd equals home. Pure path arithmetic via `path.resolve`, no filesystem
|
|
31
|
+
* access.
|
|
37
32
|
*/
|
|
38
|
-
export
|
|
39
|
-
|
|
40
|
-
const resolvedHome = path.resolve(home);
|
|
41
|
-
if (resolvedCwd === resolvedHome) {
|
|
42
|
-
return path.join(resolvedHome, '.skillstate', 'global', 'skillstate.json');
|
|
43
|
-
}
|
|
44
|
-
return path.join(resolvedCwd, '.skillstate', 'skillstate.json');
|
|
45
|
-
}
|
|
46
|
-
/** True for plain (non-null, non-array) objects. */
|
|
47
|
-
function isPlainObject(value) {
|
|
48
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
49
|
-
}
|
|
33
|
+
export { resolveHostStateForCwd as resolveStatePathForCwd };
|
|
34
|
+
export { mergePatch };
|
|
50
35
|
/**
|
|
51
36
|
* Read the state file. Missing or corrupt files yield `{}` (best-effort).
|
|
52
37
|
* The on-disk envelope is `{ version: 1, state }` (migrations-compatible);
|
|
53
|
-
* a bare object is tolerated and treated as the state itself.
|
|
38
|
+
* a bare object is tolerated and treated as the state itself. Thin fs
|
|
39
|
+
* adapter over the core hook-runtime {@link readStateEnvelope}.
|
|
54
40
|
*/
|
|
55
41
|
export function readSkillState(statePath) {
|
|
56
|
-
|
|
57
|
-
if (fs.existsSync(statePath)) {
|
|
58
|
-
const parsed = JSON.parse(fs.readFileSync(statePath, 'utf-8'));
|
|
59
|
-
if (typeof parsed === 'object' &&
|
|
60
|
-
parsed !== null &&
|
|
61
|
-
'state' in parsed &&
|
|
62
|
-
typeof parsed['state'] === 'object' &&
|
|
63
|
-
parsed['state'] !== null) {
|
|
64
|
-
return parsed['state'];
|
|
65
|
-
}
|
|
66
|
-
if (typeof parsed === 'object' && parsed !== null) {
|
|
67
|
-
return parsed;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
// Corrupt or unreadable state file — fall back to empty state.
|
|
73
|
-
}
|
|
74
|
-
return {};
|
|
42
|
+
return readStateEnvelope(statePath, (p) => fs.readFileSync(p, 'utf-8'));
|
|
75
43
|
}
|
|
76
44
|
/**
|
|
77
45
|
* Persist the state file (best-effort: read-only environments are ignored).
|
|
78
46
|
* Creates the parent directory when missing (the per-project resolver may
|
|
79
47
|
* target a fresh `<cwd>/.skillstate/`). Writes the `{ version: 1, state }`
|
|
80
|
-
* envelope so `migrate()`/runtime resume read the same file
|
|
48
|
+
* envelope so `migrate()`/runtime resume read the same file — via the core
|
|
49
|
+
* hook-runtime {@link saveStateEnvelope}.
|
|
81
50
|
*/
|
|
82
51
|
export function saveSkillState(statePath, state) {
|
|
83
52
|
try {
|
|
84
53
|
fs.mkdirSync(path.dirname(statePath), { recursive: true });
|
|
85
|
-
|
|
54
|
+
saveStateEnvelope(statePath, state, (p, data) => fs.writeFileSync(p, data));
|
|
86
55
|
}
|
|
87
56
|
catch {
|
|
88
57
|
// Best-effort: read-only environments or permission issues.
|
|
89
58
|
}
|
|
90
59
|
}
|
|
91
|
-
/**
|
|
92
|
-
* Paper ⊕ merge: `null` deletes a key, nested plain objects merge
|
|
93
|
-
* recursively, everything else replaces.
|
|
94
|
-
*/
|
|
95
|
-
export function mergePatch(base, patch) {
|
|
96
|
-
const result = { ...base };
|
|
97
|
-
for (const key of Object.keys(patch)) {
|
|
98
|
-
const value = patch[key];
|
|
99
|
-
if (value === null) {
|
|
100
|
-
delete result[key];
|
|
101
|
-
}
|
|
102
|
-
else if (isPlainObject(value) && isPlainObject(result[key])) {
|
|
103
|
-
result[key] = mergePatch(result[key], value);
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
result[key] = value;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return result;
|
|
110
|
-
}
|
|
111
60
|
/**
|
|
112
61
|
* Extract the `state_patch` object from an LLM response's fenced ```json
|
|
113
62
|
* block; `null` when there is no block, it is malformed, or it carries no
|
|
114
|
-
* object-shaped `state_patch`.
|
|
63
|
+
* object-shaped `state_patch`. Thin adapter over the core hook-runtime
|
|
64
|
+
* {@link findFencedPatch} (the invalid/truncated outcomes collapse to
|
|
65
|
+
* `null`, preserving the legacy boolean contract).
|
|
115
66
|
*/
|
|
116
67
|
export function extractPatch(response) {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
return null;
|
|
120
|
-
try {
|
|
121
|
-
const parsed = JSON.parse(match[1]);
|
|
122
|
-
if (isPlainObject(parsed) && isPlainObject(parsed['state_patch'])) {
|
|
123
|
-
return parsed['state_patch'];
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
// Malformed JSON — ignore.
|
|
128
|
-
}
|
|
129
|
-
return null;
|
|
68
|
+
const result = findFencedPatch(response);
|
|
69
|
+
return 'patch' in result ? result.patch : null;
|
|
130
70
|
}
|
|
131
71
|
/** Synthetic message ids for the injected state carrier. */
|
|
132
72
|
const STATE_MESSAGE_ID = 'skillstate-state-inject';
|
|
@@ -141,7 +81,7 @@ const STATE_MESSAGE_ID = 'skillstate-state-inject';
|
|
|
141
81
|
* `$HOME` uses the global bucket.
|
|
142
82
|
*/
|
|
143
83
|
export function createSkillStatePlugin(options = {}) {
|
|
144
|
-
const resolvePath = () =>
|
|
84
|
+
const resolvePath = () => resolveHostStateForCwd(process.cwd(), os.homedir());
|
|
145
85
|
const maxHistory = options.maxHistoryMessages ?? 3;
|
|
146
86
|
return async () => {
|
|
147
87
|
return {
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|