feat(plane): add Plane integration - #8667
mzxchandra wants to merge 10 commits into
Conversation
A file-upload subblock holding one file rendered its object keys
("name, path +4") on the canvas card and sentence chip. Multi-file values
already resolved to names; the single-file record now does too.
Adds a Plane (plane.so) block with 32 tools covering work items (create, get, get by identifier, list, search, update, delete), comments, links, attachments (upload, download, list, delete), activity history, projects, states, labels, members, the current user, cycles, and modules. Works with Plane Cloud and self-hosted instances via an optional base URL. Attachment upload runs as an in-process operation that authorizes the stored file, follows Plane's signed-storage upload flow, and confirms the upload; download uses a raw binary request whose redirect to signed storage drops the API key on cross-origin hops. A dedicated, opt-in plane-errors extractor surfaces Plane and Django REST Framework error bodies without changing the fallback chain for other tools.
encodeURIComponent leaves . and .. intact, so an ID of .. collapsed the URL onto the parent resource (a work item delete could target its project). Every slug and ID segment now goes through validatePathSegment.
The block's params transform assigned undefined for canvas-only field ids, overwriting url, title, identifier, and parentId that an Agent passes under the tool's own param names. Remaps now apply only when the canvas field is set, and work items and labels share one parent ID field.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
6 issues found across 62 files
Confidence score: 3/5
add_work_items_to_cycle.tsonly reports assignments for the submitted issues, so the result can miss other work items already in the cycle. Fetch and include the cycle’s full work-item list.operations.tsleaves the pending attachment row and uploaded bytes behind when the PATCH is rejected. Discard the pending attachment on that failure path.work_item_shared.tsomits a supplied blank description from the PATCH, so callers can’t clear an existing description. Preserve the difference between an omitted description and a blank one.list_comments.tsandlist_projects.tssend no page size whenperPageis omitted, so Plane returns 20 items instead of the advertised default of 100. Apply the default in both tools or update the advertised defaults.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/sim/tools/plane/work_item_shared.ts">
<violation number="1" location="apps/sim/tools/plane/work_item_shared.ts:80">
P2: An explicitly blank description is omitted from the PATCH, so callers cannot clear an existing work-item description through this tool. Preserve the distinction between an omitted field and a supplied blank value, sending `null` for the latter.</violation>
</file>
<file name="apps/sim/tools/plane/list_projects.ts">
<violation number="1" location="apps/sim/tools/plane/list_projects.ts:38">
P3: The tool advertises a default page size of 100, but an omitted `perPage` is sent without `per_page`, so Plane returns its default of 20. Default `perPage` to 100 here or correct the advertised default.</violation>
</file>
<file name="apps/sim/tools/plane/add_work_items_to_cycle.ts">
<violation number="1" location="apps/sim/tools/plane/add_work_items_to_cycle.ts:61">
P2: This mapper only sees the assignments returned for the submitted `issues`, so it omits unrelated work items already in the cycle despite promising all current members. Fetch the cycle work-item list, including its pages, before returning the full list, or narrow the output contract.</violation>
</file>
<file name="apps/sim/lib/internal/plane/operations.ts">
<violation number="1" location="apps/sim/lib/internal/plane/operations.ts:264">
P2: The initial POST persists an attachment with `is_uploaded: false`; this rejected PATCH returns without calling `discardPendingAttachment`, leaving the pending row and uploaded bytes behind. Delete the asset before returning the confirmation error to avoid orphaned attachments.</violation>
</file>
<file name="apps/sim/tools/error-extractors.ts">
<violation number="1" location="apps/sim/tools/error-extractors.ts:135">
P2: Nested DRF validation errors are dropped because this filter accepts only direct strings, so invalid nested/list fields produce `Request failed with status 400` instead of the validation reason. Recursively flatten nested arrays and objects while preserving field paths.</violation>
</file>
<file name="apps/sim/tools/plane/list_comments.ts">
<violation number="1" location="apps/sim/tools/plane/list_comments.ts:34">
P2: When `perPage` is omitted, this helper leaves `per_page` out and Plane returns its 20-item default, despite the tool advertising a default of 100. Default `perPage` to 100 here so the first page matches the parameter contract.</violation>
</file>
|
- Discard the pending attachment when Plane rejects the upload confirmation. - Always send per_page so Cloud and self-hosted list defaults agree. - Keep nested Django REST Framework validation errors with field paths. - Document that <p></p> clears a work item description (Plane rejects an empty string as invalid HTML). - Regenerate the docs manifest.
|
@cubic-dev-ai review this PR |
@mzxchandra I have started the AI code review. It will take a few minutes to complete. |
Adds a clearFields param (a multi-select in the block) that empties the description, assignees, labels, parent, start and target dates, estimate point, or work item type. Clearing is explicit rather than inferred from an empty input, so a blank canvas field never wipes stored values.
|
@cubic-dev-ai review this PR |
@mzxchandra I have started the AI code review. It will take a few minutes to complete. |
The identifier, url, and title fields were canvas-only ids remapped in the params function, which kept the platform from applying its own precedence (user-configured values over agent values) and from hiding filled params from the agent schema. They now use the tool's param ids with per-operation conditions, and the remaps are gone.
|
@cubic-dev-ai review this PR |
@mzxchandra I have started the AI code review. It will take a few minutes to complete. |
Sharing the identifier subblock between Get Work Item by Identifier and Create Project carried a value typed for one operation into the other. Create Project now has its own projectIdentifier field, applied only when it is non-empty so an agent-supplied identifier is never cleared.
|
@cubic-dev-ai review this PR |
@mzxchandra I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 63 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Re-trigger cubic
Summary
Adds a Plane (plane.so) integration: a block with 32 operations over Plane's open-source v1 API, so it works with Plane Cloud and self-hosted instances.
Plane block and tools
ENG-42), list (cursor pagination, sorting), search, update, delete.X-API-Key), with an optional self-hosted base URL in advanced mode.File handling
lib/internal/plane), following the same pattern as Ashby, ClickUp and ServiceNow.assertToolFileAccess, reads it with a size cap, requests a signed storage upload from Plane, posts the bytes, and confirms the upload.configuredEndpointegress profile only when it is on the configured Plane origin (bundled MinIO); any other host usescontentFetch.responseType: 'binary'tool.Shared changes
tools/error-extractors.ts: adds aplane-errorsextractor for Plane's{ error }, DRF{ detail }, and field-validation error bodies.inFallbackChain: false), so tools without an explicit extractor resolve errors exactly as before.lib/workflows/subblocks/display.ts: a single uploaded file on a block card showed its object keys ("name, path +4"); it now shows the filename.Review fixes in this PR
validatePathSegment, so a..ID cannot collapse a request onto its parent resource.Webhook triggers are not included: Plane's open-source API has no endpoint to create webhooks.
Type of Change
Testing
bunx vitest runon the changed areas: 90 tests across the Plane tools, upload operation, block params, error extractors, subblock display,blocks.test.ts, and the internal-operation registry.bun run check:audits,bun run type-check, andcheck-block-registry.ts origin/stagingpass.Reviewers may want to focus on
lib/internal/plane/operations.ts(egress profile choice and the size-limit discard path) andtools/plane/utils.ts(response mappers).Checklist
🤖 Generated with Claude Code