@chllming/wave-orchestration 0.5.3 → 0.5.4

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 (79) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +56 -509
  3. package/docs/README.md +39 -0
  4. package/docs/concepts/context7-vs-skills.md +94 -0
  5. package/docs/concepts/operating-modes.md +91 -0
  6. package/docs/concepts/runtime-agnostic-orchestration.md +95 -0
  7. package/docs/concepts/what-is-a-wave.md +133 -0
  8. package/docs/guides/planner.md +113 -0
  9. package/docs/guides/terminal-surfaces.md +80 -0
  10. package/docs/image.png +0 -0
  11. package/docs/plans/context7-wave-orchestrator.md +2 -0
  12. package/docs/plans/current-state.md +10 -0
  13. package/docs/plans/master-plan.md +3 -3
  14. package/docs/plans/migration.md +4 -3
  15. package/docs/plans/wave-orchestrator.md +27 -3
  16. package/docs/reference/runtime-config/README.md +19 -0
  17. package/docs/reference/skills.md +156 -0
  18. package/docs/roadmap.md +160 -564
  19. package/package.json +2 -1
  20. package/releases/manifest.json +17 -0
  21. package/scripts/wave-orchestrator/config.mjs +17 -0
  22. package/scripts/wave-orchestrator/context7.mjs +9 -0
  23. package/scripts/wave-orchestrator/coordination.mjs +16 -0
  24. package/scripts/wave-orchestrator/executors.mjs +24 -11
  25. package/scripts/wave-orchestrator/install.mjs +41 -2
  26. package/scripts/wave-orchestrator/launcher.mjs +113 -20
  27. package/scripts/wave-orchestrator/planner.mjs +1328 -0
  28. package/scripts/wave-orchestrator/project-profile.mjs +190 -0
  29. package/scripts/wave-orchestrator/shared.mjs +2 -0
  30. package/scripts/wave-orchestrator/skills.mjs +448 -0
  31. package/scripts/wave-orchestrator/terminals.mjs +16 -0
  32. package/scripts/wave-orchestrator/traces.mjs +23 -0
  33. package/scripts/wave-orchestrator/wave-files.mjs +299 -84
  34. package/scripts/wave.mjs +11 -0
  35. package/skills/provider-aws/SKILL.md +6 -0
  36. package/skills/provider-aws/skill.json +5 -0
  37. package/skills/provider-custom-deploy/SKILL.md +5 -0
  38. package/skills/provider-custom-deploy/skill.json +5 -0
  39. package/skills/provider-docker-compose/SKILL.md +6 -0
  40. package/skills/provider-docker-compose/skill.json +5 -0
  41. package/skills/provider-github-release/SKILL.md +6 -0
  42. package/skills/provider-github-release/skill.json +5 -0
  43. package/skills/provider-kubernetes/SKILL.md +6 -0
  44. package/skills/provider-kubernetes/skill.json +5 -0
  45. package/skills/provider-railway/SKILL.md +6 -0
  46. package/skills/provider-railway/adapters/claude.md +1 -0
  47. package/skills/provider-railway/adapters/codex.md +1 -0
  48. package/skills/provider-railway/adapters/local.md +1 -0
  49. package/skills/provider-railway/adapters/opencode.md +1 -0
  50. package/skills/provider-railway/skill.json +5 -0
  51. package/skills/provider-ssh-manual/SKILL.md +6 -0
  52. package/skills/provider-ssh-manual/skill.json +5 -0
  53. package/skills/repo-coding-rules/SKILL.md +7 -0
  54. package/skills/repo-coding-rules/skill.json +5 -0
  55. package/skills/role-deploy/SKILL.md +6 -0
  56. package/skills/role-deploy/skill.json +5 -0
  57. package/skills/role-documentation/SKILL.md +6 -0
  58. package/skills/role-documentation/skill.json +5 -0
  59. package/skills/role-evaluator/SKILL.md +6 -0
  60. package/skills/role-evaluator/skill.json +5 -0
  61. package/skills/role-implementation/SKILL.md +6 -0
  62. package/skills/role-implementation/skill.json +5 -0
  63. package/skills/role-infra/SKILL.md +6 -0
  64. package/skills/role-infra/skill.json +5 -0
  65. package/skills/role-integration/SKILL.md +6 -0
  66. package/skills/role-integration/skill.json +5 -0
  67. package/skills/role-research/SKILL.md +6 -0
  68. package/skills/role-research/skill.json +5 -0
  69. package/skills/runtime-claude/SKILL.md +6 -0
  70. package/skills/runtime-claude/skill.json +5 -0
  71. package/skills/runtime-codex/SKILL.md +6 -0
  72. package/skills/runtime-codex/skill.json +5 -0
  73. package/skills/runtime-local/SKILL.md +5 -0
  74. package/skills/runtime-local/skill.json +5 -0
  75. package/skills/runtime-opencode/SKILL.md +6 -0
  76. package/skills/runtime-opencode/skill.json +5 -0
  77. package/skills/wave-core/SKILL.md +7 -0
  78. package/skills/wave-core/skill.json +5 -0
  79. package/wave.config.json +27 -0
