@passioncode-ai/passioncode 0.2.14 → 0.2.16
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/CHANGELOG.md +20 -0
- package/family.json +2 -2
- package/package.json +1 -1
- package/payload/.claude-plugin/marketplace.json +3 -3
- package/payload/manifest.json +12 -12
- package/payload/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/payload/plugins/fabric-agent-adapter/hooks/hooks.json +3 -2
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +3 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +6 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/dashboard_kit.py +13 -12
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +5 -4
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/references/session-hooks.md +9 -3
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session.py +99 -35
- package/payload/plugins/observatory-log/.claude-plugin/plugin.json +1 -1
- package/payload/plugins/observatory-log/hooks/ask-why.py +141 -36
- package/payload/plugins/observatory-log/hooks/hooks.json +13 -1
- package/payload/plugins/observatory-log/hooks/prompt-why.py +180 -0
- package/payload/plugins/observatory-log/hooks/record-turn.sh +31 -15
- package/payload/plugins/observatory-log/hooks/session-start.sh +10 -4
- package/payload/plugins/observatory-log/skills/explaining-changes/SKILL.md +16 -5
- package/payload/plugins/observatory-log/skills/handling-secrets/SKILL.md +83 -13
- package/payload/plugins/observatory-log/skills/tracking-resources/SKILL.md +1 -1
- package/payload/plugins/passioncode/.claude-plugin/plugin.json +1 -1
|
@@ -10,7 +10,7 @@ description: >-
|
|
|
10
10
|
provider permissions or choosing a project's authentication architecture.
|
|
11
11
|
license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
12
12
|
metadata:
|
|
13
|
-
version: "0.
|
|
13
|
+
version: "0.26.0"
|
|
14
14
|
compatibility: >-
|
|
15
15
|
Requires an initialized full Project Observatory installation, Python 3.11+
|
|
16
16
|
and local shell access on macOS or Linux. Provider operations additionally
|
|
@@ -30,7 +30,7 @@ names. Never ask the user to paste a credential into the conversation.
|
|
|
30
30
|
2. Select the user's initialized `OBSERVATORY_HOME`. Run
|
|
31
31
|
`project-observatory full doctor`. A missing workspace
|
|
32
32
|
needs the documented onboarding before secret operations.
|
|
33
|
-
3. Run `"$OBSERVATORY_PYTHON" "$OBSERVATORY_ROOT/tools/skill_check.py" handling-secrets 0.
|
|
33
|
+
3. Run `"$OBSERVATORY_PYTHON" "$OBSERVATORY_ROOT/tools/skill_check.py" handling-secrets 0.26.0`
|
|
34
34
|
(`full agent install` records that interpreter; the stock macOS `python3` is too old).
|
|
35
35
|
If stale, read the installed skill once and follow its compatible commands.
|
|
36
36
|
Do not turn an unavailable version check into a retry loop.
|
|
@@ -53,8 +53,8 @@ for it. A name or note shaped like a credential is refused, never stored.
|
|
|
53
53
|
| List slots | `vault.py list PROJECT ENV` |
|
|
54
54
|
| Run a command using a slot | `use_secret.py run [--env ENV] [--vault-only] PROJECT NAME -- COMMAND ARGUMENTS` (flags before PROJECT) |
|
|
55
55
|
| Receive a value from another local command | `use_secret.py pipe NAME -- COMMAND ARGUMENTS` |
|
|
56
|
-
| Bind a slot to the one MCP server allowed to receive it as a header (the operator, once) | `vault.py bind PROJECT ENV NAME --header-for https://HOST[:PORT]` (a bare host means https); `--clear` removes it; both are journalled |
|
|
57
|
-
| Give an HTTP MCP server its bearer through
|
|
56
|
+
| Bind a slot to the one MCP server allowed to receive it as a header (the operator, once) | `vault.py bind PROJECT ENV NAME --header-for https://HOST[:PORT]` (a bare host means https), or `http://127.0.0.1:PORT` / `http://[::1]:PORT` for a loopback server (`localhost` is refused); `--clear` removes it; both are journalled |
|
|
57
|
+
| Give an HTTP MCP server its bearer through the client's header helper | `use_secret.py header [--env ENV] [--name Authorization] [--scheme Bearer] PROJECT NAME`, written into Claude Code's `headersHelper` entry; for Codex's `http_headers_helper` add `--server-url URL`, since Codex exports no server URL. Never run by hand |
|
|
58
58
|
| Populate a project's ignored environment file | `vault.py inject PROJECT ENV DIRECTORY` |
|
|
59
59
|
| Record an exposure | `vault.py leak PROJECT ENV NAME --where "location and evidence, no value"` |
|
|
60
60
|
| Replace a stored value | `vault.py rotate PROJECT ENV NAME`, replacement on stdin |
|
|
@@ -80,14 +80,16 @@ not a sandbox: a child process can encode a value, transmit it, or write it to
|
|
|
80
80
|
another file. Only run the command authorized by the task. Do not claim this
|
|
81
81
|
filter prevents every leak.
|
|
82
82
|
|
|
83
|
-
**The header door prints a value, so it serves only
|
|
83
|
+
**The header door prints a value, so it serves only a client's header helper.** `use_secret.py
|
|
84
84
|
header` writes one JSON object (`{"Authorization": "Bearer …"}`) for a
|
|
85
85
|
`headersHelper`, which Claude Code merges into the MCP request rather than the
|
|
86
86
|
conversation. It reads the vault only (never an env file or the environment), and
|
|
87
|
-
refuses unless stdout is a program, `CLAUDE_CODE_MCP_SERVER_URL`
|
|
88
|
-
host and port the slot is bound to,
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
refuses unless stdout is a program, `CLAUDE_CODE_MCP_SERVER_URL` (or `--server-url`,
|
|
88
|
+
for a client that exports none) names the scheme, host and port the slot is bound to,
|
|
89
|
+
and the value has no control character; two URLs that disagree are refused
|
|
90
|
+
(`url-conflict`). Never run it yourself, pipe it, or set `CLAUDE_CODE_MCP_SERVER_URL` or
|
|
91
|
+
`--server-url` to make it answer: that prints the value into your transcript. Each call
|
|
92
|
+
is audited, with the caller it claimed. Binding is the
|
|
91
93
|
operator's decision; ask for it, do not run `bind` to make a call succeed.
|
|
92
94
|
|
|
93
95
|
**Stdin carries one thing.** Never pipe a secret into `python3 -`, `node -` or
|
|
@@ -126,12 +128,77 @@ exposure and record it with `vault.py leak`. The design is
|
|
|
126
128
|
|
|
127
129
|
## Provider integrations
|
|
128
130
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
**A provider's MCP tool can be the leak.** Some tools return a credential in their
|
|
132
|
+
answer by design, whatever you asked them for: DigitalOcean's `db-cluster-list`,
|
|
133
|
+
`db-cluster-get`, `db-cluster-*-user`, `docr-docker-credentials`, `doks-get-kubeconfig`,
|
|
134
|
+
`spaces-key-create`. The transcript keeps a tool result whole; it cannot be redacted
|
|
135
|
+
afterwards: a `db-cluster-list` call asked for names can return every cluster's
|
|
136
|
+
passwords. Do not call such a tool; get names from the provider CLI with an
|
|
137
|
+
explicit `--format`, and credentials through the door below. Record any sighting with
|
|
138
|
+
`vault.py leak` and rotate.
|
|
139
|
+
|
|
140
|
+
DigitalOcean managed databases go through `digitalocean.py` in the operator's `doctl`
|
|
141
|
+
context. `db list` and `db consumers CLUSTER` print metadata only; consumer discovery covers
|
|
142
|
+
App Platform bindings, not every possible consumer. `db credential CLUSTER USER --db NAME
|
|
143
|
+
--to vault:PROJECT/ENV/NAME` puts the connection URL in the vault on stdin.
|
|
144
|
+
|
|
145
|
+
DigitalOcean rotation verifies every selected `--spec-env APP:KEY` literal before any reset.
|
|
146
|
+
Its name is not evidence: a plain value must equal the selected database user's current
|
|
147
|
+
provider password, or be a database URL with that password, user, engine and the provider's
|
|
148
|
+
connection host/port. A `${…}` binding is never rewritten, at any level; `--db` must be one of
|
|
149
|
+
the cluster's databases, and `db credential` checks `--db` the same way before it reads a
|
|
150
|
+
password (a cluster the provider lists no databases for, and redis/valkey, refuse `--db` with
|
|
151
|
+
their own reason). Opaque encrypted values and unverified pool endpoints are refused;
|
|
152
|
+
migrate those consumers to App Platform database bindings before rotation. No command in
|
|
153
|
+
this flow prints the current password. Only the named consumers are moved, with downtime
|
|
154
|
+
between reset and ACTIVE; ACTIVE is not application health verification.
|
|
155
|
+
|
|
156
|
+
The door writes an owner-only receipt under `store/digitalocean-rotations/` before reset,
|
|
157
|
+
initially `reset: unknown`. A lost or malformed response, timeout or nonzero CLI result can
|
|
158
|
+
follow a committed reset: exit 5 means **unknown**, not “nothing changed”. Never repeat
|
|
159
|
+
`db rotate` to recover it. Use `db credential` to deliver the current value into the selected
|
|
160
|
+
vault slot, then reconcile each consumer without another reset. Exit 1 is a refusal before
|
|
161
|
+
reset; after an attempt, 2 means deployment unconfirmed, 3 vault delivery failed, 4 an app
|
|
162
|
+
update/redeploy or temporary spec cleanup failed, and 6 receipt update failed. The largest
|
|
163
|
+
code wins. Independent consumers continue after a confirmed reset despite another consumer's
|
|
164
|
+
failure. Provider/vault error bodies are withheld. A crash or failed final receipt write
|
|
165
|
+
leaves the earlier uncertain receipt; there is no automatic reconciliation, retry or claim
|
|
166
|
+
of a transaction across provider and vault. A failed temporary-file cleanup may leave its
|
|
167
|
+
owner-only spec file and is reported for local recovery.
|
|
168
|
+
|
|
169
|
+
Reset, app updates and redeploys each make one attempt; only read calls retry.
|
|
170
|
+
A lost/nonzero mutation response leaves that consumer `unknown`, even if the provider
|
|
171
|
+
already applied it. The receipt distinguishes this from `not_started` for a local
|
|
172
|
+
pre-call failure. Read current spec and deployment state before any retry; a blind
|
|
173
|
+
redeploy is not recovery for a literal. Independent peers still continue. Deployment
|
|
174
|
+
confirmation accepts a validated phase equal to `ACTIVE`, never a suffix or arbitrary
|
|
175
|
+
provider text; malformed metadata remains unconfirmed and its body is not printed.
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
Cloudflare, OpenRouter and Heroku have separate tools, `cloudflare.py`,
|
|
179
|
+
`openrouter.py` and `heroku.py`. Check their installed `--help` and non-secret inventory first.
|
|
180
|
+
A Heroku credential is `heroku.py issue --preset read|deploy|identity --vault
|
|
181
|
+
<project>/<env>/<NAME> [--team <team>] [--app <app>]`: an OAuth authorization with that
|
|
182
|
+
scope only, proved and delivered on stdin. Heroku cannot narrow one to a team or an app,
|
|
183
|
+
so prefer `read` and name the app. Team and account membership (`heroku.py member`,
|
|
184
|
+
`cloudflare.py member`) is a printed plan until `--apply`; apply only a change the task asked for.
|
|
131
185
|
They require an explicitly configured integration and the user's own admin or
|
|
132
186
|
provisioning credential. They do not make a new user inherit the author's
|
|
133
187
|
accounts, budgets or tokens. Limit issuance and revocation to the task's scope.
|
|
134
188
|
|
|
189
|
+
A project's own OpenRouter keys come from its spend policy: `openrouter.py
|
|
190
|
+
issue-for-policy --policy FILE [--dry-run]` keeps their ceilings together within
|
|
191
|
+
the project limit and exits 1 with `OVER LIMIT by $X now ($A against the $L
|
|
192
|
+
limit); it ends after: …` when they are not. `rotate` is the one window past the
|
|
193
|
+
limit: both keys are live while it runs, and until the J-3 change a rotate that
|
|
194
|
+
fails can leave the successor `NAME-next` untracked or the predecessor uncounted —
|
|
195
|
+
delete at the provider the one the slot does not hold, then run
|
|
196
|
+
`issue-for-policy`. A pending row with no hash on an account past the listing is
|
|
197
|
+
cleared with `revoke NAME --forget-pending --reason "…"` once its key is gone. The door must
|
|
198
|
+
record the reason as a pre-action attestation before clearing the row; an
|
|
199
|
+
unwritable journal refuses the change. This is an operator assertion, not
|
|
200
|
+
provider verification. A separate completion event follows the ledger write.
|
|
201
|
+
|
|
135
202
|
A project that must edit DNS in one zone (a custom domain, a CNAME to its host)
|
|
136
203
|
gets `cloudflare.py issue --preset dns-edit --zone <zone> --vault <project>/<env>/<NAME>`:
|
|
137
204
|
Zone Read and DNS Write on that zone only, verified against its records and
|
|
@@ -171,8 +238,11 @@ gets `cloudflare.py issue --preset email-send --account <slug> --vault
|
|
|
171
238
|
group exists at account level only), verified by listing its suppressions.
|
|
172
239
|
Adding an Email Routing rule in one zone — one address to a Worker — is
|
|
173
240
|
`--preset email-routing --zone <zone>`, and deploying that Worker with its KV
|
|
174
|
-
namespace is `--preset workers-edit --account <slug
|
|
175
|
-
|
|
241
|
+
namespace is `--preset workers-edit --account <slug>`; putting a Worker in front of
|
|
242
|
+
a hostname (`example.com/*`) is the zone right `--preset workers-routes --zone <zone>`;
|
|
243
|
+
sending one hostname to another at the edge (a Single Redirect, `www.` to the apex) is
|
|
244
|
+
the zone right `--preset redirect-rules --zone <zone>`.
|
|
245
|
+
Each is its own token in its own slot. When a preset's groups are unknown, `cloudflare.py groups
|
|
176
246
|
--account <slug> --match "<words>"` lists the catalogue's names and levels,
|
|
177
247
|
read-only and without ids.
|
|
178
248
|
|
|
@@ -15,7 +15,7 @@ description: >-
|
|
|
15
15
|
the repository.
|
|
16
16
|
license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
17
17
|
metadata:
|
|
18
|
-
version: "0.
|
|
18
|
+
version: "0.26.0"
|
|
19
19
|
compatibility: >-
|
|
20
20
|
Requires a full Project Observatory installation with organizations.json
|
|
21
21
|
configured; the observatory MCP server or its local CLI. Creating the resource
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "passioncode",
|
|
4
4
|
"displayName": "PassionCode.ai",
|
|
5
|
-
"version": "0.2.
|
|
5
|
+
"version": "0.2.16",
|
|
6
6
|
"description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check at session start that keeps the PassionCode.ai skill set current.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "PassionCode.ai",
|