Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion docs/open-collection-gap-analysis/AGENT_PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ Use full branch names for stacking existing branches with `but move <child-branc
| OC-100 | Request type UX | Done | Codex | feature/oc-100-request-type-ux (g0 after restack), stacked on supervisor/add-request-type-ux-task; implementation commit `5cb05a3` | Satisfied by `test/requestTypeUx.test.ts`: schema-valid HTTP/GraphQL/WebSocket/gRPC starter templates, actual `missio.newRequest` protocol picker/write/open flow, YAML and editor-model round-trip safety, no stale protocol roots, gRPC same-protocol editor guard, and read-only protocol chip shell. Shared regressions cover HTTP/GraphQL/WebSocket/gRPC editor, validation, command/tool, and protocol behavior. Switcher/conversion helpers are intentionally out of scope because the benchmarked tools emphasize protocol choice at creation and Postman locks saved request protocols. | `npx vitest run test/requestTypeUx.test.ts test/schemaRoundTrip.test.ts test/openCollectionFoundation.test.ts test/validationService.test.ts` passed 4 files/25 tests; targeted protocol suite passed 8 files/68 tests; `npm run compile` passed; `npm test` passed 21 files/405 tests; `node scripts/validate-collection.js examples/demo-api` passed 42/42 files; `npm run build` passed. | 2026-06-15 00:15 NZT | OC-100 complete; no saved-request switcher was added by product decision and benchmark alignment. Remaining unassigned changes are parallel OC-050/OC-090 work, not OC-100. |
| OC-110 | Runtime authoring UX | Done | Codex | feature/oc-110-runtime-authoring-ux (g0), stacked on supervisor/add-runtime-authoring-ux-task; implementation commit `fe0ad14`; supervisor follow-up commit `1e6db05`; supervisor acceptance recorded | Satisfied by `test/runtimeAuthoringUx.test.ts`, `test/runtimeExecutionService.test.ts`, `test/validationService.test.ts`, and shared schema/protocol regressions: visual editor can author supported runtime scripts/tests/assertions/actions, no longer offers non-executing `hooks` scripts or unsupported persisted scopes for new rows, preserves schema-valid existing `hooks`/persisted-scope YAML with diagnostics, and runtime actions diagnose unsupported scopes instead of silently writing runtime variables. | `npm run compile` passed; focused `npx vitest run test/runtimeAuthoringUx.test.ts test/runtimeExecutionService.test.ts test/validationService.test.ts test/schemaRoundTrip.test.ts test/requestTypeUx.test.ts test/webSocketSupport.test.ts test/grpcSupport.test.ts` passed 7 files/69 tests; `node scripts\validate-collection.js examples\demo-api` passed 44/44 files; `npm test` passed 23 files/437 tests; `npm run build` passed. | 2026-06-15 09:51 NZT | Supervisor review accepted OC-110 rework; no remaining blocking findings. |
| OC-120 | Preview media zoom and rotate controls | Done | Codex | `feature/oc-120-preview-media-controls` (ia), currently stacked under OC-130/OC-140; commits `cf8d2e3`, `7d3f766`, `18dc78c`, `e31c2cd`, `fc3e164`, and `c5296ea`; no PR yet | Satisfied by `test/previewMediaControls.test.ts`: pure transform helpers, compact toolbar markup/labels/icons, rotate controls using rotate-like codicons, Ctrl+wheel and toolbar zoom handling, image/PDF controls, stale PDF render and loading-task cancellation, large PDF canvas pixel/render-scale budgeting while preserving visual zoom dimensions, packaged PDF.js asset eligibility, and generated request panel CSP checks. | `npx vitest run test/previewMediaControls.test.ts` passed 10 tests; `npm run compile` passed; targeted `npx vitest run test/previewMediaControls.test.ts test/requestTypeUx.test.ts test/responseProvider.test.ts` passed 3 files/22 tests; `npm run build` passed; `npx @vscode/vsce package --out $env:TEMP\missio-0.8.0-oc120-pdf-zoom-stability.vsix` passed; direct VSIX zip inspection found `extension/media/pdf.worker.min.mjs` and `extension/media/pdf.min.mjs`. | 2026-06-15 13:40 NZT | OC-120 user follow-up fixed. Preserve unrelated unassigned PDF.js media churn IDs `qp`/`ko`. |
| OC-130 | Protocol-native request editor first paint | Unclaimed | TBD | TBD | Add automated coverage for startup state, neutral/protocol-aware first paint, no HTTP-default flash for GraphQL/WebSocket/gRPC, invalid YAML fallback, layout stability, and shared request editor/protocol regressions. | Not started. | 2026-06-15 11:25 NZT | Claim with `missio-agent-coordination`; read `tasks/13-protocol-layout-stability.md`; create a focused branch before editing request panel code. |
| OC-130 | Protocol-native request editor first paint | Done | Codex | `feature/oc-130-protocol-layout-stability` (g0), stacked on `feature/oc-120-preview-media-controls`; implementation commit `a3d3251` | Satisfied by `test/protocolLayoutStability.test.ts` plus shared request editor/protocol regressions: neutral first-paint shell, host invalid-YAML fallback message, direct HTTP/GraphQL/WebSocket/gRPC hydration, no visible HTTP default or stale non-HTTP controls during hydration, layout-stability CSS assertions, no-op round-trip and protocol-aware validation coverage, and request type UX startup regression. | `npx vitest run test/protocolLayoutStability.test.ts` passed 9 tests; `npm run compile` passed; focused `npx vitest run test/protocolLayoutStability.test.ts test/requestTypeUx.test.ts test/runtimeAuthoringUx.test.ts test/schemaRoundTrip.test.ts test/validationService.test.ts` passed 5 files/34 tests; targeted protocol/editor matrix passed 9 files/89 tests; `node scripts\validate-collection.js examples\demo-api` passed 44/44 files; `npm test` passed 25 files/454 tests; `npm run build` passed. | 2026-06-15 12:03 NZT | OC-130 complete. Preserve parallel/unrelated unassigned OC-140 docs IDs `wp`/`tks`/`tkt`/`uxu` and PDF.js media churn IDs `qp`/`ko`; do not commit them to OC-130. |
| OC-140 | First-class WebSocket lifecycle UX | Unclaimed | TBD | TBD | Add automated coverage for WebSocket session manager state transitions, local fixture client lifecycle, separate editor connect/disconnect/send controls, message history, VS Code status bar commands, command palette/tree actions, CodeLens, Copilot lifecycle tools, cleanup/deactivation, failure diagnostics, round-trip/validation, and shared WebSocket regressions. | Not started. | 2026-06-15 12:05 NZT | Claim with `missio-agent-coordination`; read `tasks/14-websocket-lifecycle-ux.md`; coordinate with OC-130 before editing shared request editor startup/layout or WebSocket editor files. |

## Dependency Map

Expand Down Expand Up @@ -125,6 +126,22 @@ Record cross-cutting decisions here so parallel agents do not rediscover them.
Verified: `rg -n "OC-130|13-protocol-layout-stability|Protocol Layout Stability" docs\open-collection-gap-analysis` confirmed task references and goal prompt; implementation tests not required for docs-only task creation.
Next: launch OC-130 after or alongside OC-120 only if the agent coordinates shared `requestPanel` CSS and webview startup surfaces.

- 2026-06-15 12:05 NZT - Codex Supervisor: Added OC-140 as a focused follow-up task for first-class WebSocket lifecycle management.
GitButler: planning update is on `supervisor/add-websocket-lifecycle-task`; existing uncommitted OC-120/OC-130 progress and WebSocket/media implementation changes were preserved and not overwritten.
Coverage: documentation-only planning change; the task requires future automated session-manager, local fixture lifecycle, editor UI, status bar, command, CodeLens, Copilot tool, cleanup/deactivation, failure-path, round-trip, validation, and shared WebSocket regression tests.
Changed: `docs/open-collection-gap-analysis/README.md`, `AGENT_GOAL_PROMPTS.md`, `AGENT_PROGRESS.md`, and `tasks/14-websocket-lifecycle-ux.md`.
Verified: task references and goal prompt added; implementation tests not required for docs-only task creation.
Next: launch OC-140 after OC-130 settles request editor startup changes, or in parallel only with explicit coordination around shared request editor, WebSocket client, CodeLens, and Copilot surfaces.

### OC-130 Protocol-Native Request Editor First Paint

- 2026-06-15 12:03 NZT - Codex: Completed OC-130 with a neutral first-paint shell and protocol-native hydration for HTTP, GraphQL, WebSocket, and gRPC request editors.
GitButler: `feature/oc-130-protocol-layout-stability` (g0), stacked on `feature/oc-120-preview-media-controls`; implementation/test commit `a3d3251` (`Add OC-130 protocol first paint stability`). Earlier `but commit --changes ...` failed with `Unexpected hunk with neither newlines or oldlines being 0`, so the owned files were staged by path to g0 and committed with `--only`.
Coverage: implemented `test/protocolLayoutStability.test.ts` for neutral startup markup, hidden pending/invalid controls with stable dimensions, direct protocol hydration for HTTP/GraphQL/WebSocket/gRPC, invalid-YAML fallback, host parse-failure messaging, and no-op round-trip/validation; updated request type UX startup assertions so static HTML is protocol-pending instead of HTTP.
Changed: `src/panels/requestPanel.ts`, `src/webview/requestPanel.ts`, `src/webview/requestPanel.css`, `test/protocolLayoutStability.test.ts`, `test/requestTypeUx.test.ts`, and this ledger.
Verified: `npx vitest run test/protocolLayoutStability.test.ts` passed 9 tests; `npm run compile` passed; focused `npx vitest run test/protocolLayoutStability.test.ts test/requestTypeUx.test.ts test/runtimeAuthoringUx.test.ts test/schemaRoundTrip.test.ts test/validationService.test.ts` passed 5 files/34 tests; targeted `npx vitest run test/protocolLayoutStability.test.ts test/requestTypeUx.test.ts test/runtimeAuthoringUx.test.ts test/graphqlSupport.test.ts test/webSocketSupport.test.ts test/grpcSupport.test.ts test/openCollectionFoundation.test.ts test/schemaRoundTrip.test.ts test/validationService.test.ts` passed 9 files/89 tests; `node scripts\validate-collection.js examples\demo-api` passed 44/44 files; `npm test` passed 25 files/454 tests; `npm run build` passed.
Next: OC-130 is complete. Remaining unassigned changes are parallel/unrelated OC-140 planning IDs `wp`/`tks`/`tkt`/`uxu` and PDF.js media churn IDs `qp`/`ko`.

- 2026-06-15 00:57 NZT - Codex: Added OC-110 as a separate runtime authoring UX task after confirming snippet export belongs to OC-070 and non-HTTP runtime execution belongs to OC-080.
GitButler: planning update is on `supervisor/add-runtime-authoring-ux-task`, stacked on `supervisor/oc-050-090-100-audit`; active OC-070 implementation changes in `zz` were not edited or committed.
Coverage: documentation-only planning change; no runtime behavior changed.
Expand Down
1 change: 1 addition & 0 deletions src/panels/basePanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ export abstract class BaseEditorProvider implements vscode.CustomTextEditorProvi
.codicon-plug::before { content: '\\eb2d'; }
.codicon-radio-tower::before { content: '\\eb34'; }
.codicon-type-hierarchy::before { content: '\\ebb9'; }
.codicon-symbol-interface::before { content: '\\eb61'; }
.codicon-add::before { content: '\\ea60'; }
.codicon-desktop-download::before { content: '\\ec74'; }
.codicon-trash::before { content: '\\ea81'; }
Expand Down
23 changes: 20 additions & 3 deletions src/panels/requestPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,13 @@ export class RequestEditorProvider extends BaseEditorProvider {
const request = parseYaml(document.getText()) as OpenCollectionRequest;
migrateRequest(request);
webview.postMessage({ type: 'requestLoaded', request, filePath: document.uri.fsPath });
} catch { /* Invalid YAML, don't update webview */ }
} catch (error) {
webview.postMessage({
type: 'requestLoadError',
filePath: document.uri.fsPath,
message: error instanceof Error ? error.message : 'Unable to parse request YAML.',
});
}
}

private _readDocumentRequest(document: vscode.TextDocument): OpenCollectionRequest | undefined {
Expand Down Expand Up @@ -823,6 +829,16 @@ window.missioPdfJsReady = import('${pdfJsUri}')

protected _getBodyHtml(_webview: vscode.Webview): string {
return `
<div class="request-editor-shell is-hydrating" id="requestEditorShell" data-hydration-state="pending" data-protocol="pending" aria-busy="true">
<div class="request-startup-shell" id="requestStartupShell" role="status" aria-live="polite">
<div class="request-startup-card">
<span class="codicon codicon-symbol-interface request-startup-icon" aria-hidden="true"></span>
<div>
<div class="request-startup-title" id="requestStartupTitle">Loading request</div>
<div class="request-startup-detail" id="requestStartupDetail">Preparing editor...</div>
</div>
</div>
</div>
<!-- URL Bar -->
<div class="url-bar">
<div class="method-picker" id="methodPicker">
Expand All @@ -837,8 +853,8 @@ window.missioPdfJsReady = import('${pdfJsUri}')
</select>
</div>
<div class="url-wrap" id="urlWrap">
<span class="codicon codicon-globe protocol-icon protocol-icon-http" id="protocolIcon" role="img" aria-label="HTTP request type" title="HTTP request type"></span>
<div class="url-input" id="url" contenteditable="true" spellcheck="false" data-placeholder="{{baseUrl}}/api/endpoint"></div>
<span class="codicon codicon-symbol-interface protocol-icon protocol-icon-pending" id="protocolIcon" role="img" aria-label="Request type loading" title="Request type loading"></span>
<div class="url-input" id="url" contenteditable="true" spellcheck="false" data-placeholder="Loading request..."></div>
</div>
<button class="btn btn-toggle" id="varToggleBtn" title="Toggle resolved variables">{{}}</button>
<button class="btn btn-primary" id="sendBtn">Send</button>
Expand Down Expand Up @@ -1083,6 +1099,7 @@ window.missioPdfJsReady = import('${pdfJsUri}')
</div>
</div>
</div>
</div>
</div>`;
}
}
Expand Down
70 changes: 70 additions & 0 deletions src/webview/requestPanel.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,75 @@ body {
overflow: hidden;
}

.request-editor-shell {
position: relative;
height: 100vh;
min-height: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}

.request-editor-shell.is-hydrating .url-bar,
.request-editor-shell.is-hydrating .main-content,
.request-editor-shell.is-invalid-yaml .url-bar,
.request-editor-shell.is-invalid-yaml .main-content {
visibility: hidden;
pointer-events: none;
}

.request-startup-shell {
position: absolute;
inset: 0;
z-index: 20;
display: flex;
align-items: flex-start;
justify-content: center;
padding: 12px 16px;
background: var(--bg);
}

.request-editor-shell.is-ready .request-startup-shell {
display: none;
}

.request-startup-card {
width: min(100%, 520px);
min-height: 44px;
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--input-bg);
color: var(--fg);
}

.request-startup-icon {
color: var(--m-fg-muted);
font-size: 16px;
flex: 0 0 auto;
}

.request-startup-title {
font-size: 12px;
font-weight: 700;
line-height: 1.3;
}

.request-startup-detail {
margin-top: 2px;
font-size: 12px;
line-height: 1.35;
color: var(--m-fg-muted);
overflow-wrap: anywhere;
}

.request-editor-shell.is-invalid-yaml .request-startup-icon {
color: var(--badge-warn);
}

/* ── URL Bar ─────────────────────────────── */
.url-bar {
display: flex;
Expand Down Expand Up @@ -222,6 +291,7 @@ body {
.protocol-icon-graphql { color: var(--m-protocol-graphql); }
.protocol-icon-websocket { color: var(--m-protocol-websocket); }
.protocol-icon-grpc { color: var(--m-protocol-grpc); }
.protocol-icon-pending { color: var(--m-fg-muted); }
.url-input {
width: 100%;
height: 100%;
Expand Down
57 changes: 49 additions & 8 deletions src/webview/requestPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,40 @@ let _selectedFileVariantIndex: number | undefined;
type PanelProtocol = 'http' | 'graphql' | 'websocket' | 'grpc';
let _currentProtocol: PanelProtocol = 'http';

function detectPanelProtocol(req: any): PanelProtocol {
const detectedProtocol = detectRequestProtocol(req);
return detectedProtocol === 'graphql' || detectedProtocol === 'websocket' || detectedProtocol === 'grpc'
? detectedProtocol
: 'http';
}

function setEditorHydrationState(
state: 'pending' | 'ready' | 'invalid',
protocol: PanelProtocol | 'pending' = 'pending',
message?: string,
): void {
const shell = $('requestEditorShell');
const startup = $('requestStartupShell');
const title = $('requestStartupTitle');
const detail = $('requestStartupDetail');

shell.classList.toggle('is-hydrating', state === 'pending');
shell.classList.toggle('is-ready', state === 'ready');
shell.classList.toggle('is-invalid-yaml', state === 'invalid');
shell.dataset.hydrationState = state;
shell.dataset.protocol = protocol;
shell.setAttribute('aria-busy', state === 'pending' ? 'true' : 'false');

startup.style.display = state === 'ready' ? 'none' : 'flex';
if (state === 'invalid') {
title.textContent = 'Request YAML could not be loaded';
detail.textContent = message || 'Fix the YAML source and the editor will reload.';
} else {
title.textContent = 'Loading request';
detail.textContent = protocol === 'pending' ? 'Preparing editor...' : 'Preparing ' + protocol + ' editor...';
}
}

function scheduleDocumentUpdate(): void {
if (updateDocumentTimer) clearTimeout(updateDocumentTimer);
setUpdateDocumentTimer(setTimeout(() => {
Expand Down Expand Up @@ -1425,6 +1459,7 @@ function setSendingState(sending: boolean): void {

// ── Save ────────────────────────────────────────
function saveRequest(): void {
if ($('requestEditorShell').dataset.hydrationState !== 'ready') return;
if (updateDocumentTimer) {
clearTimeout(updateDocumentTimer);
setUpdateDocumentTimer(null);
Expand All @@ -1435,14 +1470,10 @@ function saveRequest(): void {
}

// ── Load request into UI ────────────────────────
function loadRequest(req: any): void {
function loadRequest(req: any): PanelProtocol {
setCurrentRequest(req);
$('exampleIndicator').style.display = 'none';
const detectedProtocol = detectRequestProtocol(req);
const protocol: PanelProtocol =
detectedProtocol === 'graphql' || detectedProtocol === 'websocket' || detectedProtocol === 'grpc'
? detectedProtocol
: 'http';
const protocol = detectPanelProtocol(req);
setProtocolUi(protocol);
const details = protocol === 'websocket'
? (req.websocket || {})
Expand Down Expand Up @@ -1574,6 +1605,7 @@ function loadRequest(req: any): void {
$input('settingMaxRedirects').value = settings.maxRedirects !== undefined && settings.maxRedirects !== 'inherit' ? settings.maxRedirects : '5';

updateBadges();
return protocol;
}

// ── CLI Approval Modal ───────────────────────────
Expand Down Expand Up @@ -1765,9 +1797,18 @@ window.addEventListener('message', (event: MessageEvent) => {
case 'requestLoaded':
if (ignoreNextLoad) {
setIgnoreNextLoad(false);
break;
if ($('requestEditorShell').dataset.hydrationState === 'ready') break;
}
loadRequest(msg.request);
try {
const protocol = loadRequest(msg.request);
setEditorHydrationState('ready', protocol);
} catch (error) {
console.error('Failed to render request editor state', error);
setEditorHydrationState('invalid', 'pending', 'Unable to render this request.');
}
break;
case 'requestLoadError':
setEditorHydrationState('invalid', 'pending', msg.message);
break;
case 'response':
$('exampleIndicator').style.display = 'none';
Expand Down
Loading
Loading