@drawbridge/drawbridge-agents 0.1.8 → 0.1.10
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.
|
@@ -35,6 +35,17 @@
|
|
|
35
35
|
]
|
|
36
36
|
},
|
|
37
37
|
"hooks": {
|
|
38
|
+
"PreToolUse": [
|
|
39
|
+
{
|
|
40
|
+
"matcher": "Write|Edit|MultiEdit|NotebookEdit",
|
|
41
|
+
"hooks": [
|
|
42
|
+
{
|
|
43
|
+
"type": "command",
|
|
44
|
+
"command": "node ./node_modules/@drawbridge/drawbridge-agents/hooks/guard-superpowers-docs.js"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
],
|
|
38
49
|
"Stop": [
|
|
39
50
|
{
|
|
40
51
|
"matcher": "",
|
|
@@ -20,7 +20,14 @@ knowledge graph, and the Asana handoff so nothing drifts at ship time.
|
|
|
20
20
|
flag the drift explicitly. See `conventions/docs-linkage.md`.
|
|
21
21
|
3. **Confirm doc anchors resolve.** Run `npx drawbridge-agents-check-docs`; fix any unresolved
|
|
22
22
|
`@story` / `@doc` tag. Add an anchor to newly-added feature code where it maps to a story.
|
|
23
|
-
4. **Refresh the graph
|
|
23
|
+
4. **Refresh the knowledge graph — always, on every feature wrap** (not conditional on whether
|
|
24
|
+
structure "obviously" changed). The canonical graph is the committed snapshot in
|
|
25
|
+
`drawbridge-docs`, shared by the whole team; skipping it lets the shared graph drift. From the
|
|
26
|
+
`drawbridge-docs` repo: `npx drawbridge-agents-graph` (rebuilds `knowledge/graphs/global.json`
|
|
27
|
+
from every repo), then `git add knowledge/graphs/global.json && git commit -m "chore: refresh
|
|
28
|
+
knowledge graph (<feature>)" && git push origin main`. If it reports "graphify runtime not
|
|
29
|
+
found", the `uv`/`graphify` binaries are in `~/.local/bin` — `export PATH="$HOME/.local/bin:$PATH"`
|
|
30
|
+
and retry (do NOT run `graphify install`; it rewrites `CLAUDE.md`).
|
|
24
31
|
5. **Hand off the task.** Invoke `drawbridge-asana-ship-handoff` with the Asana task to reassign
|
|
25
32
|
to the last commenter, post the change summary + retest steps, and set the due date.
|
|
26
33
|
|
|
@@ -9,6 +9,11 @@ skill) so it stops living only in tribal memory.
|
|
|
9
9
|
|
|
10
10
|
- `OAUTH_TOKEN_HMAC_KEY` must be identical in **drawbridge-api** and **drawbridge-sync** — both
|
|
11
11
|
`assertEnv` it at boot. A mismatch silently breaks realtime token verification.
|
|
12
|
+
- reCAPTCHA on auth is a key pair: `GOOGLE_RECAPTCHA_SECRET` (**drawbridge-api**) + `NEXT_PUBLIC_GOOGLE_RECAPTCHA_KEY`
|
|
13
|
+
(**drawbridge-app-web**), both `assertEnv`'d at boot. The api verifies the v3 token app-web's
|
|
14
|
+
`/auth` forms attach and enforces it **unconditionally** on `/oauth/{signup,signin}/request`
|
|
15
|
+
(fails closed). Deploy order matters: ship app-web **before** api, or the api blocks every
|
|
16
|
+
signin that arrives without a token. See `drawbridge-docs/user-stories/03-auth`.
|
|
12
17
|
|
|
13
18
|
## Sync owns reactive side effects
|
|
14
19
|
|
|
@@ -29,6 +34,11 @@ skill) so it stops living only in tribal memory.
|
|
|
29
34
|
units unbillable.
|
|
30
35
|
- Every `$inc` on a `totals.*` counter needs a matching entry in `drawbridge-sync/lib/totals.js`
|
|
31
36
|
`SOURCES` — that map is the only drift backstop.
|
|
37
|
+
- The `invoice` collection's **unique partial index on `stripeInvoiceId`** (drawbridge-api
|
|
38
|
+
`schema/invoice.js`) and sync's `upsertInvoice` E11000 catch (`lib/buffer.js`) are one contract:
|
|
39
|
+
sync upserts the same invoice from three concurrent webhooks (finalized/payment_succeeded/voided)
|
|
40
|
+
and relies on the index to reject the losing insert so the catch can redo it as an update. Drop
|
|
41
|
+
the index → silent duplicate invoice rows; remove the catch → concurrent events throw + retry.
|
|
32
42
|
|
|
33
43
|
## `@drawbridge/*` package coordination
|
|
34
44
|
|
|
@@ -13,6 +13,11 @@ This is the **only** allowed home for these working docs. Rules:
|
|
|
13
13
|
- Do **not** create or keep superpowers plans/specs (or `docs/superpowers/`, `docs/plans/`)
|
|
14
14
|
inside any other repo. When you finalize a plan or spec, write it under
|
|
15
15
|
`../drawbridge-docs/superpowers/{plans,specs}/`, not the repo you're working in.
|
|
16
|
+
- ⚠️ The superpowers **brainstorming** and **writing-plans** skills hardcode a save path of
|
|
17
|
+
`docs/superpowers/{specs,plans}/YYYY-MM-DD-<slug>.md` in the current repo (and tell you to
|
|
18
|
+
commit it). **Override that** — redirect the path to `../drawbridge-docs/superpowers/…`. A
|
|
19
|
+
`PreToolUse` guard hook (`hooks/guard-superpowers-docs.js`) denies writes to `docs/superpowers/`
|
|
20
|
+
and `docs/plans/` outside drawbridge-docs, so following the skill's default path will be blocked.
|
|
16
21
|
- When plan mode or a superpowers skill produces a plan/spec, the finalized document goes into
|
|
17
22
|
drawbridge-docs — regardless of which repo the work targets. Note the target repo in the doc.
|
|
18
23
|
- `.superpowers/` (brainstorm scratch — server state, HTML mockups) is ephemeral. **Never commit
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// PreToolUse hook (Write/Edit/MultiEdit/NotebookEdit): superpowers plans & specs must live in
|
|
3
|
+
// drawbridge-docs, never in a working repo. The superpowers brainstorming / writing-plans skills
|
|
4
|
+
// hardcode a `docs/superpowers/{specs,plans}/…` save path (and tell the agent to commit it),
|
|
5
|
+
// which silently overrides the passive conventions/superpowers-docs.md rule at write time. A
|
|
6
|
+
// convention can't out-argue a skill's explicit step, so this enforces it: deny the write and
|
|
7
|
+
// tell the agent where it belongs. See conventions/superpowers-docs.md.
|
|
8
|
+
const fs = require('fs')
|
|
9
|
+
const path = require('path')
|
|
10
|
+
|
|
11
|
+
const readStdin = () => {
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(fs.readFileSync(0, 'utf8') || '{}')
|
|
14
|
+
} catch (error) {
|
|
15
|
+
return {}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const deny = (reason) => {
|
|
20
|
+
process.stdout.write(JSON.stringify({
|
|
21
|
+
hookSpecificOutput: {
|
|
22
|
+
hookEventName: 'PreToolUse',
|
|
23
|
+
permissionDecision: 'deny',
|
|
24
|
+
permissionDecisionReason: reason
|
|
25
|
+
}
|
|
26
|
+
}))
|
|
27
|
+
process.exit(0)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Path segments that are never allowed outside drawbridge-docs. These are the superpowers-skill
|
|
31
|
+
// defaults (`docs/superpowers/`) plus the sibling the convention also forbids (`docs/plans/`).
|
|
32
|
+
const FORBIDDEN = [ 'docs/superpowers', 'docs/plans' ]
|
|
33
|
+
|
|
34
|
+
const run = () => {
|
|
35
|
+
const input = readStdin()
|
|
36
|
+
|
|
37
|
+
const tool = input.tool_name || ''
|
|
38
|
+
if (!/^(Write|Edit|MultiEdit|NotebookEdit)$/.test(tool)) process.exit(0)
|
|
39
|
+
|
|
40
|
+
const toolInput = input.tool_input || {}
|
|
41
|
+
const filePath = toolInput.file_path || toolInput.notebook_path
|
|
42
|
+
if (!filePath) process.exit(0)
|
|
43
|
+
|
|
44
|
+
// Normalise to forward slashes so the match is OS-independent.
|
|
45
|
+
const resolved = path.resolve(filePath).split(path.sep).join('/')
|
|
46
|
+
|
|
47
|
+
// drawbridge-docs is the canonical home — anything there is fine.
|
|
48
|
+
if (resolved.split('/').includes('drawbridge-docs')) process.exit(0)
|
|
49
|
+
|
|
50
|
+
const hit = FORBIDDEN.find((seg) => resolved.includes('/' + seg + '/') || resolved.endsWith('/' + seg))
|
|
51
|
+
if (!hit) process.exit(0)
|
|
52
|
+
|
|
53
|
+
deny(
|
|
54
|
+
'Blocked: superpowers plans/specs must live in drawbridge-docs, not in this repo (`' + hit + '/`). ' +
|
|
55
|
+
'The brainstorming / writing-plans skills instruct you to save here and commit — override that path. ' +
|
|
56
|
+
'Write to `../drawbridge-docs/superpowers/{plans,specs}/YYYY-MM-DD-<slug>.md` instead, and note the ' +
|
|
57
|
+
'target repo inside the doc. See conventions/superpowers-docs.md.'
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
run()
|
|
63
|
+
} catch (error) {
|
|
64
|
+
// Never break a user's turn because of a hook bug — fail open.
|
|
65
|
+
process.exit(0)
|
|
66
|
+
}
|
package/package.json
CHANGED