taskplane 0.5.8 → 0.5.10

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.
@@ -1163,46 +1163,75 @@ export default function (pi: ExtensionAPI) {
1163
1163
  );
1164
1164
 
1165
1165
  // ── Step 3: Execute integration mode ─────────────────
1166
- const integrationResult = executeIntegration(parsed.mode, resolution as IntegrationContext, {
1167
- runGit: (gitArgs: string[]) => runGit(gitArgs, repoRoot),
1168
- runCommand: (cmd: string, cmdArgs: string[]) => {
1169
- try {
1170
- const stdout = execFileSync(cmd, cmdArgs, {
1171
- encoding: "utf-8",
1172
- timeout: 60_000,
1173
- cwd: repoRoot,
1174
- stdio: ["pipe", "pipe", "pipe"],
1175
- }).trim();
1176
- return { ok: true, stdout, stderr: "" };
1177
- } catch (err: unknown) {
1178
- const e = err as { stdout?: string; stderr?: string; message?: string };
1179
- return {
1180
- ok: false,
1181
- stdout: (e.stdout ?? "").toString().trim(),
1182
- stderr: (e.stderr ?? e.message ?? "unknown error").toString().trim(),
1183
- };
1166
+ // In workspace mode, integrate in every repo that has the orch branch.
1167
+ const resolvedOrchBranch = (resolution as IntegrationContext).orchBranch;
1168
+ const wsConfig = execCtx!.workspaceConfig;
1169
+ const reposToIntegrate: { id: string; root: string }[] = [];
1170
+
1171
+ if (wsConfig) {
1172
+ for (const [repoId, repoConf] of wsConfig.repos) {
1173
+ // Check if orch branch exists in this repo
1174
+ const branchCheck = runGit(["rev-parse", "--verify", `refs/heads/${resolvedOrchBranch}`], repoConf.path);
1175
+ if (branchCheck.ok) {
1176
+ reposToIntegrate.push({ id: repoId, root: repoConf.path });
1184
1177
  }
1185
- },
1186
- deleteBatchState: () => deleteBatchState(repoRoot),
1187
- });
1188
-
1189
- if (!integrationResult.success) {
1190
- ctx.ui.notify(integrationResult.error!, "error");
1191
- return;
1178
+ }
1179
+ } else {
1180
+ reposToIntegrate.push({ id: "(default)", root: repoRoot });
1192
1181
  }
1193
1182
 
1194
- // Override commit count with pre-computed value for local integrations
1195
- if (integrationResult.integratedLocally) {
1196
- integrationResult.commitCount = commitsAhead;
1183
+ let totalCommits = 0;
1184
+ let allSucceeded = true;
1185
+ const repoMessages: string[] = [];
1186
+
1187
+ for (const repo of reposToIntegrate) {
1188
+ // Count commits BEFORE integration (after ff, HEAD === orch tip so count would be 0)
1189
+ const preCountResult = runGit(["rev-list", "--count", `HEAD..${resolvedOrchBranch}`], repo.root);
1190
+ const repoCommitsBefore = preCountResult.ok ? parseInt(preCountResult.stdout) || 0 : 0;
1191
+
1192
+ const integrationResult = executeIntegration(parsed.mode, resolution as IntegrationContext, {
1193
+ runGit: (gitArgs: string[]) => runGit(gitArgs, repo.root),
1194
+ runCommand: (cmd: string, cmdArgs: string[]) => {
1195
+ try {
1196
+ const stdout = execFileSync(cmd, cmdArgs, {
1197
+ encoding: "utf-8",
1198
+ timeout: 60_000,
1199
+ cwd: repo.root,
1200
+ stdio: ["pipe", "pipe", "pipe"],
1201
+ }).trim();
1202
+ return { ok: true, stdout, stderr: "" };
1203
+ } catch (err: unknown) {
1204
+ const e = err as { stdout?: string; stderr?: string; message?: string };
1205
+ return {
1206
+ ok: false,
1207
+ stdout: (e.stdout ?? "").toString().trim(),
1208
+ stderr: (e.stderr ?? e.message ?? "unknown error").toString().trim(),
1209
+ };
1210
+ }
1211
+ },
1212
+ deleteBatchState: () => { /* handled once after all repos */ },
1213
+ });
1214
+
1215
+ if (!integrationResult.success) {
1216
+ ctx.ui.notify(`❌ Integration failed in ${repo.id}:\n${integrationResult.error}`, "error");
1217
+ allSucceeded = false;
1218
+ break;
1219
+ }
1220
+
1221
+ totalCommits += repoCommitsBefore;
1222
+ repoMessages.push(` ${repo.id}: ${integrationResult.message}`);
1197
1223
  }
1198
1224
 
1199
- ctx.ui.notify(
1200
- integrationResult.message +
1201
- (integrationResult.integratedLocally
1202
- ? `\n${integrationResult.commitCount} commit(s) applied.`
1203
- : ""),
1204
- "info",
1205
- );
1225
+ if (!allSucceeded) return;
1226
+
1227
+ // Clean up batch state after all repos integrated
1228
+ try { deleteBatchState(repoRoot); } catch { /* best effort */ }
1229
+
1230
+ const summary = wsConfig
1231
+ ? `✅ Integrated ${resolvedOrchBranch} across ${reposToIntegrate.length} repo(s).\n${repoMessages.join("\n")}\n${totalCommits} total commit(s) applied.`
1232
+ : `${repoMessages[0] || "✅ Integrated."}\n${commitsAhead} commit(s) applied.`;
1233
+
1234
+ ctx.ui.notify(summary, "info");
1206
1235
  },
1207
1236
  });
1208
1237
 
@@ -787,12 +787,10 @@ export function mergeWave(
787
787
  spawnSync("git", ["commit", "-m", `checkpoint: wave ${waveIndex} task artifacts (.DONE, STATUS.md)`], { cwd: mergeWorkDir });
788
788
  execLog("merge", `W${waveIndex}`, `committed ${staged} task artifact(s) to merge worktree`);
789
789
 
790
- // Restore the repo's working tree remove the artifacts from develop's working tree
791
- // so they don't cause conflicts on /orch-integrate
792
- for (const file of artifactFiles) {
793
- spawnSync("git", ["checkout", "--", file], { cwd: repoRoot });
794
- }
795
- // Also remove any untracked .DONE files
790
+ // Restore .DONE files onlythese are untracked and would cause
791
+ // "dirty working tree" issues on /orch-integrate.
792
+ // Keep STATUS.md modifications in develop's working tree so the
793
+ // dashboard can read current progress from the canonical path.
796
794
  for (const file of artifactFiles) {
797
795
  if (file.endsWith(".DONE")) {
798
796
  const srcPath = join(repoRoot, file);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",