stackcanvas 0.2.1 → 0.2.3

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # stackcanvas
2
2
 
3
- Live infrastructure canvas for [Claude Code](https://claude.com/claude-code).
3
+ Live infrastructure canvas for AI coding agents — any agent that speaks [MCP](https://modelcontextprotocol.io) ([Claude Code](https://claude.com/claude-code) is the CI-verified path).
4
4
  The agent writes and plans your Terraform — stackcanvas shows it as a living
5
5
  diagram. Drag new resources onto the canvas; the agent turns them into
6
6
  idiomatic HCL. No SaaS, no credentials leave your machine: everything runs on
@@ -23,7 +23,13 @@ localhost, reading your local state and plan.
23
23
  canvas highlights what will change. Only the agent executes Terraform —
24
24
  the canvas has no apply button by design.
25
25
 
26
- ## Install (Claude Code)
26
+ ## Install
27
+
28
+ stackcanvas is a standard MCP stdio server (`npx -y stackcanvas`) — point any
29
+ MCP-capable coding agent at it. The paths below, in order of how battle-tested
30
+ they are:
31
+
32
+ ### Claude Code (CI-verified)
27
33
 
28
34
  claude plugin marketplace add pshenok/stackcanvas
29
35
  claude plugin install stackcanvas@stackcanvas
@@ -42,12 +48,12 @@ Or without the plugin system:
42
48
  Then, inside a repo with Terraform, just ask: *open the stackcanvas canvas
43
49
  for this repo*.
44
50
 
45
- ## Other MCP clients
51
+ ### Other MCP clients
46
52
 
47
- stackcanvas is a standard [MCP](https://modelcontextprotocol.io) server, so
48
- any MCP-compatible client can run it. The snippets below are **reported to
49
- work as standard MCP servers; not yet CI-verified** only the Claude Code
50
- path above is exercised in CI.
53
+ The snippets below are **reported to work; not yet CI-verified** — only the
54
+ Claude Code path above is exercised in CI. Codex CLI and other MCP-capable
55
+ agents should work with the equivalent stdio config (`npx -y stackcanvas`)
56
+ untested, reports welcome in issues.
51
57
 
52
58
  **Cursor** (`.cursor/mcp.json`):
53
59
 
@@ -78,11 +84,14 @@ What's provider-specific is only the curation layer, shipped as **provider packs
78
84
 
79
85
  - a palette pack (`packages/ui/src/resource-palette.ts`) — curated drag-and-drop types
80
86
  - containment rules (`DEFAULT_CONTAINMENT_RULES` in `@stackcanvas/core`) — which
81
- resources render as visual containers (AWS VPC/subnet today)
87
+ resources render as visual containers (AWS VPC/subnet, GCP network/subnetwork,
88
+ Azure subnet, Cloudflare zone today)
82
89
  - icon patterns (`packages/ui/src/icons.tsx`)
83
90
 
84
- AWS ships first. Adding a GCP/Azure/other pack is pure data and makes a great
85
- first PR.
91
+ Four packs ship today: **AWS** (complete the reference pack) and **GCP /
92
+ Azure / Cloudflare starter packs** covering the common resource types per
93
+ provider. Rounding out a starter pack, or adding a new provider entirely, is
94
+ pure data and makes a great first PR.
86
95
 
87
96
  ## OpenTofu
88
97
 
@@ -103,7 +112,7 @@ to pin it — both take precedence over auto-detection.
103
112
 
104
113
  ## Demo
105
114
 
106
- `examples/demo` contains a small AWS config. Run `terraform init && terraform plan -out=tfplan && terraform show -json tfplan > .stackcanvas/plan.json` there and open the canvas to see create-highlighting. `plan` does not create or modify any resources — nothing is provisioned until `terraform apply` (note: the AWS provider still needs credentials and makes read-only API calls during plan).
115
+ `examples/local-demo` is a **zero-credential** playground: `terraform init && terraform apply -auto-approve` creates real state using only local providers (no cloud account touched), and the canvas renders it — including sensitive masking on the generated password. `examples/demo` contains a small AWS config. Run `terraform init && terraform plan -out=tfplan && terraform show -json tfplan > .stackcanvas/plan.json` there and open the canvas to see create-highlighting. `plan` does not create or modify any resources — nothing is provisioned until `terraform apply` (note: the AWS provider still needs credentials and makes read-only API calls during plan).
107
116
 
108
117
  ## Telemetry
109
118
 
package/dist/cli.js CHANGED
@@ -40,7 +40,15 @@ function deriveEdges(nodes) {
40
40
  }
41
41
  var DEFAULT_CONTAINMENT_RULES = [
42
42
  { containerType: "aws_vpc", memberAttr: "vpc_id", kind: "vpc" },
43
- { containerType: "aws_subnet", memberAttr: "subnet_id", kind: "subnet" }
43
+ { containerType: "aws_subnet", memberAttr: "subnet_id", kind: "subnet" },
44
+ // GCP networks/subnetworks are referenced by `self_link`, not `id`.
45
+ { containerType: "google_compute_network", memberAttr: "network", kind: "vpc", containerIdAttr: "self_link" },
46
+ { containerType: "google_compute_subnetwork", memberAttr: "subnetwork", kind: "subnet", containerIdAttr: "self_link" },
47
+ { containerType: "azurerm_subnet", memberAttr: "subnet_id", kind: "subnet" },
48
+ // Cloudflare zones aren't a network container, but they group the
49
+ // resources scoped to them the same way a VPC groups its members — reuse
50
+ // the 'vpc' kind rather than introducing a one-off styling kind.
51
+ { containerType: "cloudflare_zone", memberAttr: "zone_id", kind: "vpc" }
44
52
  ];
45
53
  function deriveContainment(g, rules = DEFAULT_CONTAINMENT_RULES) {
46
54
  const groups = [...g.groups];
@@ -48,7 +56,7 @@ function deriveContainment(g, rules = DEFAULT_CONTAINMENT_RULES) {
48
56
  for (const rule of rules) {
49
57
  const groupByPhysicalId = /* @__PURE__ */ new Map();
50
58
  for (const n of nodes.filter((n2) => n2.type === rule.containerType)) {
51
- const pid = n.attributes["id"];
59
+ const pid = n.attributes[rule.containerIdAttr ?? "id"];
52
60
  if (typeof pid !== "string") continue;
53
61
  const gid = `${rule.kind}:${n.id}`;
54
62
  groups.push({ id: gid, label: n.name, kind: rule.kind, parent: n.group });
@@ -926,7 +934,7 @@ function openBrowser(url) {
926
934
  }
927
935
 
928
936
  // src/version.ts
929
- var VERSION = "0.2.1";
937
+ var VERSION = "0.2.3";
930
938
 
931
939
  // src/server.ts
932
940
  function looksLikeTerraformRoot(dir) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackcanvas",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {
@@ -29,7 +29,7 @@
29
29
  "@types/node": "^22.0.0",
30
30
  "tsup": "^8.0.0"
31
31
  },
32
- "description": "Live infrastructure canvas for Claude Code: see what your AI agent is about to do to your Terraform \u2014 and approve it \u2014 before it happens. Local-first, credentials never leave your machine.",
32
+ "description": "Live infrastructure canvas for AI coding agents (MCP): see what your agent is about to do to your Terraform \u2014 and approve it \u2014 before it happens. Local-first, credentials never leave your machine.",
33
33
  "license": "MIT",
34
34
  "repository": {
35
35
  "type": "git",