@loucompanion/forge-bridge 0.1.1-dev.03b8ba168599 → 0.1.1-dev.2bc1e7f19b3a
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.
- package/dist/cli/cli.service.d.ts +4 -0
- package/dist/cli/cli.service.js +21 -1
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +1 -0
- package/dist/session/internals.d.ts +2 -0
- package/dist/session/internals.js +1 -0
- package/dist/session/phase-completion.d.ts +86 -0
- package/dist/session/phase-completion.js +1018 -0
- package/dist/session/provider-cli/provider-cli.service.d.ts +3 -0
- package/dist/session/provider-cli/provider-cli.service.js +482 -151
- package/dist/session/provider-cli/provider-cli.types.d.ts +1 -0
- package/dist/session/session.service.js +3 -1
- package/dist/session/session.types.d.ts +3 -0
- package/dist/session/session.types.js +11 -0
- package/dist/shared/cursor-agent/cursor-agent.launch.d.ts +9 -0
- package/dist/shared/cursor-agent/cursor-agent.launch.js +66 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worktree/artifact-injector.d.ts +1 -1
- package/dist/worktree/artifact-injector.js +9 -9
- package/package.json +1 -1
|
@@ -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 {
|
|
@@ -18,6 +18,7 @@ export interface DispatchResolvedArtifact {
|
|
|
18
18
|
readonly scope: string;
|
|
19
19
|
readonly body: string;
|
|
20
20
|
readonly contentHash: string;
|
|
21
|
+
readonly version: number;
|
|
21
22
|
readonly lane?: string | null;
|
|
22
23
|
readonly event?: string | null;
|
|
23
24
|
}
|
|
@@ -101,6 +102,7 @@ export interface RunnerDispatchArtifact {
|
|
|
101
102
|
readonly report: string;
|
|
102
103
|
readonly producedBy: string;
|
|
103
104
|
readonly status: string;
|
|
105
|
+
readonly phase?: string | null;
|
|
104
106
|
}
|
|
105
107
|
export interface RunOnceResultPacket {
|
|
106
108
|
readonly schemaVersion: 1;
|
|
@@ -109,6 +111,7 @@ export interface RunOnceResultPacket {
|
|
|
109
111
|
readonly events: readonly RunnerDispatchEvent[];
|
|
110
112
|
readonly spec?: RunnerDispatchSpec | null;
|
|
111
113
|
readonly artifact?: RunnerDispatchArtifact | null;
|
|
114
|
+
readonly artifacts?: readonly RunnerDispatchArtifact[] | null;
|
|
112
115
|
}
|
|
113
116
|
export interface RunnerEventLine {
|
|
114
117
|
readonly type: "runner_event";
|
|
@@ -153,6 +153,7 @@ function parseArtifacts(value) {
|
|
|
153
153
|
scope: requiredString(artifact, "scope"),
|
|
154
154
|
body: optionalString(artifact, "body") ?? "",
|
|
155
155
|
contentHash: requiredString(artifact, "contentHash"),
|
|
156
|
+
version: optionalPositiveInteger(artifact, "version") ?? 1,
|
|
156
157
|
lane: optionalString(artifact, "lane"),
|
|
157
158
|
event: optionalString(artifact, "event")
|
|
158
159
|
};
|
|
@@ -188,6 +189,16 @@ function requiredBoolean(source, key) {
|
|
|
188
189
|
}
|
|
189
190
|
return value;
|
|
190
191
|
}
|
|
192
|
+
function optionalPositiveInteger(source, key) {
|
|
193
|
+
const value = source[key];
|
|
194
|
+
if (value === undefined || value === null) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
|
|
198
|
+
throw new Error(`${key} must be a positive integer when provided.`);
|
|
199
|
+
}
|
|
200
|
+
return value;
|
|
201
|
+
}
|
|
191
202
|
function requiredNumber(source, key) {
|
|
192
203
|
const value = source[key];
|
|
193
204
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -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.
|
|
1
|
+
export declare const forgeBridgeVersion = "0.1.1-dev.2bc1e7f19b3a";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const forgeBridgeVersion = "0.1.1-dev.
|
|
1
|
+
export const forgeBridgeVersion = "0.1.1-dev.2bc1e7f19b3a";
|
|
@@ -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
|
|
19
|
-
assertInside(forgeRoot,
|
|
20
|
-
|
|
21
|
-
|
|
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) {
|
|
@@ -27,10 +29,7 @@ export function selectLaneCommand(artifacts, lane, phase) {
|
|
|
27
29
|
return artifacts.find((artifact) => normalizedArtifactKind(artifact.kind) === "command" && artifact.slug.trim().toLowerCase() === slug);
|
|
28
30
|
}
|
|
29
31
|
export function resolveCommandSlug(lane, phase) {
|
|
30
|
-
const normalizedPhase = phase.trim().toLowerCase();
|
|
31
|
-
if (normalizedPhase === "self_review") {
|
|
32
|
-
return "self-review-prompt";
|
|
33
|
-
}
|
|
32
|
+
const normalizedPhase = phase.trim().toLowerCase().replace(/-/g, "_");
|
|
34
33
|
if (normalizedPhase === "rework") {
|
|
35
34
|
return "rework-prompt";
|
|
36
35
|
}
|
|
@@ -43,12 +42,13 @@ export function resolveCommandSlug(lane, phase) {
|
|
|
43
42
|
return "dev-prompt";
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
|
-
export function buildSpecBody(laneCommand, workItem) {
|
|
45
|
+
export function buildSpecBody(laneCommand, workItem, phase = "implementation") {
|
|
47
46
|
const prompt = laneCommand.body.replaceAll("{workItemId}", workItem.id);
|
|
48
47
|
return `---
|
|
49
48
|
work_item_id: ${workItem.id}
|
|
50
49
|
status: approved
|
|
51
50
|
lane: ${laneCommand.lane ?? "develop"}
|
|
51
|
+
phase: ${phase}
|
|
52
52
|
command_slug: ${laneCommand.slug}
|
|
53
53
|
---
|
|
54
54
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loucompanion/forge-bridge",
|
|
3
|
-
"version": "0.1.1-dev.
|
|
3
|
+
"version": "0.1.1-dev.2bc1e7f19b3a",
|
|
4
4
|
"description": "Forge runner bridge CLI for connecting local developer machines to Forge dispatch.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|