@playola-radio/slipstream 0.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.
Files changed (104) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +132 -0
  3. package/SKILL.md +63 -0
  4. package/THIRD-PARTY-NOTICES.md +36 -0
  5. package/contracts/interface/v2/schema.json +480 -0
  6. package/dist/answer-forwarder.js +58 -0
  7. package/dist/attribution-engine.js +164 -0
  8. package/dist/attribution-producer.js +153 -0
  9. package/dist/attribution-scoring.js +86 -0
  10. package/dist/attribution.js +120 -0
  11. package/dist/blob-source.js +100 -0
  12. package/dist/boundary-registry.js +47 -0
  13. package/dist/cas.js +99 -0
  14. package/dist/change-view.js +201 -0
  15. package/dist/claude-root-transcript.js +110 -0
  16. package/dist/cli.js +629 -0
  17. package/dist/clip-blob-reader.js +104 -0
  18. package/dist/clip-function-parser.js +83 -0
  19. package/dist/clip-language.js +15 -0
  20. package/dist/clip-projection-service.js +240 -0
  21. package/dist/clip-projection-worker.js +18 -0
  22. package/dist/clip-projection.js +585 -0
  23. package/dist/clip-worker-pool.js +118 -0
  24. package/dist/config.js +154 -0
  25. package/dist/control-client.js +98 -0
  26. package/dist/control-protocol.js +72 -0
  27. package/dist/daemon-location.js +33 -0
  28. package/dist/daemon.js +951 -0
  29. package/dist/display-fold.js +332 -0
  30. package/dist/engine.js +112 -0
  31. package/dist/entrypoint.js +17 -0
  32. package/dist/event.js +79 -0
  33. package/dist/evidence-ingest.js +60 -0
  34. package/dist/harness-context/claude.js +42 -0
  35. package/dist/harness-context/codex.js +49 -0
  36. package/dist/harness-context.js +49 -0
  37. package/dist/health.js +65 -0
  38. package/dist/http-reader.js +655 -0
  39. package/dist/http-security.js +50 -0
  40. package/dist/interface-projection.js +243 -0
  41. package/dist/interface-range-resolver.js +230 -0
  42. package/dist/interface-service.js +509 -0
  43. package/dist/interface-ts-pool.js +111 -0
  44. package/dist/interface-ts-worker.js +35 -0
  45. package/dist/interface-v2-comparison.js +135 -0
  46. package/dist/interface-v2-core.js +123 -0
  47. package/dist/interface-v2-typescript.js +448 -0
  48. package/dist/lock.js +197 -0
  49. package/dist/log-reader.js +148 -0
  50. package/dist/log.js +59 -0
  51. package/dist/maintenance.js +255 -0
  52. package/dist/mcp-forwarder.js +161 -0
  53. package/dist/mcp-protocol.js +92 -0
  54. package/dist/platform.js +21 -0
  55. package/dist/projection-admission.js +296 -0
  56. package/dist/projection-trace.js +17 -0
  57. package/dist/public-events.js +27 -0
  58. package/dist/question-hook.js +110 -0
  59. package/dist/questions.js +167 -0
  60. package/dist/reader-runtime.js +38 -0
  61. package/dist/reader.js +93 -0
  62. package/dist/recovery.js +303 -0
  63. package/dist/schema.js +108 -0
  64. package/dist/session.js +866 -0
  65. package/dist/sibling-module.js +10 -0
  66. package/dist/snapshot.js +15 -0
  67. package/dist/storage.js +111 -0
  68. package/dist/store-reader.js +185 -0
  69. package/dist/swift-grammar.js +268 -0
  70. package/dist/swift-interface-extract.js +344 -0
  71. package/dist/swift-interface.js +62 -0
  72. package/dist/swift-parse-host.js +174 -0
  73. package/dist/swift-parse-worker.js +34 -0
  74. package/dist/swift-parse.js +134 -0
  75. package/dist/swift-spans.js +62 -0
  76. package/dist/task-forwarder.js +152 -0
  77. package/dist/transcript/claude.js +199 -0
  78. package/dist/transcript/codex.js +132 -0
  79. package/dist/transcript/discovery.js +365 -0
  80. package/dist/transcript/file-reader.js +128 -0
  81. package/dist/transcript/fs-io.js +287 -0
  82. package/dist/transcript/runner.js +62 -0
  83. package/dist/transcript/steppers.js +30 -0
  84. package/dist/transcript/types.js +30 -0
  85. package/dist/transcript/watcher.js +133 -0
  86. package/dist/tui.js +168 -0
  87. package/package.json +60 -0
  88. package/schemas/projections/clip.v1.json +195 -0
  89. package/schemas/projections/clip.v2.json +212 -0
  90. package/schemas/projections/clip.v3.json +212 -0
  91. package/schemas/slipstream.capture.baseline.completed.v1.json +62 -0
  92. package/schemas/slipstream.capture.gap.v1.json +112 -0
  93. package/schemas/slipstream.change.attribution.v1.json +115 -0
  94. package/schemas/slipstream.enrichment.configured.v1.json +77 -0
  95. package/schemas/slipstream.enrichment.coverage.v1.json +95 -0
  96. package/schemas/slipstream.file.baselined.v1.json +122 -0
  97. package/schemas/slipstream.file.changed.v1.json +179 -0
  98. package/schemas/slipstream.harness.evidence.v1.json +145 -0
  99. package/schemas/slipstream.question.answered.v1.json +29 -0
  100. package/schemas/slipstream.question.dispatch_attempted.v1.json +28 -0
  101. package/schemas/slipstream.question.queued.v1.json +55 -0
  102. package/schemas/slipstream.session.resumed.v1.json +70 -0
  103. package/schemas/slipstream.session.started.v1.json +69 -0
  104. package/schemas/slipstream.task.started.v1.json +72 -0
