@loucompanion/forge-bridge 0.1.1-dev.03b8ba168599 → 0.1.1-dev.32d4dd5874ee

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.
@@ -65,13 +65,15 @@ export class BridgeSessionService {
65
65
  emit,
66
66
  signal
67
67
  });
68
+ const phaseArtifacts = run.artifacts?.length ? run.artifacts : run.artifact ? [run.artifact] : [];
68
69
  return redactSecrets({
69
70
  schemaVersion: 1,
70
71
  exitCode: 0,
71
72
  summary: run.summary,
72
73
  events,
73
74
  spec: run.spec ?? null,
74
- artifact: run.artifact ?? null
75
+ artifact: run.artifact ?? null,
76
+ artifacts: phaseArtifacts
75
77
  }, redactionSecrets);
76
78
  }
77
79
  finally {
@@ -101,6 +101,7 @@ export interface RunnerDispatchArtifact {
101
101
  readonly report: string;
102
102
  readonly producedBy: string;
103
103
  readonly status: string;
104
+ readonly phase?: string | null;
104
105
  }
105
106
  export interface RunOnceResultPacket {
106
107
  readonly schemaVersion: 1;
@@ -109,6 +110,7 @@ export interface RunOnceResultPacket {
109
110
  readonly events: readonly RunnerDispatchEvent[];
110
111
  readonly spec?: RunnerDispatchSpec | null;
111
112
  readonly artifact?: RunnerDispatchArtifact | null;
113
+ readonly artifacts?: readonly RunnerDispatchArtifact[] | null;
112
114
  }
113
115
  export interface RunnerEventLine {
114
116
  readonly type: "runner_event";
@@ -0,0 +1,9 @@
1
+ export interface CursorAgentLaunch {
2
+ readonly command: string;
3
+ readonly args: readonly string[];
4
+ }
5
+ export declare function isCursorAgentCommand(command: string): boolean;
6
+ export declare function resolveCursorAgentDirectLaunch(command: string, args: readonly string[]): Promise<CursorAgentLaunch | null>;
7
+ export declare function findLatestCursorAgentVersionDir(versionsRoot: string): Promise<string | null>;
8
+ export declare function compareCursorAgentVersionDirNames(left: string, right: string): number;
9
+ export declare function parseCursorAgentVersionSortKey(name: string): number;
@@ -0,0 +1,66 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ const cursorAgentVersionDirPattern = /^\d{4}\.\d{1,2}\.\d{1,2}-.+/;
4
+ export function isCursorAgentCommand(command) {
5
+ const normalized = command.trim().toLowerCase();
6
+ return normalized === "cursor-agent" || normalized === "agent";
7
+ }
8
+ export async function resolveCursorAgentDirectLaunch(command, args) {
9
+ if (!isCursorAgentCommand(command)) {
10
+ return null;
11
+ }
12
+ const localAppData = process.env.LOCALAPPDATA;
13
+ if (!localAppData) {
14
+ return null;
15
+ }
16
+ const versionDir = await findLatestCursorAgentVersionDir(path.join(localAppData, "cursor-agent", "versions"));
17
+ if (!versionDir) {
18
+ return null;
19
+ }
20
+ const nodePath = path.join(versionDir, "node.exe");
21
+ const indexPath = path.join(versionDir, "index.js");
22
+ if (!(await fileExists(nodePath)) || !(await fileExists(indexPath))) {
23
+ return null;
24
+ }
25
+ return {
26
+ command: nodePath,
27
+ args: [indexPath, ...args]
28
+ };
29
+ }
30
+ export async function findLatestCursorAgentVersionDir(versionsRoot) {
31
+ let entries;
32
+ try {
33
+ entries = await fs.readdir(versionsRoot);
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ const latestName = entries
39
+ .filter((name) => cursorAgentVersionDirPattern.test(name))
40
+ .sort(compareCursorAgentVersionDirNames)
41
+ .at(-1);
42
+ return latestName ? path.join(versionsRoot, latestName) : null;
43
+ }
44
+ export function compareCursorAgentVersionDirNames(left, right) {
45
+ const leftKey = parseCursorAgentVersionSortKey(left);
46
+ const rightKey = parseCursorAgentVersionSortKey(right);
47
+ if (leftKey !== rightKey) {
48
+ return leftKey - rightKey;
49
+ }
50
+ return left.localeCompare(right);
51
+ }
52
+ export function parseCursorAgentVersionSortKey(name) {
53
+ const datePart = name.split("-")[0] ?? "";
54
+ const parts = datePart.split(".");
55
+ if (parts.length !== 3) {
56
+ return 0;
57
+ }
58
+ const year = parts[0] ?? "";
59
+ const month = (parts[1] ?? "").padStart(2, "0");
60
+ const day = (parts[2] ?? "").padStart(2, "0");
61
+ const numeric = Number(`${year}${month}${day}`);
62
+ return Number.isFinite(numeric) ? numeric : 0;
63
+ }
64
+ async function fileExists(inputPath) {
65
+ return fs.stat(inputPath).then((stat) => stat.isFile()).catch(() => false);
66
+ }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const forgeBridgeVersion = "0.1.1-dev.03b8ba168599";
1
+ export declare const forgeBridgeVersion = "0.1.1-dev.32d4dd5874ee";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const forgeBridgeVersion = "0.1.1-dev.03b8ba168599";
1
+ export const forgeBridgeVersion = "0.1.1-dev.32d4dd5874ee";
@@ -8,4 +8,4 @@ export declare function buildSpecBody(laneCommand: DispatchResolvedArtifact, wor
8
8
  readonly title: string;
9
9
  readonly description: string;
10
10
  readonly acceptanceCriteria: string;
11
- }): string;
11
+ }, phase?: string): string;
@@ -15,11 +15,13 @@ export async function writeArtifact(worktreePath, artifact) {
15
15
  const scope = safeArtifactSegment("scope", artifact.scope);
16
16
  const slug = safeArtifactSegment("slug", artifact.slug);
17
17
  const forgeRoot = path.resolve(worktreePath, ".forge");
18
- const targetDir = path.resolve(forgeRoot, kindFolder, scope);
19
- assertInside(forgeRoot, targetDir, "Artifact directory");
20
- await fs.mkdir(targetDir, { recursive: true });
21
- const filePath = path.resolve(targetDir, `${slug}.md`);
18
+ const scopeDir = path.resolve(forgeRoot, kindFolder, scope);
19
+ assertInside(forgeRoot, scopeDir, "Artifact directory");
20
+ const filePath = normalizedArtifactKind(artifact.kind) === "skill"
21
+ ? path.resolve(scopeDir, slug, "SKILL.md")
22
+ : path.resolve(scopeDir, `${slug}.md`);
22
23
  assertInside(forgeRoot, filePath, "Artifact file");
24
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
23
25
  await fs.writeFile(filePath, artifact.body, "utf8");
24
26
  }
25
27
  export function selectLaneCommand(artifacts, lane, phase) {
@@ -43,12 +45,13 @@ export function resolveCommandSlug(lane, phase) {
43
45
  return "dev-prompt";
44
46
  }
45
47
  }
46
- export function buildSpecBody(laneCommand, workItem) {
48
+ export function buildSpecBody(laneCommand, workItem, phase = "implementation") {
47
49
  const prompt = laneCommand.body.replaceAll("{workItemId}", workItem.id);
48
50
  return `---
49
51
  work_item_id: ${workItem.id}
50
52
  status: approved
51
53
  lane: ${laneCommand.lane ?? "develop"}
54
+ phase: ${phase}
52
55
  command_slug: ${laneCommand.slug}
53
56
  ---
54
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loucompanion/forge-bridge",
3
- "version": "0.1.1-dev.03b8ba168599",
3
+ "version": "0.1.1-dev.32d4dd5874ee",
4
4
  "description": "Forge runner bridge CLI for connecting local developer machines to Forge dispatch.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",