Skip to content

Commit 7c0c5a9

Browse files
committed
refactor session scaffold pathing and template context
1 parent 4f42dfa commit 7c0c5a9

6 files changed

Lines changed: 51 additions & 42 deletions

File tree

.changeset/heavy-shoes-report.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

apps/tui/README.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@ In local development, run `bun run dev` from the repo root. Turborepo will run
88
the TUI and daemon together, and the TUI will wait for the foreground daemon
99
instead of spawning a detached background process.
1010

11-
## Scaffold a workspace
12-
13-
From the `apps/tui` directory, run:
14-
15-
```bash
16-
bun run src/cli.ts init /path/to/project
17-
```
18-
1911
## Advanced daemon control
2012

2113
```bash

apps/tui/src/cli.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
waitUntilReady,
1010
} from "@techatnyu/ralphd";
1111
import { runTui } from "./index";
12-
import { bootstrapRalphWorkspace } from "./scaffold";
1312

1413
async function requireDaemon(): Promise<void> {
1514
const running = await daemon.isDaemonRunning();
@@ -37,22 +36,6 @@ const cli = new Crust("ralph")
3736
.run(async () => {
3837
await runTui();
3938
})
40-
.command("init", (cmd) =>
41-
cmd
42-
.meta({ description: "Create a Ralph workspace for a project" })
43-
.args([
44-
{
45-
name: "directory",
46-
type: "string",
47-
required: true,
48-
description: "Project directory where .ralph will be created",
49-
},
50-
])
51-
.run(async ({ args }) => {
52-
await bootstrapRalphWorkspace(args.directory);
53-
console.log(`Created Ralph workspace in ${args.directory}/.ralph`);
54-
}),
55-
)
5639
.command("daemon", (daemonCommand) =>
5740
daemonCommand
5841
.meta({ description: "Manage the background daemon" })

apps/tui/src/scaffold.ts

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,56 @@
1-
import { basename, resolve } from "node:path";
1+
import { mkdir } from "node:fs/promises";
2+
import { join } from "node:path";
23
import { scaffold } from "@crustjs/create";
4+
import { resolveDaemonPaths } from "@techatnyu/ralphd";
35

4-
export async function bootstrapRalphWorkspace(
5-
projectDirectory: string,
6-
): Promise<void> {
7-
const absoluteProjectDirectory = resolve(projectDirectory);
8-
const projectName = basename(absoluteProjectDirectory);
6+
export interface SessionScaffoldOptions {
7+
instanceId: string;
8+
sessionId: string;
9+
ralphHome?: string;
10+
}
11+
12+
function assertValidSegment(value: string, label: string): void {
13+
if (!value.trim()) {
14+
throw new Error(`${label} is required`);
15+
}
16+
17+
if (value.includes("/") || value.includes("\\")) {
18+
throw new Error(`${label} must not contain path separators`);
19+
}
20+
}
21+
22+
export function resolveSessionScaffoldPath(
23+
options: SessionScaffoldOptions,
24+
): string {
25+
assertValidSegment(options.instanceId, "instanceId");
26+
assertValidSegment(options.sessionId, "sessionId");
27+
28+
const ralphHome =
29+
options.ralphHome ?? resolveDaemonPaths(process.env).ralphHome;
30+
31+
return join(
32+
ralphHome,
33+
"sessions",
34+
options.instanceId,
35+
options.sessionId,
36+
);
37+
}
38+
39+
export async function bootstrapSessionScaffold(
40+
options: SessionScaffoldOptions,
41+
): Promise<string> {
42+
const sessionPath = resolveSessionScaffoldPath(options);
43+
44+
await mkdir(sessionPath, { recursive: true });
945

1046
await scaffold({
1147
template: new URL("../templates/ralph-workspace", import.meta.url),
12-
dest: resolve(absoluteProjectDirectory, ".ralph"),
48+
dest: sessionPath,
1349
context: {
14-
projectName,
50+
instanceId: options.instanceId,
51+
sessionId: options.sessionId,
1552
},
1653
});
17-
}
54+
55+
return sessionPath;
56+
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
# {{projectName}}
2-
<!-- The high-level project specification. Captures what you're building and why — goals, scope, tech stack choices, and architectural decisions. Implementation details (concrete tasks, exact thresholds, file-level structure) belong in prd.json and the codebase itself. A good spec is stable and rarely needs updating as the project evolves. -->
1+
# Instance {{instanceId}} Session {{sessionId}}

packages/daemon/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
export { DaemonClient, daemon } from "./client";
2+
export { RALPH_HOME, resolveDaemonPaths } from "./env";
23
export {
34
ensureDaemonRunning,
45
runForegroundDaemon,
56
startDetached,
67
stopDaemon,
78
waitUntilReady,
89
} from "./launcher";
9-
export type * from "./protocol";
10+
export type * from "./protocol";

0 commit comments

Comments
 (0)