Skip to content

Commit 73e7019

Browse files
V48 (specification-implementation): Move streams into api package primitives
Colocate streaming helpers with responses under packages/api/src/streams. Export @bitcode/api/streams; keep BC @bitcode/streams re-exports.
1 parent 57c8a19 commit 73e7019

30 files changed

Lines changed: 1144 additions & 1143 deletions

BITCODE_SPEC_V48_NOTES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,3 +1860,8 @@ Active proof/catalog path strings and docs:refresh scripts point at the new layo
18601860
The monorepo is the Bitcode protocol surface. `@bitcode/protocol` is the
18611861
demo/runtime shell; generators/proof tooling prefer `@bitcode/protocol-canonical`.
18621862

1863+
## Streams → api primitives (Garrett, 2026-07-13)
1864+
1865+
- Moved `@bitcode/streams` implementation into `packages/api/src/streams`.
1866+
- Export: `@bitcode/api/streams` (with `./streams/*`).
1867+
- BC: `@bitcode/streams` re-exports the API streams module (same pattern as responses).

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,8 @@
526526
"audit:stories": "node scripts/audit_stories.js",
527527
"check:prompts": "node scripts/generate_prompt_inventory.js --ci",
528528
"lint": "eslint packages --ext .ts,.tsx",
529-
"typecheck:core": "pnpm -C packages/execution-generics run typecheck && pnpm -C packages/pipelines-generics run typecheck && pnpm -C packages/pipeline-hosts run typecheck && pnpm -C packages/agent-generics run typecheck && pnpm -C packages/streams run typecheck",
530-
"lint:core": "pnpm exec eslint packages/execution-generics packages/pipelines-generics packages/agent-generics/src packages/streams/src --ext .ts,.tsx",
529+
"typecheck:core": "pnpm -C packages/execution-generics run typecheck && pnpm -C packages/pipelines-generics run typecheck && pnpm -C packages/pipeline-hosts run typecheck && pnpm -C packages/agent-generics run typecheck && pnpm -C packages/api run typecheck",
530+
"lint:core": "pnpm exec eslint packages/execution-generics packages/pipelines-generics packages/agent-generics/src packages/api/src/streams --ext .ts,.tsx",
531531
"lint:agents": "eslint packages/generic-agents packages/pipelines/asset-pack/src/agents --ext .ts",
532532
"prelint:agents": "pnpm run build:eslint-plugin",
533533
"lint:fix": "eslint packages --ext .ts,.tsx --fix",

packages/agent-generics/jest.config.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module.exports = {
3030
'^@bitcode/generic-llms-google$': '<rootDir>/../generic-llms/Google/src/index.ts',
3131
'^@bitcode/logger$': '<rootDir>/../logger/src/index.ts',
3232
'^@bitcode/parsing$': '<rootDir>/../parsing/src/parsing.ts',
33-
'^@bitcode/streams$': '<rootDir>/../streams/src/index.ts',
33+
'^@bitcode/streams$': '<rootDir>/../api/src/streams/index.ts',
3434
'^@bitcode/supabase$': '<rootDir>/../supabase/src/index.ts',
3535
'^@bitcode/artifacts$': '<rootDir>/../artifacts/src/artifacts.ts',
3636
'^@bitcode/([^/]+)$': '<rootDir>/../$1/src/index.ts',

packages/api/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@bitcode/api",
33
"version": "1.0.0",
4-
"description": "Comprehensive Bitcode API routes package - the unified backend route-orchestration layer",
4+
"description": "Comprehensive Bitcode API routes package - the unified backend route-orchestration layer; includes HTTP responses and streaming primitives",
55
"main": "src/index.ts",
66
"types": "src/index.ts",
77
"scripts": {
@@ -32,7 +32,6 @@
3232
"@bitcode/pipelines-generics": "workspace:*",
3333
"@bitcode/networking": "workspace:*",
3434
"@bitcode/security": "workspace:*",
35-
"@bitcode/streams": "workspace:*",
3635
"@bitcode/supabase": "workspace:*",
3736
"@bitcode/vcs": "workspace:*",
3837
"@supabase/supabase-js": "^2.0.0",
@@ -52,6 +51,8 @@
5251
".": "./src/index.ts",
5352
"./pipelines/cancel": "./src/pipelines/cancel.ts",
5453
"./pipelines/orphan-sweep": "./src/pipelines/orphan-sweep.ts",
55-
"./responses": "./src/responses/index.ts"
54+
"./responses": "./src/responses/index.ts",
55+
"./streams": "./src/streams/index.ts",
56+
"./streams/*": "./src/streams/*"
5657
}
5758
}

packages/api/src/routes/shippables.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { createPipelineCompletionMessage, findOrCreateConversationForPipeline }
3030
import { createJsonResponse, createErrorResponse, createAuthErrorResponse } from '@bitcode/responses';
3131
import { buildSemanticCompletionResult } from './shippables-semantic-payload';
3232
import * as crypto from 'crypto';
33-
import { Streamer } from '@bitcode/streams';
33+
import { Streamer } from '../streams';
3434

