@loucompanion/forge-bridge 0.1.3-dev.b6be5e7f9668 → 0.1.3-dev.d1ca67076aa9

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.
Files changed (46) hide show
  1. package/dist/bridge/bridge.service.js +8 -2
  2. package/dist/cli/cli.help.d.ts +2 -0
  3. package/dist/cli/cli.help.js +171 -0
  4. package/dist/cli/cli.service.js +5 -183
  5. package/dist/session/phase-completion.artifacts.d.ts +10 -0
  6. package/dist/session/phase-completion.artifacts.js +599 -0
  7. package/dist/session/phase-completion.d.ts +32 -44
  8. package/dist/session/phase-completion.helpers.d.ts +112 -0
  9. package/dist/session/phase-completion.helpers.js +660 -0
  10. package/dist/session/phase-completion.js +28 -3485
  11. package/dist/session/phase-completion.prompts.d.ts +14 -0
  12. package/dist/session/phase-completion.prompts.js +220 -0
  13. package/dist/session/phase-completion.runtime.d.ts +36 -0
  14. package/dist/session/phase-completion.runtime.js +609 -0
  15. package/dist/session/phase-completion.schemas.d.ts +3 -0
  16. package/dist/session/phase-completion.schemas.js +707 -0
  17. package/dist/session/phase-completion.validation.d.ts +34 -0
  18. package/dist/session/phase-completion.validation.js +724 -0
  19. package/dist/session/provider-cli/provider-cli.artifacts.d.ts +93 -0
  20. package/dist/session/provider-cli/provider-cli.artifacts.js +754 -0
  21. package/dist/session/provider-cli/provider-cli.deterministic-payloads.d.ts +12 -0
  22. package/dist/session/provider-cli/provider-cli.deterministic-payloads.js +279 -0
  23. package/dist/session/provider-cli/provider-cli.deterministic.d.ts +12 -0
  24. package/dist/session/provider-cli/provider-cli.deterministic.js +318 -0
  25. package/dist/session/provider-cli/provider-cli.process.d.ts +31 -0
  26. package/dist/session/provider-cli/provider-cli.process.js +265 -0
  27. package/dist/session/provider-cli/provider-cli.prompts.d.ts +33 -0
  28. package/dist/session/provider-cli/provider-cli.prompts.js +411 -0
  29. package/dist/session/provider-cli/provider-cli.qa-sidecars.d.ts +11 -0
  30. package/dist/session/provider-cli/provider-cli.qa-sidecars.js +65 -0
  31. package/dist/session/provider-cli/provider-cli.runtime.d.ts +9 -0
  32. package/dist/session/provider-cli/provider-cli.runtime.js +40 -0
  33. package/dist/session/provider-cli/provider-cli.service.d.ts +6 -53
  34. package/dist/session/provider-cli/provider-cli.service.js +11 -2495
  35. package/dist/session/provider-cli/provider-output-state.d.ts +20 -0
  36. package/dist/session/provider-cli/provider-output-state.js +445 -0
  37. package/dist/session/session.types.d.ts +54 -0
  38. package/dist/session/session.types.js +92 -0
  39. package/dist/shared/process/windows-launch.d.ts +8 -0
  40. package/dist/shared/process/windows-launch.js +38 -0
  41. package/dist/version.d.ts +1 -1
  42. package/dist/version.js +1 -1
  43. package/dist/worktree/artifact-injector.js +39 -6
  44. package/dist/worktree/worktree.service.d.ts +2 -1
  45. package/dist/worktree/worktree.service.js +32 -12
  46. package/package.json +1 -1
