Skip to content

Commit 84e32b7

Browse files
phodalclaude
andcommitted
refactor(studio): reorganize source tree by domain layer
harness-studio's src/ had accumulated a flat, inconsistent layout: a 2723-line server.ts route dispatcher, artifact-format files mixed with plugin registry files, a session-debugger-model.ts that mixed shared types with server-only logic and a server -> app reverse dependency, and artifact views split across app/ and app/artifacts/. - Extract src/contracts/ for types shared by app and server, dropping the redundant "-model" suffix and merging the duplicate 2-line artifact re-export. - Split session-debugger-model.ts into contracts/debugger-session.ts (types), server/debugger-session-transform.ts (retained-run conversion), and app/run/{debugger-cursor,sample-debugger-session}.ts (UI navigation and the recorded-sample fixture), removing the server -> app dependency. - Consolidate ArtifactView/ArtifactPreviewHost/MarkdownArtifactView into app/artifacts/ alongside the other Artifact Surface views. - Group server/ into artifacts/{registry,adapters}/, providers/{qoder,walnut}/, experiment/, and workspace/; extract StudioIntentAnalyzer out of server.ts so the Qoder provider no longer depends on the route-dispatcher file for one interface. - Split server.ts's route handlers into per-domain modules (studio-types, http-utils, acp-runs, workspace/routes, git/routes, artifacts/routes, experiment/routes, content-routes), leaving server.ts as a thin dispatcher plus the server factory. - Group app/ into run/, experiment/, and code/ for each multi-file feature area; single-view areas stay flat. - Split src/index.ts into a browser-safe src/client.ts (also published as the "./client" export) and the Node-only server/CLI surface. Verified after every step with tsc --noEmit (diffed against a captured baseline of pre-existing, unrelated errors from a stale sibling package build) and vitest run (265/266 passing throughout, matching the pre-existing baseline exactly). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent df4b5b0 commit 84e32b7

132 files changed

Lines changed: 3254 additions & 3219 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/harness-studio/README.md

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,20 +106,41 @@ fingerprint never enters selection.
106106
## Architecture
107107

108108
```text
109-
dist/app/ esbuild-bundled React app (index.html + assets/app.js)
110-
src/app/ components plus pure state modules:
111-
agui-store.ts AG-UI event → run view state reducer
112-
compare-model.ts verdict.json → table model
113-
sse-client.ts incremental SSE frame parser
114-
studio-shell-model.ts
115-
config → IA/readiness projection
116-
src/server/ static host + /api/config + /api/evidence + embedded /agui
117-
read-only /inspector + checkpoint history list/resolve
118-
+ durable experiment lock
109+
dist/app/ esbuild-bundled React app (index.html + assets/app.js)
110+
src/contracts/ types and wire formats shared by app and server
111+
(artifact, debugger-session, experiment, git-history,
112+
input-trace, intent-correlation, workspace-artifact)
113+
src/app/ shell (App.tsx, studio-shell-model.ts, studio-theme.ts)
114+
plus feature areas, each a components+state pair:
115+
run/ live run view, AG-UI reducer, Debugger
116+
cursor navigation, recorded sample
117+
experiment/ three-lane experiment trace view
118+
artifacts/ per-format Artifact Surface views and
119+
the surface registry
120+
code/ shared code/diff rendering (Shiki
121+
highlighting, ArtifactCodeView)
122+
and single-view areas at the top level (Compare,
123+
Customizations, GitHistory, InputTrace, Inspector,
124+
ArtifactsWorkspace)
125+
src/server/ static host + /api/config + /api/evidence + embedded
126+
/agui, grouped by domain:
127+
artifacts/registry/ catalog, compile runtime,
128+
Provider activation/discovery
129+
artifacts/adapters/ built-in docx/markdown/pdf/
130+
pptx/xlsx format adapters
131+
providers/qoder/ Qoder-specific Provider,
132+
Canvas bridge, intent analyzer
133+
providers/walnut/ Walnut Provider and bootstrap
134+
experiment/ experiment events + locking
135+
workspace/ workspace/session discovery
136+
query/ read-only route query helpers
119137
```
120138

121139
The pure modules are the tested seam; the React components are direct renders
122-
of their outputs.
140+
of their outputs. `src/index.ts` is the Node entry point (server, CLI,
141+
Provider activation); `src/client.ts` re-exports only the browser-safe subset
142+
(also available from the package as `@qoder-ai/harness-studio/client`) so a
143+
browser bundle never pulls in Node-only code.
123144

124145
## Development
125146

