Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions apps/server/src/bin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, NetService.layer);
const isThreadSendMessageError = Schema.is(ThreadSendMessageError);
const isThreadSendServerUnavailableError = Schema.is(ThreadSendServerUnavailableError);
const isThreadSendTargetError = Schema.is(ThreadSendTargetError);
const encodeUnknownJson = Schema.encodeSync(Schema.fromJsonString(Schema.Unknown));
const ProjectActionReconcileCliResult = Schema.Struct({
mode: Schema.String,
projectCreated: Schema.Boolean,
scriptsChanged: Schema.Boolean,
created: Schema.optional(Schema.Array(Schema.String)),
});
const decodeProjectActionReconcileCliResult = Schema.decodeSync(
Schema.fromJsonString(ProjectActionReconcileCliResult),
);
class ProjectCliHttpApi extends HttpApi.make("environment")
.add(EnvironmentMetadataHttpApi)
.add(EnvironmentOrchestrationHttpApi) {}
Expand Down Expand Up @@ -626,6 +636,143 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => {
}),
);

it.effect("reconciles checked-in Project Actions through the offline event store", () =>
Effect.gen(function* () {
const baseDir = NodeFS.mkdtempSync(
NodePath.join(NodeOS.tmpdir(), "t3-cli-project-actions-offline-test-"),
);
const workspaceRoot = NodeFS.mkdtempSync(
NodePath.join(NodeOS.tmpdir(), "t3-cli-project-actions-offline-workspace-"),
);
const sourceFile = NodePath.join(workspaceRoot, "t3.json");
const stateFile = NodePath.join(baseDir, "userdata", "lastcode", "project-actions.json");
NodeFS.writeFileSync(
sourceFile,
encodeUnknownJson({
scripts: [
{ name: "Setup Worktree", command: "vp i", runOnWorktreeCreate: true },
{
id: "lc-wait-for-pr",
name: "Wait for PR",
command: "node scripts/lastcode-wait-for-pr.ts",
icon: "test",
},
],
}),
);

const { output } = yield* captureStdout(
runCli([
"project",
"reconcile-actions",
workspaceRoot,
"--source-file",
sourceFile,
"--state-file",
stateFile,
"--create-if-missing",
"--base-dir",
baseDir,
]),
);
const result = decodeProjectActionReconcileCliResult(output);
assert.equal(result.mode, "offline");
assert.isTrue(result.projectCreated);
assert.deepEqual(result.created, ["lc-wait-for-pr"]);

const { output: repeatedOutput } = yield* captureStdout(
runCli([
"project",
"reconcile-actions",
workspaceRoot,
"--source-file",
sourceFile,
"--state-file",
stateFile,
"--create-if-missing",
"--base-dir",
baseDir,
]),
);
const repeated = decodeProjectActionReconcileCliResult(repeatedOutput);
assert.isFalse(repeated.projectCreated);
assert.isFalse(repeated.scriptsChanged);
assert.deepEqual(repeated.created, []);

const snapshot = yield* readPersistedSnapshot(baseDir);
const project = snapshot.projects.find(
(entry) => entry.workspaceRoot === workspaceRoot && entry.deletedAt === null,
);
assert.deepEqual(project?.scripts, [
{
id: "lc-wait-for-pr",
name: "Wait for PR",
command: "node scripts/lastcode-wait-for-pr.ts",
icon: "test",
runOnWorktreeCreate: false,
},
]);
assert.isTrue(NodeFS.existsSync(stateFile));
}),
);

it.effect("reconciles checked-in Project Actions through a running server", () =>
Effect.gen(function* () {
const baseDir = NodeFS.mkdtempSync(
NodePath.join(NodeOS.tmpdir(), "t3-cli-project-actions-live-test-"),
);
const workspaceRoot = NodeFS.mkdtempSync(
NodePath.join(NodeOS.tmpdir(), "t3-cli-project-actions-live-workspace-"),
);
const sourceFile = NodePath.join(workspaceRoot, "t3.json");
const stateFile = NodePath.join(baseDir, "userdata", "lastcode", "project-actions.json");
NodeFS.writeFileSync(
sourceFile,
encodeUnknownJson({
scripts: [
{
id: "lc-local-ci",
name: "Run Quick CI",
command: "node scripts/lastcode-local-ci.ts --quick",
icon: "test",
},
],
}),
);

yield* withLiveProjectCliServer(baseDir, () =>
Effect.gen(function* () {
const { output } = yield* captureStdout(
runCli([
"project",
"reconcile-actions",
workspaceRoot,
"--source-file",
sourceFile,
"--state-file",
stateFile,
"--create-if-missing",
"--trusted-source-ids",
"lc-local-ci",
"--base-dir",
baseDir,
]),
);
const result = decodeProjectActionReconcileCliResult(output);
assert.equal(result.mode, "live");
assert.isTrue(result.projectCreated);

const query = yield* ProjectionSnapshotQuery.ProjectionSnapshotQuery;
const snapshot = yield* query.getSnapshot();
const project = snapshot.projects.find(
(entry) => entry.workspaceRoot === workspaceRoot && entry.deletedAt === null,
);
assert.isTrue(project?.scripts[0]?.allowAgentResume);
}),
);
}),
);

it.effect("falls back to bounded SQLite reads without clearing the runtime record", () =>
Effect.gen(function* () {
const seedBaseDir = NodeFS.mkdtempSync(
Expand Down
Loading