3535
// Initialize ORM client with admin access for API routes
3636
const orm = createAdminClient();
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
# Streams Core
1+
# @bitcode/api/streams
2+
3+
> BC alias: `@bitcode/streams`
4+
5+
Streams Core
26

37
## Overview
48

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/**
2+
* File Diff Streaming Helpers
3+
*
4+
* Utilities for streaming file changes through the execution pipeline.
5+
* Integrates with the core streaming system to show code diffs in real-time.
6+
*
7+
* @package @bitcode/api/streams
8+
*/
9+
10+
import type { StreamMessage, FileDiff, FileTreeChange } from './streams';
11+
import { writeStreamMessage } from './streams';
12+
13+
/**
14+
* Write a single file diff to the stream
15+
*
16+
* Use this when a file is created, modified, or deleted during execution.
17+
* The UI will render an expandable diff viewer inline with the log.
18+
*/
19+
export async function writeFileDiff(
20+
dataStream: any,
21+
fileDiff: FileDiff,
22+
options?: {
23+
phase?: string;
24+
agent?: string;
25+
step?: string;
26+
message?: string;
27+
}
28+
): Promise<void> {
29+
const message: StreamMessage = {
30+
type: 'file-diff',
31+
message: options?.message || `File ${fileDiff.action}: ${fileDiff.path}`,
32+
fileDiff,
33+
executionState: options ? {
34+
phase: options.phase as any,
35+
agent: options.agent,
36+
step: options.step as any,
37+
} : undefined,
38+
progress: fileDiff.action === 'created' ? 'success' : fileDiff.action === 'deleted' ? 'warning' : 'in-progress',
39+
};
40+
41+
await writeStreamMessage(dataStream, message);
42+
}
43+
44+
/**
45+
* Write complete file tree changes to the stream
46+
*
47+
* Use this at the end of implementation phase to show all file changes
48+
* in a single, comprehensive view with statistics.
49+
*/
50+
export async function writeFileTreeChanges(
51+
dataStream: any,
52+
fileTree: FileTreeChange,
53+
options?: {
54+
phase?: string;
55+
agent?: string;
56+
step?: string;
57+
message?: string;
58+
}
59+
): Promise<void> {
60+
const message: StreamMessage = {
61+
type: 'file-diff',
62+
message: options?.message || 'File tree changes completed',
63+
fileTree,
64+
executionState: options ? {
65+
phase: options.phase as any,
66+
agent: options.agent,
67+
step: options.step as any,
68+
} : undefined,
69+
progress: 'success',
70+
};
71+
72+
await writeStreamMessage(dataStream, message);
73+
}
74+
75+
/**
76+
* Calculate file tree statistics from an array of file diffs
77+
*/
78+
export function calculateFileTreeStats(files: FileDiff[]): FileTreeChange {
79+
const stats = files.reduce((acc, file) => {
80+
if (file.action === 'created') acc.filesCreated++;
81+
if (file.action === 'modified') acc.filesModified++;
82+
if (file.action === 'deleted') acc.filesDeleted++;
83+
acc.totalLinesAdded += file.linesAdded || 0;
84+
acc.totalLinesRemoved += file.linesRemoved || 0;
85+
return acc;
86+
}, {
87+
filesCreated: 0,
88+
filesModified: 0,
89+
filesDeleted: 0,
90+
totalLinesAdded: 0,
91+
totalLinesRemoved: 0,
92+
files: files,
93+
});
94+
95+
return stats;
96+
}
97+
98+
/**
99+
* Extract file diffs from tool results
100+
*
101+
* Parse tool execution results (Write, Edit, Delete tools) and convert
102+
* to FileDiff objects for streaming.
103+
*/
104+
export function extractFileDiffsFromToolResults(toolResults: any[]): FileDiff[] {
105+
const diffs: FileDiff[] = [];
106+
107+
for (const result of toolResults) {
108+
if (result.toolName === 'Write' && result.result) {
109+
// File created or overwritten
110+
diffs.push({
111+
path: result.args?.file_path || result.args?.path,
112+
action: 'created',
113+
newContent: result.args?.content,
114+
linesAdded: result.args?.content?.split('\n').length || 0,
115+
linesRemoved: 0,
116+
});
117+
}
118+
119+
if (result.toolName === 'Edit' && result.result) {
120+
// File modified
121+
diffs.push({
122+
path: result.args?.file_path || result.args?.path,
123+
action: 'modified',
124+
oldContent: result.metadata?.originalContent,
125+
newContent: result.metadata?.newContent,
126+
linesAdded: result.metadata?.linesAdded || 0,
127+
linesRemoved: result.metadata?.linesRemoved || 0,
128+
});
129+
}
130+
131+
if (result.toolName === 'Bash' && result.args?.command?.includes('rm ')) {
132+
// File deleted (simple detection)
133+
const match = result.args.command.match(/rm\s+([^\s]+)/);
134+
if (match) {
135+
diffs.push({
136+
path: match[1],
137+
action: 'deleted',
138+
linesAdded: 0,
139+
linesRemoved: result.metadata?.linesRemoved || 0,
140+
});
141+
}
142+
}
143+
}
144+
145+
return diffs;
146+
}
File renamed without changes.

0 commit comments

Comments
 (0)