dsh-cc-loader 0.1.2 → 0.2.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 +8 -0
- package/package.json +30 -30
- package/src/index.js +3 -0
- package/src/session-compat.js +112 -0
package/README.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# dsh-cc-loader
|
|
2
2
|
|
|
3
|
+
> [!IMPORTANT]
|
|
4
|
+
> **Only upgrade to this version when upgrading DSH to `0.1.5-rc.2` or later.**
|
|
5
|
+
> `v0.2.0` adds the session event-log compatibility boundary
|
|
6
|
+
> (`sessionEvents` / `sessionEventAt` / `sessionLastEvent`) required by the
|
|
7
|
+
> 0.1.5 host. Earlier DSH releases do not have the readers it targets. If your
|
|
8
|
+
> DSH is still `0.1.0-rc.7`–`0.1.1-rc.2`, **do not upgrade** — stay on `v0.1.x`.
|
|
9
|
+
> The two lines are mutually exclusive.
|
|
10
|
+
|
|
3
11
|
Shared parse layer for the dsh-cc ecosystem: parses Claude Code `.claude/` assets (project + global `~/.claude`) **and Claude Code plugins** (`plugin.json` / `marketplace.json` / plugin root) into a standalone in-memory IR.
|
|
4
12
|
|
|
5
13
|
- **Memory IR, zero-write path**: nothing is written to disk; the source of truth stays the `.claude` files and plugin manifests themselves, so DSH stays in sync with Claude Code.
|
package/package.json
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dsh-cc-loader",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "Shared parse layer for the dsh-cc ecosystem: parses Claude Code .claude/ (project + global) into a standalone .dsh intermediate representation (IR), classifying every component DIRECT/ADAPTED/UNSUPPORTED/BLOCKED and filtering unsupported ones out.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "src/index.js",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./src/index.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"src",
|
|
12
|
-
"README.md"
|
|
13
|
-
],
|
|
14
|
-
"keywords": [
|
|
15
|
-
"dsh",
|
|
16
|
-
"deepseek-harness",
|
|
17
|
-
"claude-code",
|
|
18
|
-
"loader",
|
|
19
|
-
"parser"
|
|
20
|
-
],
|
|
21
|
-
"license": "MIT",
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"yaml": "^2.0.0"
|
|
24
|
-
},
|
|
25
|
-
"engines": {
|
|
26
|
-
"node": ">=20"
|
|
27
|
-
},
|
|
28
|
-
"repository": "git+https://github.com/Bcy2020/dsh-cc-ecosystem.git",
|
|
29
|
-
"homepage": "https://github.com/Bcy2020/dsh-cc-ecosystem"
|
|
30
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-cc-loader",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Shared parse layer for the dsh-cc ecosystem: parses Claude Code .claude/ (project + global) into a standalone .dsh intermediate representation (IR), classifying every component DIRECT/ADAPTED/UNSUPPORTED/BLOCKED and filtering unsupported ones out.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"dsh",
|
|
16
|
+
"deepseek-harness",
|
|
17
|
+
"claude-code",
|
|
18
|
+
"loader",
|
|
19
|
+
"parser"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"yaml": "^2.0.0"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20"
|
|
27
|
+
},
|
|
28
|
+
"repository": "git+https://github.com/Bcy2020/dsh-cc-ecosystem.git",
|
|
29
|
+
"homepage": "https://github.com/Bcy2020/dsh-cc-ecosystem"
|
|
30
|
+
}
|
package/src/index.js
CHANGED
|
@@ -39,3 +39,6 @@ export {
|
|
|
39
39
|
evaluateCall, parseRulesFor, splitSubcommands, removedToolNames,
|
|
40
40
|
classifyComponents, STATUS, matchesIfRule,
|
|
41
41
|
} from './classify.js'
|
|
42
|
+
// Session event-log readers. `Session.events` was removed in DSH 0.1.2-alpha.4
|
|
43
|
+
// and is gone in 0.1.5; every plugin read of the log goes through these.
|
|
44
|
+
export { sessionEvents, sessionEventAt, sessionLastEvent } from './session-compat.js'
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// session-compat.js — the single compatibility boundary for reading a DSH
|
|
2
|
+
// session's event log.
|
|
3
|
+
//
|
|
4
|
+
// WHY THIS EXISTS
|
|
5
|
+
// ---------------
|
|
6
|
+
// `Session.events` was REMOVED in DSH 0.1.2-alpha.4 and is gone in 0.1.5. It
|
|
7
|
+
// was the full event-log array (both spread and numeric indexing were used on
|
|
8
|
+
// it). Hosts at 0.1.5 expose a different, narrower surface:
|
|
9
|
+
//
|
|
10
|
+
// session.seq -> SessionLogOffset (== log length)
|
|
11
|
+
// session.eventAt(seq) -> SessionEvent | undefined
|
|
12
|
+
// session.snapshotEvents(from?, to?) -> readonly SessionEvent[] (frozen)
|
|
13
|
+
// session.ownEvents() -> readonly SessionEvent[] (post-fork)
|
|
14
|
+
//
|
|
15
|
+
// Reading `session.events` on 0.1.5 does not throw a nice error: it is
|
|
16
|
+
// `undefined`, so a spread raises `agent.session.events is not iterable` and a
|
|
17
|
+
// numeric index raises `Cannot read properties of undefined (reading 'NN')`.
|
|
18
|
+
// Both were live crashes. Every plugin read of the log MUST go through this
|
|
19
|
+
// module so the legacy fallback exists in exactly one place instead of being
|
|
20
|
+
// re-guessed at each call site.
|
|
21
|
+
//
|
|
22
|
+
// SUPPORT POLICY
|
|
23
|
+
// --------------
|
|
24
|
+
// The new API is ALWAYS preferred; the legacy `session.events` property is
|
|
25
|
+
// read only when the new methods are absent, i.e. only on pre-0.1.2-alpha.4
|
|
26
|
+
// hosts. Supporting two shapes is intentional and cheap: `typeof fn ===
|
|
27
|
+
// 'function'` is the whole branch.
|
|
28
|
+
//
|
|
29
|
+
// Both functions are total: a missing, partial, or malformed session object
|
|
30
|
+
// yields `undefined` rather than throwing, so a plugin degrades to "no log
|
|
31
|
+
// visible" instead of crashing the host at an event boundary.
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Read a session's full event log.
|
|
35
|
+
*
|
|
36
|
+
* Prefers `session.snapshotEvents()` (DSH >= 0.1.2-alpha.4). Falls back to the
|
|
37
|
+
* legacy `session.events` array on older hosts. The full log is returned —
|
|
38
|
+
* including any fork-inherited prefix — because callers index it with absolute
|
|
39
|
+
* sequence numbers taken from `session.surface.nodes`, and because the legacy
|
|
40
|
+
* `events` property was itself the full log.
|
|
41
|
+
*
|
|
42
|
+
* @param {unknown} session - the agent's session (`agent.session`), or anything else.
|
|
43
|
+
* @returns {readonly unknown[]|undefined} the event log, or `undefined` when
|
|
44
|
+
* the session exposes neither reader.
|
|
45
|
+
*/
|
|
46
|
+
export function sessionEvents(session) {
|
|
47
|
+
if (session === null || typeof session !== 'object') return undefined
|
|
48
|
+
const snapshot = session.snapshotEvents
|
|
49
|
+
if (typeof snapshot === 'function') {
|
|
50
|
+
const events = snapshot.call(session)
|
|
51
|
+
if (Array.isArray(events)) return events
|
|
52
|
+
}
|
|
53
|
+
// A host exposing only the point reader (`eventAt` + `seq`) still has a
|
|
54
|
+
// readable log: materialize it by walking the sequence range. Real 0.1.5
|
|
55
|
+
// sessions have `snapshotEvents` too; this keeps the boundary total.
|
|
56
|
+
const at = session.eventAt
|
|
57
|
+
const end = session.seq
|
|
58
|
+
if (typeof at === 'function' && typeof end === 'number' && Number.isInteger(end) && end >= 0) {
|
|
59
|
+
const events = []
|
|
60
|
+
for (let seq = 0; seq < end; seq += 1) {
|
|
61
|
+
const event = at.call(session, seq)
|
|
62
|
+
if (event === undefined) break
|
|
63
|
+
events.push(event)
|
|
64
|
+
}
|
|
65
|
+
return events
|
|
66
|
+
}
|
|
67
|
+
const legacy = session.events
|
|
68
|
+
return Array.isArray(legacy) ? legacy : undefined
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Read one session event by its absolute sequence number.
|
|
73
|
+
*
|
|
74
|
+
* Prefers `session.eventAt(seq)` (DSH >= 0.1.2-alpha.4). Falls back to numeric
|
|
75
|
+
* indexing into the legacy `session.events` array on older hosts. This is the
|
|
76
|
+
* cheaper reader when only one event is needed: `eventAt` is a direct array
|
|
77
|
+
* lookup, whereas `snapshotEvents()` materializes (and on a full read freezes)
|
|
78
|
+
* the whole log.
|
|
79
|
+
*
|
|
80
|
+
* @param {unknown} session - the agent's session (`agent.session`), or anything else.
|
|
81
|
+
* @param {number} seq - the absolute event sequence number.
|
|
82
|
+
* @returns {unknown} the event, or `undefined` when absent/unreadable.
|
|
83
|
+
*/
|
|
84
|
+
export function sessionEventAt(session, seq) {
|
|
85
|
+
if (session === null || typeof session !== 'object') return undefined
|
|
86
|
+
if (typeof seq !== 'number' || !Number.isInteger(seq) || seq < 0) return undefined
|
|
87
|
+
const at = session.eventAt
|
|
88
|
+
if (typeof at === 'function') return at.call(session, seq)
|
|
89
|
+
const legacy = session.events
|
|
90
|
+
return Array.isArray(legacy) ? legacy[seq] : undefined
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The newest event matching a predicate, or `undefined`.
|
|
95
|
+
*
|
|
96
|
+
* A convenience over {@link sessionEvents} for the common "findLast" pattern
|
|
97
|
+
* (`lastTurn`, `lastAssistantMessage`): it scans the log newest-first, so it
|
|
98
|
+
* never builds a reversed copy of a potentially long log.
|
|
99
|
+
*
|
|
100
|
+
* @param {unknown} session - the agent's session (`agent.session`).
|
|
101
|
+
* @param {(event: any) => boolean} predicate - match test for one event.
|
|
102
|
+
* @returns {any} the newest matching event, or `undefined`.
|
|
103
|
+
*/
|
|
104
|
+
export function sessionLastEvent(session, predicate) {
|
|
105
|
+
const events = sessionEvents(session)
|
|
106
|
+
if (events === undefined || typeof predicate !== 'function') return undefined
|
|
107
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
108
|
+
const event = events[index]
|
|
109
|
+
if (predicate(event)) return event
|
|
110
|
+
}
|
|
111
|
+
return undefined
|
|
112
|
+
}
|