@drawbridge/drawbridge-agents 0.1.9 → 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** if the change altered cross-repo structure: `npx drawbridge-agents-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
 
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawbridge/drawbridge-agents",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Shared agent-instruction content (rules, code style, conventions) for the drawbridge-* monorepo.",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {