@intx/hub-sessions 0.1.2 → 0.2.2

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.
Files changed (87) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +84 -1
  3. package/dist/agent-repo.d.ts +89 -0
  4. package/dist/agent-repo.js +109 -0
  5. package/dist/agent-state-kind.d.ts +12 -0
  6. package/dist/agent-state-kind.js +185 -0
  7. package/dist/asset-service.d.ts +123 -0
  8. package/dist/asset-service.js +349 -0
  9. package/dist/available-skills-stanza.d.ts +21 -0
  10. package/dist/available-skills-stanza.js +32 -0
  11. package/dist/credential-push.d.ts +32 -0
  12. package/dist/credential-push.js +85 -0
  13. package/dist/event-collector-registry.d.ts +20 -0
  14. package/dist/event-collector-registry.js +115 -0
  15. package/dist/event-collector.d.ts +39 -0
  16. package/dist/event-collector.js +357 -0
  17. package/dist/hub-session-lookups.d.ts +17 -0
  18. package/dist/hub-session-lookups.js +204 -0
  19. package/dist/hub-session-orchestrator.d.ts +25 -0
  20. package/dist/hub-session-orchestrator.js +122 -0
  21. package/dist/index.d.ts +18 -0
  22. package/dist/index.js +16 -0
  23. package/dist/package-registry-kind.d.ts +70 -0
  24. package/dist/package-registry-kind.js +260 -0
  25. package/dist/repo-store/index.d.ts +4 -0
  26. package/dist/repo-store/index.js +3 -0
  27. package/dist/repo-store/store.d.ts +41 -0
  28. package/dist/repo-store/store.js +1692 -0
  29. package/dist/repo-store/subscribe-kind.d.ts +53 -0
  30. package/dist/repo-store/subscribe-kind.js +179 -0
  31. package/dist/repo-store/types.d.ts +483 -0
  32. package/dist/repo-store/types.js +42 -0
  33. package/dist/session-service.d.ts +235 -0
  34. package/dist/session-service.js +997 -0
  35. package/dist/skill-kind.d.ts +41 -0
  36. package/dist/skill-kind.js +288 -0
  37. package/dist/substrate.d.ts +8 -0
  38. package/dist/substrate.js +21 -0
  39. package/dist/workflow-kind.d.ts +21 -0
  40. package/dist/workflow-kind.js +263 -0
  41. package/dist/workflow-run-event-log.d.ts +21 -0
  42. package/dist/workflow-run-event-log.js +51 -0
  43. package/dist/workflow-run-kind.d.ts +326 -0
  44. package/dist/workflow-run-kind.js +2646 -0
  45. package/dist/workflow-run-reader.d.ts +47 -0
  46. package/dist/workflow-run-reader.js +157 -0
  47. package/dist/ws/index.d.ts +3 -0
  48. package/dist/ws/index.js +3 -0
  49. package/dist/ws/sidecar-events.d.ts +134 -0
  50. package/dist/ws/sidecar-events.js +70 -0
  51. package/dist/ws/sidecar-handler.d.ts +184 -0
  52. package/dist/ws/sidecar-handler.js +1603 -0
  53. package/dist/ws/sidecar-token-authenticator.d.ts +15 -0
  54. package/dist/ws/sidecar-token-authenticator.js +24 -0
  55. package/package.json +34 -12
  56. package/src/agent-repo.test.ts +0 -310
  57. package/src/agent-repo.ts +0 -165
  58. package/src/agent-state-kind.test.ts +0 -247
  59. package/src/agent-state-kind.ts +0 -204
  60. package/src/asset-service.test.ts +0 -540
  61. package/src/asset-service.ts +0 -378
  62. package/src/available-skills-stanza.test.ts +0 -87
  63. package/src/available-skills-stanza.ts +0 -47
  64. package/src/credential-push.ts +0 -65
  65. package/src/event-collector-registry.test.ts +0 -73
  66. package/src/event-collector-registry.ts +0 -171
  67. package/src/event-collector.test.ts +0 -1387
  68. package/src/event-collector.ts +0 -424
  69. package/src/hub-session-lookups.ts +0 -206
  70. package/src/hub-session-orchestrator.test.ts +0 -510
  71. package/src/hub-session-orchestrator.ts +0 -213
  72. package/src/index.ts +0 -78
  73. package/src/repo-store/index.ts +0 -15
  74. package/src/repo-store/store.test.ts +0 -1169
  75. package/src/repo-store/store.ts +0 -428
  76. package/src/repo-store/types.ts +0 -253
  77. package/src/session-service.test.ts +0 -895
  78. package/src/session-service.ts +0 -464
  79. package/src/skill-kind.test.ts +0 -599
  80. package/src/skill-kind.ts +0 -350
  81. package/src/ws/index.ts +0 -18
  82. package/src/ws/sidecar-events.test.ts +0 -96
  83. package/src/ws/sidecar-events.ts +0 -231
  84. package/src/ws/sidecar-handler.test.ts +0 -2217
  85. package/src/ws/sidecar-handler.ts +0 -1574
  86. package/tsconfig.json +0 -4
  87. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,53 @@