@@ -0,0 +1,38 @@
1
+ import path from "node:path";
2
+ export function buildWindowsCmdLaunch(command, args) {
3
+ return {
4
+ command: process.env.ComSpec ?? "cmd.exe",
5
+ args: ["/d", "/s", "/v:off", "/c", `"${windowsCommandLine(command, args)}"`]
6
+ };
7
+ }
8
+ export function buildWindowsLaunchCommand(commandPath, args) {
9
+ const extension = path.extname(commandPath).toLowerCase();
10
+ if (extension === ".ps1") {
11
+ return {
12
+ command: powershellExecutable(),
13
+ args: ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", commandPath, ...args]
14
+ };
15
+ }
16
+ if (extension === ".cmd" || extension === ".bat") {
17
+ return buildWindowsCmdLaunch(commandPath, args);
18
+ }
19
+ return { command: commandPath, args };
20
+ }
21
+ export function windowsCommandLine(command, args) {
22
+ return [command, ...args].map(quoteWindowsCommandLineArg).join(" ");
23
+ }
24
+ export function quoteWindowsCommandLineArg(value) {
25
+ const escaped = value
26
+ .replace(/\^/g, "^^")
27
+ .replace(/%/g, "^%");
28
+ if (escaped.length > 0 && !/[\s"&|<>()^%!]/.test(escaped)) {
29
+ return escaped;
30
+ }
31
+ return `"${escaped.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/g, "$1$1")}"`;
32
+ }
33
+ function powershellExecutable() {
34
+ const systemRoot = process.env.SystemRoot;
35
+ return systemRoot
36
+ ? path.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
37
+ : "powershell.exe";
38
+ }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const forgeBridgeVersion = "0.1.3-dev.b6be5e7f9668";
1
+ export declare const forgeBridgeVersion = "0.1.3-dev.d1ca67076aa9";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const forgeBridgeVersion = "0.1.3-dev.b6be5e7f9668";
1
+ export const forgeBridgeVersion = "0.1.3-dev.d1ca67076aa9";
@@ -36,19 +36,29 @@ const DRAFT_OPERATIONAL_SKILLS = new Set([
36
36
  "draft-repo-context",
37
37
  "draft-graph-context",
38
38
  "draft-product-scope",
39
- "draft-work-order-plan",
40
39
  "draft-critic",
41
40
  "draft-proposal"
42
41
  ]);
42
+ const DRAFT_WORK_ITEM_OPERATIONAL_SKILLS = new Set([
43
+ "draft-work-item-plan"
44
+ ]);
45
+ const DRAFT_WORK_ORDER_OPERATIONAL_SKILLS = new Set([
46
+ "draft-work-order-plan"
47
+ ]);
43
48
  const DRAFT_OPERATIONAL_HOOKS = new Set([
44
49
  "draft-intent",
45
50
  "draft-repo-context",
46
51
  "draft-graph-context",
47
52
  "draft-product-scope",
48
- "draft-work-order-plan",
49
53
  "draft-critic",
50
54
  "draft-proposal"
51
55
  ]);
56
+ const DRAFT_WORK_ITEM_OPERATIONAL_HOOKS = new Set([
57
+ "draft-work-item-plan"
58
+ ]);
59
+ const DRAFT_WORK_ORDER_OPERATIONAL_HOOKS = new Set([
60
+ "draft-work-order-plan"
61
+ ]);
52
62
  export async function injectWorktreeArtifacts(worktreePath, artifacts) {
53
63
  for (const artifact of artifacts) {
54
64
  await writeArtifact(worktreePath, artifact);
@@ -64,7 +74,7 @@ export function filterArtifactsForLane(artifacts, lane, phase) {
64
74
  return artifacts.filter((artifact) => shouldInjectArchitectArtifact(artifact, commandSlug));
65
75
  }
66
76
  if (normalizedLane === "draft") {
67
- return artifacts.filter((artifact) => shouldInjectDraftArtifact(artifact, commandSlug));
77
+ return artifacts.filter((artifact) => shouldInjectDraftArtifact(artifact, commandSlug, phase));
68
78
  }
69
79
  return artifacts;
70
80
  }
@@ -142,7 +152,7 @@ function shouldInjectArchitectArtifact(artifact, commandSlug) {
142
152
  return false;
143
153
  }
144
154
  }
145
- function shouldInjectDraftArtifact(artifact, commandSlug) {
155
+ function shouldInjectDraftArtifact(artifact, commandSlug, phase) {
146
156
  if (artifact.scope.trim().toLowerCase() !== "operational") {
147
157
  return false;
148
158
  }
@@ -151,13 +161,36 @@ function shouldInjectDraftArtifact(artifact, commandSlug) {
151
161
  case "command":
152
162
  return slug === commandSlug;
153
163
  case "skill":
154
- return DRAFT_OPERATIONAL_SKILLS.has(slug);
164
+ return DRAFT_OPERATIONAL_SKILLS.has(slug) || draftPhaseSkills(phase).has(slug);
155
165
  case "hook":
156
- return DRAFT_OPERATIONAL_HOOKS.has(slug);
166
+ return DRAFT_OPERATIONAL_HOOKS.has(slug) || draftPhaseHooks(phase).has(slug);
157
167
  default:
158
168
  return false;
159
169
  }
160
170
  }
171
+ function draftPhaseSkills(phase) {
172
+ switch (normalizeDraftPhase(phase)) {
173
+ case "work_order":
174
+ return DRAFT_WORK_ORDER_OPERATIONAL_SKILLS;
175
+ case "story":
176
+ return DRAFT_WORK_ITEM_OPERATIONAL_SKILLS;
177
+ default:
178
+ return DRAFT_WORK_ITEM_OPERATIONAL_SKILLS;
179
+ }
180
+ }
181
+ function draftPhaseHooks(phase) {
182
+ switch (normalizeDraftPhase(phase)) {
183
+ case "work_order":
184
+ return DRAFT_WORK_ORDER_OPERATIONAL_HOOKS;
185
+ case "story":
186
+ return DRAFT_WORK_ITEM_OPERATIONAL_HOOKS;
187
+ default:
188
+ return DRAFT_WORK_ITEM_OPERATIONAL_HOOKS;
189
+ }
190
+ }
191
+ function normalizeDraftPhase(phase) {
192
+ return phase.trim().toLowerCase().replaceAll("-", "_");
193
+ }
161
194
  export function buildSpecBody(laneCommand, workItem, phase = "implementation") {
162
195
  const prompt = laneCommand.body.replaceAll("{workItemId}", workItem.id);
163
196
  return `---
@@ -9,7 +9,8 @@ export declare class GitWorktreeService implements WorktreeService {
9
9
  private resolveRepoPath;
10
10
  private findExistingRepoPath;
11
11
  private resolveMatchingRepo;
12
- private ensureBaseBranch;
12
+ private resolveBaseStartPoint;
13
+ private resetWorktreeToBase;
13
14
  private gitRefExists;
14
15
  private currentBranch;
15
16
  private ensureGitIdentity;
@@ -14,7 +14,7 @@ export class GitWorktreeService {
14
14
  const baseBranch = normalizeBranchName(request.baseBranch, "develop");
15
15
  const repoPath = await this.resolveRepoPath(request.repo, allowedRoot, baseBranch);
16
16
  await this.ensureGitIdentity(repoPath);
17
- await this.ensureBaseBranch(repoPath, baseBranch);
17
+ const baseStartPoint = await this.resolveBaseStartPoint(repoPath, baseBranch);
18
18
  const shortId = request.workItem.id.replace(/-/g, "").slice(0, 12);
19
19
  const kind = safeSegment(request.workItem.kind, "work-item");
20
20
  const fallbackWorktreeKey = `${kind}/${shortId}`;
@@ -30,7 +30,7 @@ export class GitWorktreeService {
30
30
  const exists = await directoryExists(worktreePath);
31
31
  let resolvedWorktreePath;
32
32
  if (!exists) {
33
- await this.git.run(repoPath, ["worktree", "add", "-B", branchName, worktreePath, baseBranch]);
33
+ await this.git.run(repoPath, ["worktree", "add", "-B", branchName, worktreePath, baseStartPoint]);
34
34
  resolvedWorktreePath = await resolveExistingDirectoryPath(worktreePath);
35
35
  }
36
36
  else {
@@ -42,6 +42,9 @@ export class GitWorktreeService {
42
42
  if (currentBranch !== branchName) {
43
43
  throw new Error(`Existing worktree ${resolvedWorktreePath} is on branch '${currentBranch}', expected '${branchName}'.`);
44
44
  }
45
+ if (shouldResetExistingWorktree(request)) {
46
+ await this.resetWorktreeToBase(resolvedWorktreePath, baseStartPoint);
47
+ }
45
48
  }
46
49
  await this.ensureGitIdentity(resolvedWorktreePath);
47
50
  await clearRunArtifactRoots(resolvedWorktreePath, request);
@@ -164,21 +167,27 @@ export class GitWorktreeService {
164
167
  const resolved = await resolveExistingDirectoryPath(candidate);
165
168
  return isSubPath(allowedRoot, resolved) ? resolved : null;
166
169
  }
167
- async ensureBaseBranch(repoPath, baseBranch) {
168
- if (await this.gitRefExists(repoPath, `refs/heads/${baseBranch}`)) {
169
- return;
170
- }
170
+ async resolveBaseStartPoint(repoPath, baseBranch) {
171
+ const localRef = `refs/heads/${baseBranch}`;
172
+ const remoteRef = `refs/remotes/origin/${baseBranch}`;
171
173
  const origin = await this.git.run(repoPath, ["remote", "get-url", "origin"]).catch(() => "");
172
- if (origin.trim().length === 0) {
173
- throw new Error(`Base branch '${baseBranch}' was not found in the local checkout.`);
174
+ if (origin.trim().length > 0) {
175
+ const fetched = await this.git.run(repoPath, ["fetch", "--prune", "origin"])
176
+ .then(() => true)
177
+ .catch(() => false);
178
+ if (fetched && await this.gitRefExists(repoPath, remoteRef)) {
179
+ return remoteRef;
180
+ }
174
181
  }
175
- await this.git.run(repoPath, ["fetch", "origin", `${baseBranch}:refs/remotes/origin/${baseBranch}`]).catch(() => "");
176
- if (await this.gitRefExists(repoPath, `refs/remotes/origin/${baseBranch}`)) {
177
- await this.git.run(repoPath, ["branch", baseBranch, `refs/remotes/origin/${baseBranch}`]);
178
- return;
182
+ if (await this.gitRefExists(repoPath, localRef)) {
183
+ return localRef;
179
184
  }
180
185
  throw new Error(`Base branch '${baseBranch}' was not found locally or on origin.`);
181
186
  }
187
+ async resetWorktreeToBase(worktreePath, baseStartPoint) {
188
+ await this.git.run(worktreePath, ["reset", "--hard", baseStartPoint]);
189
+ await this.git.run(worktreePath, ["clean", "-fd"]);
190
+ }
182
191
  async gitRefExists(repoPath, gitRef) {
183
192
  return this.git.run(repoPath, ["show-ref", "--verify", "--quiet", gitRef]).then(() => true).catch(() => false);
184
193
  }
@@ -269,6 +278,17 @@ function normalizeOwnerType(value) {
269
278
  }
270
279
  return null;
271
280
  }
281
+ function shouldResetExistingWorktree(request) {
282
+ const lane = request.lane.trim().toLowerCase();
283
+ const phase = request.phase.trim().toLowerCase().replace(/-/g, "_");
284
+ if (lane === "develop" && (phase === "implementation" || phase === "self_review" || phase === "validation")) {
285
+ return false;
286
+ }
287
+ if (lane === "qa" || phase === "qa") {
288
+ return false;
289
+ }
290
+ return true;
291
+ }
272
292
  function qaReworkPacketFileName(packetPath) {
273
293
  const normalized = packetPath.trim().replace(/\\/g, "/");
274
294
  const fileName = normalized.split("/").filter(Boolean).at(-1) ?? "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loucompanion/forge-bridge",
3
- "version": "0.1.3-dev.b6be5e7f9668",
3
+ "version": "0.1.3-dev.d1ca67076aa9",
4
4
  "description": "Forge runner bridge CLI for connecting local developer machines to Forge dispatch.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",