@@ -87,9 +87,12 @@ import {
87
87
  createGlobalDashboardTerminalEntry,
88
88
  createTemporaryTerminalEntries,
89
89
  killTmuxSessionIfExists,
90
+ normalizeTerminalSurface,
90
91
  pruneOrphanLaneTemporaryTerminalEntries,
91
92
  removeLaneTemporaryTerminalEntries,
92
93
  removeTerminalEntries,
94
+ terminalSurfaceUsesTerminalRegistry,
95
+ TERMINAL_SURFACES,
93
96
  } from "./terminals.mjs";
94
97
  import {
95
98
  buildCodexExecInvocation,
@@ -124,6 +127,12 @@ import { buildDocsQueue, readDocsQueue, writeDocsQueue } from "./docs-queue.mjs"
124
127
  import { deriveWaveLedger, readWaveLedger, writeWaveLedger } from "./ledger.mjs";
125
128
  import { buildQualityMetrics, writeTraceBundle } from "./traces.mjs";
126
129
  import { triageClarificationRequests } from "./clarification-triage.mjs";
130
+ import { readProjectProfile, resolveDefaultTerminalSurface } from "./project-profile.mjs";
131
+ import {
132
+ resolveAgentSkills,
133
+ summarizeResolvedSkills,
134
+ writeResolvedSkillArtifacts,
135
+ } from "./skills.mjs";
127
136
  import {
128
137
  buildDependencySnapshot,
129
138
  buildRequestAssignments,
@@ -133,7 +142,22 @@ import {
133
142
  } from "./routing-state.mjs";
134
143
  export { CODEX_SANDBOX_MODES, DEFAULT_CODEX_SANDBOX_MODE, normalizeCodexSandboxMode, buildCodexExecInvocation };
135
144
 
136
- function printUsage(lanePaths) {
145
+ export function formatReconcileBlockedWaveLine(blockedWave) {
146
+ const parts = Array.isArray(blockedWave?.reasons)
147
+ ? blockedWave.reasons
148
+ .map((reason) => {
149
+ const code = compactSingleLine(reason?.code || "", 80);
150
+ const detail = compactSingleLine(reason?.detail || "", 240);
151
+ return code && detail ? `${code}=${detail}` : "";
152
+ })
153
+ .filter(Boolean)
154
+ : [];
155
+ return `[reconcile] wave ${blockedWave?.wave ?? "unknown"} not reconstructable: ${
156
+ parts.join("; ") || "unknown reason"
157
+ }`;
158
+ }
159
+
160
+ function printUsage(lanePaths, terminalSurface) {
137
161
  console.log(`Usage: pnpm exec wave launch [options]
138
162
 
139
163
  Options:
@@ -158,6 +182,8 @@ Options:
158
182
  --codex-sandbox <mode> Codex sandbox mode: ${CODEX_SANDBOX_MODES.join(" | ")} (default: ${DEFAULT_CODEX_SANDBOX_MODE})
159
183
  --manifest-out <path> Write parsed wave manifest JSON (default: ${path.relative(REPO_ROOT, lanePaths.defaultManifestPath)})
160
184
  --dry-run Parse waves and update manifest only
185
+ --terminal-surface <mode>
186
+ Terminal surface: ${TERMINAL_SURFACES.join(" | ")} (default: ${terminalSurface})
161
187
  --no-dashboard Disable per-wave tmux dashboard session
162
188
  --cleanup-sessions Kill lane tmux sessions after each wave (default: on)
163
189
  --keep-sessions Keep lane tmux sessions after each wave
@@ -176,6 +202,7 @@ Options:
176
202
 
177
203
  function parseArgs(argv) {
178
204
  let lanePaths = buildLanePaths(DEFAULT_WAVE_LANE);
205
+ const projectProfile = readProjectProfile();
179
206
  const options = {
180
207
  lane: DEFAULT_WAVE_LANE,
181
208
  startWave: 0,
@@ -193,6 +220,7 @@ function parseArgs(argv) {
193
220
  codexSandboxMode: DEFAULT_CODEX_SANDBOX_MODE,
194
221
  manifestOut: lanePaths.defaultManifestPath,
195
222
  dryRun: false,
223
+ terminalSurface: resolveDefaultTerminalSurface(projectProfile),
196
224
  dashboard: true,
197
225
  cleanupSessions: true,
198
226
  keepTerminals: false,
@@ -216,6 +244,8 @@ function parseArgs(argv) {
216
244
  }
217
245
  if (arg === "--dry-run") {
218
246
  options.dryRun = true;
247
+ } else if (arg === "--terminal-surface") {
248
+ options.terminalSurface = normalizeTerminalSurface(argv[++i], "--terminal-surface");
219
249
  } else if (arg === "--no-dashboard") {
220
250
  options.dashboard = false;
221
251
  } else if (arg === "--cleanup-sessions") {
@@ -305,6 +335,9 @@ function parseArgs(argv) {
305
335
  if (!options.autoNext && options.endWave !== null && options.endWave < options.startWave) {
306
336
  throw new Error("--end-wave must be >= --start-wave");
307
337
  }
338
+ if (!options.dryRun && options.terminalSurface === "none") {
339
+ throw new Error("--terminal-surface none is only supported with --dry-run");
340
+ }
308
341
  return { help: false, lanePaths, options };
309
342
  }
310
343
 
@@ -1336,6 +1369,7 @@ export async function runClosureSweepPhase({
1336
1369
  flushDashboards();
1337
1370
  const launchResult = await launchAgentSessionFn(lanePaths, {
1338
1371
  wave: wave.wave,
1372
+ waveDefinition: wave,
1339
1373
  agent: runInfo.agent,
1340
1374
  sessionName: runInfo.sessionName,
1341
1375
  promptPath: runInfo.promptPath,
@@ -1359,6 +1393,7 @@ export async function runClosureSweepPhase({
1359
1393
  runInfo.lastPromptHash = launchResult?.promptHash || null;
1360
1394
  runInfo.lastContext7 = launchResult?.context7 || null;
1361
1395
  runInfo.lastExecutorId = launchResult?.executorId || runInfo.agent.executorResolved?.id || null;
1396
+ runInfo.lastSkillProjection = launchResult?.skills || summarizeResolvedSkills(runInfo.agent.skillsResolved);
1362
1397
  setWaveDashboardAgent(dashboardState, runInfo.agent.agentId, {
1363
1398
  state: "running",
1364
1399
  detail: `Closure sweep launched${launchResult?.context7?.mode ? ` (${launchResult.context7.mode})` : ""}`,
@@ -1573,7 +1608,7 @@ function removeOrphanWaveDashboards(lanePaths, activeSessionNames) {
1573
1608
  return removedDashboardPaths;
1574
1609
  }
1575
1610
 
1576
- export function reconcileStaleLauncherArtifacts(lanePaths) {
1611
+ export function reconcileStaleLauncherArtifacts(lanePaths, options = {}) {
1577
1612
  const outcome = {
1578
1613
  removedLock: false,
1579
1614
  removedSessions: [],
@@ -1597,12 +1632,14 @@ export function reconcileStaleLauncherArtifacts(lanePaths) {
1597
1632
 
1598
1633
  outcome.removedSessions = cleanupLaneTmuxSessions(lanePaths);
1599
1634
  const activeSessionNames = new Set(listLaneTmuxSessionNames(lanePaths));
1600
- const terminalCleanup = pruneOrphanLaneTemporaryTerminalEntries(
1601
- lanePaths.terminalsPath,
1602
- lanePaths,
1603
- activeSessionNames,
1604
- );
1605
- outcome.removedTerminalNames = terminalCleanup.removedNames;
1635
+ if (terminalSurfaceUsesTerminalRegistry(options.terminalSurface || "vscode")) {
1636
+ const terminalCleanup = pruneOrphanLaneTemporaryTerminalEntries(
1637
+ lanePaths.terminalsPath,
1638
+ lanePaths,
1639
+ activeSessionNames,
1640
+ );
1641
+ outcome.removedTerminalNames = terminalCleanup.removedNames;
1642
+ }
1606
1643
 
1607
1644
  const globalDashboard = readJsonOrNull(lanePaths.globalDashboardPath);
1608
1645
  if (globalDashboard && typeof globalDashboard === "object" && Array.isArray(globalDashboard.waves)) {
@@ -1740,9 +1777,19 @@ function launchWaveDashboardSession(lanePaths, { sessionName, dashboardPath, mes
1740
1777
  );
1741
1778
  }
1742
1779
 
1780
+ function refreshResolvedSkillsForRun(runInfo, waveDefinition, lanePaths) {
1781
+ runInfo.agent.skillsResolved = resolveAgentSkills(
1782
+ runInfo.agent,
1783
+ waveDefinition || { deployEnvironments: [] },
1784
+ { laneProfile: lanePaths.laneProfile },
1785
+ );
1786
+ return runInfo.agent.skillsResolved;
1787
+ }
1788
+
1743
1789
  async function launchAgentSession(lanePaths, params) {
1744
1790
  const {
1745
1791
  wave,
1792
+ waveDefinition = null,
1746
1793
  agent,
1747
1794
  sessionName,
1748
1795
  promptPath,
@@ -1770,6 +1817,20 @@ async function launchAgentSession(lanePaths, params) {
1770
1817
  cacheDir: lanePaths.context7CacheDir,
1771
1818
  disabled: !context7Enabled,
1772
1819
  });
1820
+ const overlayDir = path.join(lanePaths.executorOverlaysDir, `wave-${wave}`, agent.slug);
1821
+ ensureDirectory(overlayDir);
1822
+ const skillsResolved =
1823
+ agent.skillsResolved || resolveAgentSkills(agent, waveDefinition || { deployEnvironments: [] }, {
1824
+ laneProfile: lanePaths.laneProfile,
1825
+ });
1826
+ agent.skillsResolved = skillsResolved;
1827
+ const skillArtifacts = writeResolvedSkillArtifacts(overlayDir, skillsResolved);
1828
+ if (skillArtifacts) {
1829
+ agent.skillsResolved = {
1830
+ ...skillsResolved,
1831
+ artifacts: skillArtifacts,
1832
+ };
1833
+ }
1773
1834
  const prompt = buildExecutionPrompt({
1774
1835
  lane: lanePaths.lane,
1775
1836
  wave,
@@ -1790,12 +1851,12 @@ async function launchAgentSession(lanePaths, params) {
1790
1851
  });
1791
1852
  const promptHash = hashAgentPromptFingerprint(agent);
1792
1853
  fs.writeFileSync(promptPath, `${prompt}\n`, "utf8");
1793
- const overlayDir = path.join(lanePaths.executorOverlaysDir, `wave-${wave}`, agent.slug);
1794
1854
  const launchSpec = buildExecutorLaunchSpec({
1795
1855
  agent,
1796
1856
  promptPath,
1797
1857
  logPath,
1798
1858
  overlayDir,
1859
+ skillProjection: agent.skillsResolved,
1799
1860
  });
1800
1861
  const resolvedExecutorMode = launchSpec.executorId || agent.executorResolved?.id || "codex";
1801
1862
  if (dryRun) {
@@ -1805,8 +1866,16 @@ async function launchAgentSession(lanePaths, params) {
1805
1866
  env: launchSpec.env || {},
1806
1867
  useRateLimitRetries: launchSpec.useRateLimitRetries === true,
1807
1868
  invocationLines: launchSpec.invocationLines,
1869
+ skills: summarizeResolvedSkills(agent.skillsResolved),
1808
1870
  });
1809
- return { promptHash, context7, executorId: resolvedExecutorMode, launchSpec, dryRun: true };
1871
+ return {
1872
+ promptHash,
1873
+ context7,
1874
+ executorId: resolvedExecutorMode,
1875
+ launchSpec,
1876
+ dryRun: true,
1877
+ skills: summarizeResolvedSkills(agent.skillsResolved),
1878
+ };
1810
1879
  }
1811
1880
  killTmuxSessionIfExists(lanePaths.tmuxSocketName, sessionName);
1812
1881
 
@@ -1881,7 +1950,12 @@ async function launchAgentSession(lanePaths, params) {
1881
1950
  ["new-session", "-d", "-s", sessionName, `bash -lc ${shellQuote(command)}`],
1882
1951
  `launch session ${sessionName}`,
1883
1952
  );
1884
- return { promptHash, context7, executorId: resolvedExecutorMode };
1953
+ return {
1954
+ promptHash,
1955
+ context7,
1956
+ executorId: resolvedExecutorMode,
1957
+ skills: summarizeResolvedSkills(agent.skillsResolved),
1958
+ };
1885
1959
  }
1886
1960
 
1887
1961
  async function waitForWaveCompletion(lanePaths, agentRuns, timeoutMinutes, onProgress = null) {
@@ -2198,7 +2272,7 @@ function buildFallbackExecutorState(executorState, executorId, attempt, reason)
2198
2272
  };
2199
2273
  }
2200
2274
 
2201
- function applyRetryFallbacks(agentRuns, failures, lanePaths, attemptNumber) {
2275
+ function applyRetryFallbacks(agentRuns, failures, lanePaths, attemptNumber, waveDefinition = null) {
2202
2276
  const failedAgentIds = new Set(failures.map((failure) => failure.agentId));
2203
2277
  let changed = false;
2204
2278
  const outcomes = new Map();
@@ -2264,6 +2338,7 @@ function applyRetryFallbacks(agentRuns, failures, lanePaths, attemptNumber) {
2264
2338
  continue;
2265
2339
  }
2266
2340
  run.agent.executorResolved = nextState;
2341
+ refreshResolvedSkillsForRun(run, waveDefinition, lanePaths);
2267
2342
  changed = true;
2268
2343
  outcomes.set(run.agent.agentId, {
2269
2344
  applied: true,
@@ -2485,7 +2560,7 @@ export function buildGateSnapshot({
2485
2560
  };
2486
2561
  }
2487
2562
 
2488
- export function resolveRelaunchRuns(agentRuns, failures, derivedState, lanePaths) {
2563
+ export function resolveRelaunchRuns(agentRuns, failures, derivedState, lanePaths, waveDefinition = null) {
2489
2564
  const runsByAgentId = new Map(agentRuns.map((run) => [run.agent.agentId, run]));
2490
2565
  const pendingFeedback = (derivedState?.coordinationState?.humanFeedback || []).filter((record) =>
2491
2566
  isOpenCoordinationStatus(record.status),
@@ -2502,6 +2577,7 @@ export function resolveRelaunchRuns(agentRuns, failures, derivedState, lanePaths
2502
2577
  failures,
2503
2578
  lanePaths,
2504
2579
  nextAttemptNumber,
2580
+ waveDefinition,
2505
2581
  );
2506
2582
  const retryBarrier = retryBarrierFromOutcomes(fallbackResolution.outcomes, failures);
2507
2583
  if (retryBarrier) {
@@ -2671,7 +2747,7 @@ function preflightWavesForExecutorAvailability(waves, lanePaths) {
2671
2747
  export async function runLauncherCli(argv) {
2672
2748
  const parsed = parseArgs(argv);
2673
2749
  if (parsed.help) {
2674
- printUsage(parsed.lanePaths);
2750
+ printUsage(parsed.lanePaths, parsed.options.terminalSurface);
2675
2751
  return;
2676
2752
  }
2677
2753
  const { lanePaths, options } = parsed;
@@ -2743,7 +2819,9 @@ export async function runLauncherCli(argv) {
2743
2819
  }
2744
2820
 
2745
2821
  try {
2746
- const staleArtifactCleanup = reconcileStaleLauncherArtifacts(lanePaths);
2822
+ const staleArtifactCleanup = reconcileStaleLauncherArtifacts(lanePaths, {
2823
+ terminalSurface: options.terminalSurface,
2824
+ });
2747
2825
  const context7BundleIndex = loadContext7BundleIndex(lanePaths.context7BundleIndexPath);
2748
2826
  const allWaves = parseWaveFiles(lanePaths.wavesDir, { laneProfile: lanePaths.laneProfile })
2749
2827
  .map((wave) =>
@@ -2820,6 +2898,9 @@ export async function runLauncherCli(argv) {
2820
2898
  ? reconciliation.state.completedWaves.join(", ")
2821
2899
  : "none";
2822
2900
  console.log(`[reconcile] added from status files: ${addedSummary}`);
2901
+ for (const blockedWave of reconciliation.blockedFromStatus || []) {
2902
+ console.log(formatReconcileBlockedWaveLine(blockedWave));
2903
+ }
2823
2904
  console.log(`[reconcile] completed waves now: ${completedSummary}`);
2824
2905
  return;
2825
2906
  }
@@ -2896,6 +2977,7 @@ export async function runLauncherCli(argv) {
2896
2977
  for (const runInfo of agentRuns) {
2897
2978
  await launchAgentSession(lanePaths, {
2898
2979
  wave: wave.wave,
2980
+ waveDefinition: wave,
2899
2981
  agent: runInfo.agent,
2900
2982
  sessionName: runInfo.sessionName,
2901
2983
  promptPath: runInfo.promptPath,
@@ -2925,6 +3007,9 @@ export async function runLauncherCli(argv) {
2925
3007
  }
2926
3008
 
2927
3009
  preflightWavesForExecutorAvailability(filteredWaves, lanePaths);
3010
+ const terminalRegistryEnabled = terminalSurfaceUsesTerminalRegistry(
3011
+ options.terminalSurface,
3012
+ );
2928
3013
 
2929
3014
  globalDashboard = buildGlobalDashboardState({
2930
3015
  lane: lanePaths.lane,
@@ -2936,7 +3021,7 @@ export async function runLauncherCli(argv) {
2936
3021
  });
2937
3022
  writeGlobalDashboard(lanePaths.globalDashboardPath, globalDashboard);
2938
3023
 
2939
- if (!options.keepTerminals) {
3024
+ if (terminalRegistryEnabled && !options.keepTerminals) {
2940
3025
  const removed = removeLaneTemporaryTerminalEntries(lanePaths.terminalsPath, lanePaths);
2941
3026
  if (removed > 0) {
2942
3027
  recordGlobalDashboardEvent(globalDashboard, {
@@ -2960,8 +3045,10 @@ export async function runLauncherCli(argv) {
2960
3045
  lanePaths,
2961
3046
  globalDashboard.runId || "global",
2962
3047
  );
2963
- appendTerminalEntries(lanePaths.terminalsPath, [globalDashboardTerminalEntry]);
2964
- globalDashboardTerminalAppended = true;
3048
+ if (terminalRegistryEnabled) {
3049
+ appendTerminalEntries(lanePaths.terminalsPath, [globalDashboardTerminalEntry]);
3050
+ globalDashboardTerminalAppended = true;
3051
+ }
2965
3052
  launchWaveDashboardSession(lanePaths, {
2966
3053
  sessionName: globalDashboardTerminalEntry.sessionName,
2967
3054
  dashboardPath: lanePaths.globalDashboardPath,
@@ -3040,8 +3127,10 @@ export async function runLauncherCli(argv) {
3040
3127
  runTag,
3041
3128
  options.dashboard,
3042
3129
  );
3043
- appendTerminalEntries(lanePaths.terminalsPath, terminalEntries);
3044
- terminalsAppended = true;
3130
+ if (terminalRegistryEnabled) {
3131
+ appendTerminalEntries(lanePaths.terminalsPath, terminalEntries);
3132
+ terminalsAppended = true;
3133
+ }
3045
3134
 
3046
3135
  const agentRuns = wave.agents.map((agent) => {
3047
3136
  const safeName = `wave-${wave.wave}-${agent.slug}`;
@@ -3229,6 +3318,7 @@ export async function runLauncherCli(argv) {
3229
3318
  flushDashboards();
3230
3319
  const launchResult = await launchAgentSession(lanePaths, {
3231
3320
  wave: wave.wave,
3321
+ waveDefinition: wave,
3232
3322
  agent: runInfo.agent,
3233
3323
  sessionName: runInfo.sessionName,
3234
3324
  promptPath: runInfo.promptPath,
@@ -3252,6 +3342,8 @@ export async function runLauncherCli(argv) {
3252
3342
  runInfo.lastPromptHash = launchResult?.promptHash || null;
3253
3343
  runInfo.lastContext7 = launchResult?.context7 || null;
3254
3344
  runInfo.lastExecutorId = launchResult?.executorId || runInfo.agent.executorResolved?.id || null;
3345
+ runInfo.lastSkillProjection =
3346
+ launchResult?.skills || summarizeResolvedSkills(runInfo.agent.skillsResolved);
3255
3347
  setWaveDashboardAgent(dashboardState, runInfo.agent.agentId, {
3256
3348
  state: "running",
3257
3349
  detail: "Session launched",
@@ -3780,6 +3872,7 @@ export async function runLauncherCli(argv) {
3780
3872
  failures,
3781
3873
  derivedState,
3782
3874
  lanePaths,
3875
+ wave,
3783
3876
  );
3784
3877
  if (relaunchResolution.barrier) {
3785
3878
  for (const failure of relaunchResolution.barrier.failures) {