1
+ import { type Type } from "arktype";
2
+ import type { Principal, RepoId, RepoStore } from "./types.js";
3
+ export type SubscribeKindOpts = {
4
+ signal: AbortSignal;
5
+ from: "head" | {
6
+ seq: number;
7
+ };
8
+ /**
9
+ * Workflow-event kinds to surface. Matches against the inner
10
+ * payload's `type` field after the validator narrows the blob. The
11
+ * helper yields only events whose `type` appears in this list.
12
+ */
13
+ kinds: readonly string[];
14
+ bufferLimit?: number;
15
+ };
16
+ export type SubscribeKindEntry<T> = {
17
+ /**
18
+ * Workflow-event seq parsed from the committed filename
19
+ * (`runs/<runId>/events/<seq>.json`). Distinct from the substrate's
20
+ * commit-level seq exposed by `RepoStore.subscribe`.
21
+ */
22
+ seq: number;
23
+ /**
24
+ * Owning runId, parsed from the committed blob's path. The substrate
25
+ * stores each run's event log under `runs/<runId>/events/`; the helper
26
+ * surfaces the path segment so consumers can attribute each yielded
27
+ * event to its run without re-walking the tree. Required by the
28
+ * workflow-host scheduler's live-ingest path, which routes incoming
29
+ * `TimerSet` events to per-run queue entries.
30
+ */
31
+ runId: string;
32
+ event: T;
33
+ };
34
+ /**
35
+ * Typed entrypoint over `RepoStore.subscribe` for the workflow-run
36
+ * event log. The substrate emits one ref-update envelope per commit;
37
+ * each commit may add one or more `runs/<runId>/events/<seq>.json`
38
+ * blobs. This helper loads those blobs from the new commit's tree,
39
+ * narrows each through the supplied arktype validator, applies the
40
+ * kinds filter against the inner `type` discriminator, and yields one
41
+ * `{ seq, event }` entry per matching blob.
42
+ *
43
+ * The path layout is owned here, not in the substrate: the substrate
44
+ * `subscribe` is a generic ref-tail primitive and knows nothing about
45
+ * workflow-runs.
46
+ *
47
+ * Diff scope: the helper enumerates event blobs present in the new
48
+ * commit but absent from the old commit. A commit that does not add
49
+ * any event blobs (e.g. a kind-handler-internal rewrite) produces no
50
+ * entries even if the kinds filter would otherwise match earlier
51
+ * events.
52
+ */
53
+ export declare function subscribeKind<V extends Type>(store: RepoStore, principal: Principal, repoId: RepoId, ref: string, validator: V, opts: SubscribeKindOpts): AsyncGenerator<SubscribeKindEntry<V["infer"]>, void, void>;
@@ -0,0 +1,179 @@
1
+ import fs from "node:fs";
2
+ import git from "isomorphic-git";
3
+ import { type } from "arktype";
4
+ import { hasCode } from "@intx/types";
5
+ /**
6
+ * Path-layout constants for the workflow-run repo's event log. The
7
+ * workflow-run kind handler commits one JSON blob per event under
8
+ * `runs/<runId>/events/<seq>.json` (the layout decided in the
9
+ * pre-build interface decisions for the workflow-run repo). The
10
+ * `subscribeKind` helper owns this layout so the substrate `subscribe`
11
+ * stays generic and free of workflow-event vocabulary.
12
+ */
13
+ const RUNS_PREFIX = "runs";
14
+ const EVENTS_DIR = "events";
15
+ /**
16
+ * Substrate envelope shape. Imported textually rather than from
17
+ * `types.ts` so this helper has a local, validator-checked view of
18
+ * what `RepoStore.subscribe` yields and does not depend on the
19
+ * substrate's TypeScript type for runtime safety.
20
+ */
21
+ const SubstrateEvent = type({
22
+ type: "'ref.updated'",
23
+ ref: "string",
24
+ "oldSha?": "string | null",
25
+ newSha: "string",
26
+ });
27
+ /**
28
+ * Per-event filename shape. Filenames are `<seq>.json` under
29
+ * `runs/<runId>/events/`. `<seq>` is a non-negative decimal integer.
30
+ */
31
+ const EVENT_FILENAME_RE = /^(0|[1-9][0-9]*)\.json$/;
32
+ const KindEnvelope = type({
33
+ type: "string",
34
+ });
35
+ /**
36
+ * Typed entrypoint over `RepoStore.subscribe` for the workflow-run
37
+ * event log. The substrate emits one ref-update envelope per commit;
38
+ * each commit may add one or more `runs/<runId>/events/<seq>.json`
39
+ * blobs. This helper loads those blobs from the new commit's tree,
40
+ * narrows each through the supplied arktype validator, applies the
41
+ * kinds filter against the inner `type` discriminator, and yields one
42
+ * `{ seq, event }` entry per matching blob.
43
+ *
44
+ * The path layout is owned here, not in the substrate: the substrate
45
+ * `subscribe` is a generic ref-tail primitive and knows nothing about
46
+ * workflow-runs.
47
+ *
48
+ * Diff scope: the helper enumerates event blobs present in the new
49
+ * commit but absent from the old commit. A commit that does not add
50
+ * any event blobs (e.g. a kind-handler-internal rewrite) produces no
51
+ * entries even if the kinds filter would otherwise match earlier
52
+ * events.
53
+ */
54
+ export async function* subscribeKind(store, principal, repoId, ref, validator, opts) {
55
+ const kindsAllowed = new Set(opts.kinds);
56
+ const dir = store.getRepoDir(repoId);
57
+ const subscribeOpts = {
58
+ signal: opts.signal,
59
+ from: opts.from,
60
+ };
61
+ if (opts.bufferLimit !== undefined) {
62
+ subscribeOpts.bufferLimit = opts.bufferLimit;
63
+ }
64
+ const iter = store.subscribe(principal, repoId, ref, subscribeOpts);
65
+ for await (const { event } of iter) {
66
+ const envelope = SubstrateEvent(event);
67
+ if (envelope instanceof type.errors) {
68
+ throw new Error(`subscribe_kind_envelope_invalid: ${envelope.summary}`);
69
+ }
70
+ const candidates = await collectAddedEventBlobs(dir, envelope.oldSha ?? null, envelope.newSha);
71
+ for (const candidate of candidates) {
72
+ const raw = await readBlobAtCommit(dir, envelope.newSha, candidate.blobPath);
73
+ let parsedJson;
74
+ try {
75
+ parsedJson = JSON.parse(new TextDecoder().decode(raw));
76
+ }
77
+ catch (cause) {
78
+ throw new Error(`subscribe_kind_invalid_json: ${candidate.blobPath}`, {
79
+ cause,
80
+ });
81
+ }
82
+ const kind = KindEnvelope(parsedJson);
83
+ if (kind instanceof type.errors) {
84
+ throw new Error(`subscribe_kind_missing_type: ${candidate.blobPath}: ${kind.summary}`);
85
+ }
86
+ if (!kindsAllowed.has(kind.type))
87
+ continue;
88
+ const narrowed = validator(parsedJson);
89
+ if (narrowed instanceof type.errors) {
90
+ throw new Error(`subscribe_kind_validation_failed: ${candidate.blobPath}: ${narrowed.summary}`);
91
+ }
92
+ yield { seq: candidate.seq, runId: candidate.runId, event: narrowed };
93
+ }
94
+ }
95
+ }
96
+ /**
97
+ * Walk the `runs/<runId>/events/` subtree at `newSha` and at `oldSha`
98
+ * (when present) and return the set of event candidates present in
99
+ * the new commit but not in the old. Filenames that fail the
100
+ * `<seq>.json` shape are surfaced as errors rather than silently
101
+ * skipped — the workflow-run kind handler's validatePush is the
102
+ * authority for what may land under this prefix, so an unexpected
103
+ * shape here is a substrate-side invariant violation.
104
+ */
105
+ async function collectAddedEventBlobs(dir, oldSha, newSha) {
106
+ const newSet = await enumerateEventBlobs(dir, newSha);
107
+ if (oldSha === null) {
108
+ return [...newSet.values()].sort(byRunThenSeq);
109
+ }
110
+ const oldSet = await enumerateEventBlobs(dir, oldSha);
111
+ const out = [];
112
+ for (const [key, candidate] of newSet) {
113
+ if (oldSet.has(key))
114
+ continue;
115
+ out.push(candidate);
116
+ }
117
+ out.sort(byRunThenSeq);
118
+ return out;
119
+ }
120
+ function byRunThenSeq(a, b) {
121
+ if (a.runId < b.runId)
122
+ return -1;
123
+ if (a.runId > b.runId)
124
+ return 1;
125
+ return a.seq - b.seq;
126
+ }
127
+ async function enumerateEventBlobs(dir, commitOid) {
128
+ const out = new Map();
129
+ let commit;
130
+ try {
131
+ commit = await git.readCommit({ fs, dir, oid: commitOid });
132
+ }
133
+ catch (err) {
134
+ if (hasCode(err) && err.code === "NotFoundError")
135
+ return out;
136
+ throw err;
137
+ }
138
+ const runsOid = await lookupSubtree(dir, commit.commit.tree, RUNS_PREFIX);
139
+ if (runsOid === null)
140
+ return out;
141
+ const { tree: runs } = await git.readTree({ fs, dir, oid: runsOid });
142
+ for (const runEntry of runs) {
143
+ if (runEntry.type !== "tree")
144
+ continue;
145
+ const runId = runEntry.path;
146
+ const eventsOid = await lookupSubtree(dir, runEntry.oid, EVENTS_DIR);
147
+ if (eventsOid === null)
148
+ continue;
149
+ const { tree: events } = await git.readTree({ fs, dir, oid: eventsOid });
150
+ for (const blob of events) {
151
+ if (blob.type !== "blob")
152
+ continue;
153
+ const match = EVENT_FILENAME_RE.exec(blob.path);
154
+ if (match === null) {
155
+ throw new Error(`subscribe_kind_unexpected_event_filename: ${RUNS_PREFIX}/${runId}/${EVENTS_DIR}/${blob.path}`);
156
+ }
157
+ const seqStr = match[1];
158
+ if (seqStr === undefined)
159
+ throw new Error("unreachable");
160
+ const seq = Number.parseInt(seqStr, 10);
161
+ const blobPath = `${RUNS_PREFIX}/${runId}/${EVENTS_DIR}/${blob.path}`;
162
+ out.set(`${runId}/${blob.path}`, { seq, runId, blobPath });
163
+ }
164
+ }
165
+ return out;
166
+ }
167
+ async function lookupSubtree(dir, parentTreeOid, name) {
168
+ const { tree } = await git.readTree({ fs, dir, oid: parentTreeOid });
169
+ const entry = tree.find((e) => e.path === name);
170
+ if (entry === undefined)
171
+ return null;
172
+ if (entry.type !== "tree")
173
+ return null;
174
+ return entry.oid;
175
+ }
176
+ async function readBlobAtCommit(dir, commitOid, filepath) {
177
+ const { blob } = await git.readBlob({ fs, dir, oid: commitOid, filepath });
178
+ return blob;
179
+ }