Windows: prompt attachments parity for the New Node draft flow - #415
Merged
Merged
Conversation
coneilen
force-pushed
the
coneilen-microsoft-windows-prompt-attachments
branch
5 times, most recently
from
September 22, 2026 20:55
0e9d754 to
a089e8f
Compare
Windows equivalent of macOS's ProjectFeature+Attachments.swift /
NodeDraftAttachments.swift: attach supported files/images from a native
multi-select file picker into the New Node dialog, ingest them with
size/type validation, display name/type/size with removal before submit,
persist staged assets to a bounded per-draft attachments directory, and
carry attachment references in the typed node draft and daemon wire
payload in the same PromptAttachment shape Swift's NodeDraft decodes.
- DraftAttachments.zig (new): extension/size validation, project-path
slugging, attachments-directory resolution, file ingestion, directory
cleanup, and [image #N] token generation/removal-with-renumbering,
ported from the macOS reference. 8 unit tests.
- FilePicker.c/.h (new): IFileOpenDialog-based multi-select file picker
with an extension filter matching the supported types, mirroring the
existing FolderPicker.c.
- Forms.zig: NodeDraft gains node_id/attachment_paths/attachment_ids/
attachment_count; validateNode bounds attachment_count; new public
generateDraftId lets a draft's id be chosen before its dialog opens
(needed so attachments can be filed under the id the node will
eventually carry), hardened against same-tick collisions with a
process-lifetime counter.
- Wire.zig: commandGraphCreateNodeFull now encodes "attachments" as
[{"id":...,"path":...}], always an array, matching Swift
PromptAttachment's Codable shape exactly.
- DaemonClient.zig: sendCreateNodeDraft prefers draft.node_id when the
dialog staged at least one attachment, instead of always generating a
fresh id at send time.
- App.zig: createNode pre-generates the draft id before opening the
dialog so attachments can be filed under it while the dialog is open.
- NativeForms.zig: adds an Attachments section to the node dialog as an
independent custom-drawn section (list, Attach/Remove buttons, help
text) appended after the generic field loop, rather than renumbering
the existing worktree/subgraph/createdBy pass-through field indices -
this keeps every existing field index, label, and values[] slot
untouched. Handles attach/remove, [image #N] token insertion into the
active brief field, lazy per-draft directory creation, listbox
refresh, and cleanup of staged files on cancel or post-validation
failure.
- windows-tests/GraphCommandInteropTests.swift + new fixture: decodes a
node draft with an attachment through the real Swift NodeDraft/
PromptAttachment Codable types and PromptAttachments.resolving.
Diffs to Wire.zig/NativeForms.zig/DaemonClient.zig were kept to their
minimal logical changes (not a whole-file zig fmt reformat), since these
files were not already zig-fmt-clean under the pinned 0.15.2 formatter
and another branch may also be editing NativeForms.zig.
Testing:
- zig test src\Forms.zig: 59/59 passed (Forms + GraphModel + Wire,
including new attachments wire-encoding and generateDraftId tests).
- zig test src\NativeForms.zig -lc (with a stub winghostty header to get
past cImport, since this environment has no pinned Winghostty
provider): 92/92 passed, including new tests for buildNodeDraft's
attachment/node_id carry-through and attachment section visibility.
Known blockers / remaining scope:
- Full exe build and WindowsShell/UIA live-automation evidence require
bootstrapping a pinned Winghostty provider worktree
(Tools/windows/bootstrap.ps1), not available in this environment.
- Clipboard paste and drag-drop attachment support were not implemented;
left as documented remaining scope rather than partially faked.
- Swift interop test run (windows-tests/GraphCommandInteropTests.swift)
could not be executed locally: SwiftPM dependency resolution hits an
environment-enforced git safe.bareRepository=explicit policy that
blocks fetching tags from the cached bare dependency repos. The new
fixture/test were written to the same pattern as the existing passing
cases and should decode identically in CI.
Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
coneilen
force-pushed
the
coneilen-microsoft-windows-prompt-attachments
branch
from
September 22, 2026 22:31
a089e8f to
d726575
Compare
Keep form validation single-pass while classifying Forms.FormError results at the App boundary, so invalid drafts retain the user-facing validation message rather than looking like dialog creation failed. Signed-off-by: Colin Neilens <coneilen@microsoft.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
coneilen
added a commit
that referenced
this pull request
Sep 22, 2026
The prompt-attachments slice (PR #415) landed the native picker, staged ingestion, and daemon wire encoding, but the parity matrix had no row or evidence mentioning attachments at all, so the ledger under-recorded what actually shipped. Fold the evidence into the existing Node creation sheet row, where the macOS attachment affordance lives, and keep the row Partial: clipboard paste and drag-and-drop are still unimplemented, and the live file-picker interaction is not exercised by the UI Automation gate, so picker behavior rests on unit coverage rather than live evidence. Documentation only; no status upgrades and no code changes. Signed-off-by: Colin Neilens <coneilen@microsoft.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Windows equivalent of macOS's
ProjectFeature+Attachments.swift/NodeDraftAttachments.swift: attach supported files and images from a native multi-select file picker into the New Node dialog, ingest them with size/type validation, show name/type/size with removal before submit, persist staged assets to a bounded per-draft attachments directory, and carry attachment references in the typed node draft and daemon wire payload in the samePromptAttachmentshape Swift'sNodeDraftdecodes.DraftAttachments.zig(new): extension/size validation, project-path slugging, attachments-directory resolution, file ingestion, directory cleanup, and[image #N]token generation and removal-with-renumbering, ported from the macOS reference. 8 unit tests.FilePicker.c/.h(new):IFileOpenDialog-based multi-select picker with an extension filter matching the supported types, mirroring the existingFolderPicker.c.Forms.zig:NodeDraftgainsnode_id/attachment_paths/attachment_ids/attachment_count;validateNodeboundsattachment_count; new publicgenerateDraftIdlets a draft's id be chosen before its dialog opens (so attachments are filed under the id the node will carry), hardened against same-tick collisions with a process-lifetime counter.Wire.zig:commandGraphCreateNodeFullencodesattachmentsas[{"id":...,"path":...}], always an array, matching SwiftPromptAttachment's Codable shape exactly.Validation
RED: git show a4aafc5:graphcode-windows/src/Wire.zig and a4aafc5:graphcode-windows/src/Forms.zig -> no attachment ingestion path existed: NodeDraft carried no attachment fields, commandGraphCreateNodeFull emitted no attachments key, and the New Node dialog had no picker, so nothing could round-trip into Swift PromptAttachment
GREEN: zig test graphcode-windows/src/DraftAttachments.zig -> 8 tests passed covering extension and size validation, project-path slugging, attachments-directory resolution, ingestion, cleanup, and image-token renumbering
REGRESSION: zig test graphcode-windows/src/Forms.zig and zig test graphcode-windows/src/Wire.zig -> existing Forms and Wire suites passed with the new node_id/attachment fields and the always-array attachments encoding
Coverage limits — read before marking any row Validated
The native
IFileOpenDialogpicker cannot be driven headlessly in CI, so the live picker interaction is not proven by this PR. What is proven is everything behind it: validation, slugging, directory resolution, ingestion, cleanup, token renumbering, draft field plumbing, and the exact wire encoding. The picker invocation itself remains unproven and its parity row must stay Partial until a live walkthrough exists.Authoritative build and test results for this branch come from this PR's own
windows-shelljob under the repo-pinned Zig 0.15.2. Local Zig 0.16 is a different toolchain and has already produced misleading results elsewhere in this effort, so CI governs.Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com