packages/harness-studio/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
".": {
2323
"types": "./dist/index.d.ts",
2424
"import": "./dist/index.js"
25+
},
26+
"./client": {
27+
"types": "./dist/client.d.ts",
28+
"import": "./dist/client.js"
2529
}
2630
},
2731
"files": [

packages/harness-studio/scripts/start-inspector-workspace.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { createInspectorWorkspaceSessionProvider } from "./inspector-workspace-p
88
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
99
const repositoryRoot = path.resolve(packageRoot, "../..");
1010
const { startHarnessStudioServer } = await import(path.join(packageRoot, "dist", "server", "server.js"));
11-
const { createQoderCliIntentAnalyzer } = await import(path.join(packageRoot, "dist", "server", "qoder-intent-analyzer.js"));
11+
const { createQoderCliIntentAnalyzer } = await import(path.join(packageRoot, "dist", "server", "providers", "qoder", "intent-analyzer.js"));
1212
const { createBundledAgentCustomizationCollector } = await import(path.join(packageRoot, "dist", "server", "customization-collector.js"));
1313
const portIndex = process.argv.indexOf("--port");
1414
const requestedPort = portIndex >= 0 ? Number(process.argv[portIndex + 1]) : 3311;

packages/harness-studio/src/app/App.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ import { Sun } from "@phosphor-icons/react/Sun";
1616
import { ArtifactsWorkspace } from "./ArtifactsWorkspace.js";
1717
import { CompareView } from "./CompareView.js";
1818
import { CustomizationView } from "./CustomizationView.js";
19-
import { ExperimentView } from "./ExperimentView.js";
19+
import { ExperimentView } from "./experiment/ExperimentView.js";
2020
import { GitHistoryView } from "./GitHistoryView.js";
2121
import { InputTraceView } from "./InputTraceView.js";
22-
import { RunView } from "./RunView.js";
23-
import type { DebuggerSession } from "./session-debugger-model.js";
22+
import { RunView } from "./run/RunView.js";
23+
import type { DebuggerSession } from "../contracts/debugger-session.js";
2424
import { useRovingFocus } from "./roving-tablist.js";
2525
import { studioApiError } from "./studio-api.js";
2626
import { StudioThemeContext, type StudioTheme } from "./studio-theme.js";

packages/harness-studio/src/app/ArtifactsWorkspace.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ import { TreeStructure } from "@phosphor-icons/react/TreeStructure";
1616
import {
1717
isArtifactCatalogResponse,
1818
type ArtifactDescriptor,
19-
} from "../artifact-model.js";
19+
} from "../contracts/artifact.js";
2020
import {
2121
isWorkspaceArtifactNavigation,
2222
type StudioArtifactCatalogResponse,
2323
type WorkspaceArtifactNavigation,
2424
type WorkspaceArtifactObservation,
25-
} from "../workspace-artifact-model.js";
26-
import { ArtifactView } from "./ArtifactView.js";
25+
} from "../contracts/workspace-artifact.js";
26+
import { ArtifactView } from "./artifacts/ArtifactView.js";
2727
import { useRovingFocus } from "./roving-tablist.js";
2828
import type { StudioConfig } from "./studio-shell-model.js";
2929

packages/harness-studio/src/app/GitHistoryView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import {
2727
type GitHistoryRef,
2828
type GitLogPage,
2929
type GitRefsSnapshot,
30-
} from "../git-history-model.js";
31-
import { ArtifactCodeView } from "./ArtifactCodeView.js";
30+
} from "../contracts/git-history.js";
31+
import { ArtifactCodeView } from "./code/ArtifactCodeView.js";
3232

3333
const PAGE_SIZE = 40;
3434
const GIT_LANE_COLOR_TOKENS = [5, 4, 2, 1, 6, 7, 3] as const;

packages/harness-studio/src/app/InputTraceView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ import {
1212
type UserInputFileTreeNode,
1313
type UserInputRecord,
1414
type UserInputTraceV1,
15-
} from "../input-trace-model.js";
15+
} from "../contracts/input-trace.js";
1616
import {
1717
isIntentCorrelationAnalysis,
1818
type IntentCorrelationAnalysisV1,
1919
type IntentProposal,
20-
} from "../intent-correlation-model.js";
20+
} from "../contracts/intent-correlation.js";
2121

2222
type ActivityFilter = "all" | UserInputActivity | "unlinked";
2323

packages/harness-studio/src/app/artifacts/ArtifactDiagnostics.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ArtifactDataSnapshot } from "../../artifact-model.js";
1+
import type { ArtifactDataSnapshot } from "../../contracts/artifact.js";
22

33
export function ArtifactDiagnostics({ diagnostics }: {
44
diagnostics: ArtifactDataSnapshot["diagnostics"];

packages/harness-studio/src/app/ArtifactPreviewHost.tsx renamed to packages/harness-studio/src/app/artifacts/ArtifactPreviewHost.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import {
33
isArtifactBuildSnapshot,
44
type ArtifactBuildSnapshot,
55
type ArtifactDescriptor,
6-
} from "../artifact-model.js";
7-
import { ArtifactCodeView } from "./ArtifactCodeView.js";
8-
import { useRovingTablist } from "./roving-tablist.js";
9-
import { studioApiError } from "./studio-api.js";
10-
import { useStudioTheme } from "./studio-theme.js";
6+
} from "../../contracts/artifact.js";
7+
import { ArtifactCodeView } from "../code/ArtifactCodeView.js";
8+
import { useRovingTablist } from "../roving-tablist.js";
9+
import { studioApiError } from "../studio-api.js";
10+
import { useStudioTheme } from "../studio-theme.js";
1111

1212
type PreviewState = "compiling" | "starting" | "ready" | "compile-failed" | "runtime-failed";
1313
type PreviewSurface = "preview" | "source";

packages/harness-studio/src/app/artifacts/ArtifactSurface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ComponentType } from "react";
2-
import type { ArtifactDescriptor } from "../../artifact-model.js";
2+
import type { ArtifactDescriptor } from "../../contracts/artifact.js";
33

44
export interface ArtifactSurfaceMountContext {
55
artifact: ArtifactDescriptor;

0 commit comments

Comments
 (0)