@@ -0,0 +1,49 @@
1
+ import { isAbsolute } from 'node:path';
2
+ function isObject(v) {
3
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
4
+ }
5
+ /**
6
+ * Codex identity adapter (fail-closed).
7
+ *
8
+ * Per the SC3 probe (tools/identity-probe/FINDINGS.md): Codex exposes NO identity
9
+ * environment variable and a clean env at startup — identity arrives ONLY on the
10
+ * tool call, in `_meta`. The carrier is `_meta.threadId` (== session_id) plus
11
+ * `_meta['x-codex-turn-metadata'].workspaces`, a map from the canonical worktree
12
+ * path to its origin/commit. `cwd` is unreliable (sometimes `/`) and is never a
13
+ * binding input.
14
+ *
15
+ * Fail closed unless `_meta` is present, `threadId` is present, and `workspaces`
16
+ * has EXACTLY one key: an absent, empty, or multi-root map is ambiguous, so we
17
+ * refuse rather than guess. (A dropped Codex transport is terminal for the binding
18
+ * — recovery needs a new conversation — but that is the transport's concern, not
19
+ * this pure derivation's.)
20
+ */
21
+ export function codexIdentity(toolCallParams) {
22
+ if (!isObject(toolCallParams))
23
+ return { unresolved: 'tool call has no params' };
24
+ const meta = toolCallParams._meta;
25
+ if (!isObject(meta))
26
+ return { unresolved: 'tool call _meta is absent' };
27
+ const threadId = meta.threadId;
28
+ if (typeof threadId !== 'string' || threadId.length === 0) {
29
+ return { unresolved: 'tool call _meta.threadId is absent' };
30
+ }
31
+ const turn = meta['x-codex-turn-metadata'];
32
+ if (!isObject(turn))
33
+ return { unresolved: 'tool call _meta.x-codex-turn-metadata is absent' };
34
+ const workspaces = turn.workspaces;
35
+ if (!isObject(workspaces))
36
+ return { unresolved: 'tool call _meta workspaces map is absent' };
37
+ const keys = Object.keys(workspaces);
38
+ if (keys.length === 0)
39
+ return { unresolved: 'workspaces map is empty; worktree root is ambiguous' };
40
+ if (keys.length > 1)
41
+ return { unresolved: `workspaces map has ${keys.length} roots; ambiguous` };
42
+ const worktree = keys[0];
43
+ // The worktree root must be an absolute path. A relative key (`.`, or an array's
44
+ // `0`) would be resolved against the daemon's own CWD, which is never a binding
45
+ // input — reject it before contacting the daemon.
46
+ if (!isAbsolute(worktree))
47
+ return { unresolved: `workspace root ${worktree} is not an absolute path` };
48
+ return { harness: 'codex', harness_session_id: threadId, worktree };
49
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The forwarder's harness-identity resolver.
3
+ *
4
+ * SC3 requires verified harness session context; CWD alone is insufficient, and
5
+ * ambiguous identity must FAIL rather than guess. The two harnesses expose
6
+ * identity by different mechanisms and at different times (see FINDINGS.md), so
7
+ * this dispatches by `clientInfo.name` at `initialize`:
8
+ * - claude-code → identity is the env triple, observable eagerly at initialize
9
+ * and cached (tool-call params carry no identity).
10
+ * - codex-mcp-client → identity arrives only per tool call, derived each time.
11
+ *
12
+ * Anything else — an unrecognized client, or a call before initialize — fails
13
+ * closed. `worktree`/`harness_session_id` here are DECLARED context the forwarder
14
+ * ships to the daemon; the daemon does the selection comparison.
15
+ */
16
+ import { claudeIdentity } from "./harness-context/claude.js";
17
+ import { codexIdentity } from "./harness-context/codex.js";
18
+ export function isResolved(result) {
19
+ return !('unresolved' in result);
20
+ }
21
+ export const CLAUDE_CLIENT = 'claude-code';
22
+ export const CODEX_CLIENT = 'codex-mcp-client';
23
+ function isObject(v) {
24
+ return typeof v === 'object' && v !== null;
25
+ }
26
+ export function createHarnessContext() {
27
+ let resolve = () => ({
28
+ unresolved: 'harness not initialized',
29
+ });
30
+ return {
31
+ initialize(clientInfo, env) {
32
+ const name = isObject(clientInfo) && typeof clientInfo.name === 'string' ? clientInfo.name : undefined;
33
+ if (name === CLAUDE_CLIENT) {
34
+ const cached = claudeIdentity(env); // eager: the env triple is available now
35
+ resolve = () => cached;
36
+ }
37
+ else if (name === CODEX_CLIENT) {
38
+ resolve = (params) => codexIdentity(params); // per-call: identity only at declaration
39
+ }
40
+ else {
41
+ const reason = `unrecognized harness clientInfo.name: ${name ?? '(absent)'}`;
42
+ resolve = () => ({ unresolved: reason });
43
+ }
44
+ },
45
+ identityForCall(toolCallParams) {
46
+ return resolve(toolCallParams);
47
+ },
48
+ };
49
+ }
package/dist/health.js ADDED
@@ -0,0 +1,65 @@
1
+ export function createHealth(durableSeq = 0n) {
2
+ let state = 'starting';
3
+ let seq = durableSeq;
4
+ let failure;
5
+ let gapPending = false;
6
+ const listeners = new Set();
7
+ return {
8
+ snapshot: () => ({
9
+ state,
10
+ durable_seq: seq.toString(),
11
+ ...(failure ? { failure } : {}),
12
+ gap_pending: gapPending,
13
+ }),
14
+ setDurableSeq: (next) => {
15
+ seq = next;
16
+ // A listener that throws (violating its contract) must not corrupt the
17
+ // caller that just advanced the durable seq — e.g. break the append path
18
+ // between a durable commit and the bookkeeping that follows it. Report and
19
+ // keep notifying the rest.
20
+ for (const l of listeners) {
21
+ try {
22
+ l();
23
+ }
24
+ catch (err) {
25
+ // Reporting must itself be crash-proof: String(err) can re-enter user
26
+ // code (a custom toString / Symbol.toPrimitive) that throws again, and
27
+ // that second exception would escape into the caller — re-opening the
28
+ // exact post-commit hole this catch exists to close.
29
+ let detail;
30
+ try {
31
+ detail = String(err);
32
+ }
33
+ catch {
34
+ detail = '<unstringifiable listener error>';
35
+ }
36
+ console.error(`slipstream: health listener threw: ${detail}`);
37
+ }
38
+ }
39
+ },
40
+ markHealthy: () => {
41
+ state = 'healthy';
42
+ failure = undefined;
43
+ gapPending = false;
44
+ },
45
+ markFailing: (next) => {
46
+ // Keep the first failure of an outage: it marks when acknowledgment
47
+ // stopped. A failed recovery attempt re-enters `failing` from
48
+ // `recovering`; preserve that original failure rather than overwriting it.
49
+ if (state !== 'failing') {
50
+ state = 'failing';
51
+ failure ??= next;
52
+ gapPending = true;
53
+ }
54
+ },
55
+ markRecovering: () => {
56
+ state = 'recovering';
57
+ },
58
+ subscribe: (listener) => {
59
+ listeners.add(listener);
60
+ return () => {
61
+ listeners.delete(listener);
62
+ };
63
+ },
64
+ };
65
+ }