@drawbridge/drawbridge-agents 0.1.87 → 0.1.89

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.
@@ -14,6 +14,7 @@
14
14
  "mcp__*"
15
15
  ],
16
16
  "additionalDirectories": [
17
+ "../.worktrees",
17
18
  "../drawbridge-agents",
18
19
  "../drawbridge-api",
19
20
  "../drawbridge-app-web",
@@ -9,7 +9,7 @@ One Asana release task is the unit. Its id names everything: the `feature/<id>`
9
9
 
10
10
  The ten lines below are the release, as Darren confirmed them on 2026-10-22. The skill owns lines 1 to 5 and 10 and runs them without anyone present once line 2 has its yes. A developer owns 6 and 9. A QA person owns 7 and 8. The skill never does a developer's or a tester's line for them.
11
11
 
12
- 1. A person gives the skill the release task link. The skill checks `gh auth status`.
12
+ 1. A person gives the skill the release task link. The skill runs the doctor, then asks two things before reading anything: who reviews and who tests, each with the dev organization they sign in to.
13
13
  2. The skill reads the task and subtasks, writes the stories, sends ONE numbered list and waits for the yes. The yes starts an unattended run.
14
14
  3. Task → Building: branches, the release document, the band.
15
15
  4. The skill builds on the release branches against the Local database, with the QA agent run locally. Nobody is asked anything; whatever needs a person is parked.
@@ -24,6 +24,13 @@ The ten lines below are the release, as Darren confirmed them on 2026-10-22. The
24
24
 
25
25
  Read the release task and every subtask through `drawbridge-tests/lib/asana.js` (`api( 'GET', '/tasks/<id>?opt_fields=name,notes,memberships.section.name' )`, then `/tasks/<id>/subtasks`). Subtasks live in "DrawBridge - Application" (or the Backlog) and stay there. A release is named with one ice cream, in alphabetical order across releases, nothing else: "Almond", "Butterscotch", "Cherry", "Dulce", "Espresso" exist (Darren, 2026-10-22: no numbers, no weeks, no dates; the alphabet carries the order). The date is the task's due field. If asked to create one, take the next letter after the latest in the Releases project. Run `npx drawbridge-agents-release-doctor` from the api checkout first: it checks git, `gh auth status`, `op` on the beta channel, the api's two env files, `scripts/op.sh`, the npm registry and both clusters, and prints one numbered list of what is missing with the fix for each. Stop on any required miss and hand that list to the person. Other developers start releases from their own machines, so nothing is assumed.
26
26
 
27
+ **Then, before the stories, ONE numbered list of two questions**, so the people are known before any work starts and nobody waits for the review to finish (Darren, 2026-10-23: "the first questions asked right away is who is the development reviewer and who is the qa specialist"; "Then any task questions can come after the initial review"):
28
+
29
+ 1. Who on the development team reviews this release: their GitHub username (for the pull requests), their Asana name (for the task), and the dev organization they sign in to (name or id).
30
+ 2. Who tests it: the QA person's Asana name and the dev organization they can open (name or id). Every link in the "Test on dev (QA)" lists is built on THAT organization, never on the e2e organization or one of Darren's, because a tester sent to an organization they cannot open loses the whole session (Jaime, 2026-10-23: a link went to one of Darren's organizations).
31
+
32
+ Wait for both answers. Never guess either name or organization. The developer still assigns the QA person at line 6; the name asked here is who that will be.
33
+
27
34
  ## Line 2: the one list
28
35
 
29
36
  **The graph first, grep last.** `git -C ../drawbridge-docs pull` brings the committed knowledge graph (`drawbridge-docs/knowledge/graphs/global.json`, rebuilt at the end of every release); it already knows the family, so a release does not rediscover it by searching sixteen repos from scratch (Darren, 2026-10-22: "make sure we are leveraging the knowledge graphs and not always searching each time we start from develop. That is the point of having that feature"). For every subtask, before any grep: `graphify query "<the subtask in words>"`, then `graphify explain <symbol>` and `graphify affected <symbol>` for the handlers, fields or components it names, all with `--graph ../drawbridge-docs/knowledge/graphs/global.json`. The answers give the repos and files the subtask touches and the cross-repo contracts in play; that list is the Scope table at line 3. Grep only inside a file the graph named, to read it, never across repos to find it.
@@ -31,7 +38,7 @@ Read the release task and every subtask through `drawbridge-tests/lib/asana.js`
31
38
  **Every subtask has a story; no exceptions.** For every subtask, find the existing story or write one (`drawbridge-feature` step 1), from what the graph showed: a bug fix gets the story whose scenario it restores, a new behaviour gets a new story, an internal change gets the story of the behaviour it must keep working. A subtask that ends line 2 with no story is a stop condition, not a gap to fill later: the QA person tests from the story, so a subtask without one has nothing to test against (Darren, 2026-10-22: "all subtasks in a release create or link to an existing story, so there is context about what needs to be tested"). Then ONE numbered list to the person who started the release, each item three plain sentences (`conventions/rules.md` rule 7) plus a fourth, the recommendation, holding:
32
39
 
33
40
  - every unknown from every story, **each with the fix you recommend**: "I recommend <the option>, because <the reason>." The recommendation comes from having read the code the subtask touches (the files the graph named, opened whole) and from what apps like Drawbridge commonly do for the same thing, and it picks the best experience for the person using the product. That goes for every aspect of the platform, not only screens: a feature, a price or plan rule, a design, a message, a default, a limit. A question without a recommendation reads as a question nobody has thought about (Darren, 2026-10-22: "recommend the fix as well. This way I know you've reviewed the code and considered the best approach. We should always be looking at what is the best user experience as well as what is common for apps like ours"). When the recommendation needs a fact you do not have, say which, and still name the option you would take;
34
- - **who on the development team takes the pull requests**: their GitHub username (for the pull requests) and their Asana name (for the task). Asked now so nobody needs to be present between lines 3 and 5. Never guess a reviewer;
41
+ - nothing about who reviews or tests: both were answered at line 1;
35
42
  - **a package publish, if any subtask names `@drawbridge/components` or `@drawbridge/drawbridge-utils`**, as a statement, not a question: this release publishes a package; the developer named above publishes it. The package is built first and gets its own pull request to the package's `main`; the end list (line 5) hands the developer the merge and the publish command; the skill then bumps the pin in every consumer, and the app pull requests open after that, once the publish is done. Line 4 step 2 is the exact sequence.
36
43
 
37
44
  **Publishing is settled; never ask about it.** The developer publishes every package, from the package checkout on `main`, with `git pull && npm run build` (tsup, the tests, `npm publish`, their one-time password). Agents hold no npm token and never will (an agent's `npm publish` answers 401); the automation token (queue task 1218041740718540, in Butterscotch) will move the publish into CI, and until then it is the developer's hand. So the skill never asks who publishes, whether to publish, whether it may publish, or how: it writes the one command into the end list as an instruction to the developer and waits for `npm view` to show the version (Darren, 2026-10-22: "I get a lot of questions in the release about npm publishing etc, lets make sure that it's clear that the developers do the publishing so that these go away").
@@ -45,7 +52,7 @@ A run does not stop while there is code left to write. Whatever the hour, the ag
45
52
  1. **No question, no comment, no request.** The line 3 writes to Asana (section moves, the story on each subtask) happen right after the yes and ask nothing; after them, no question to the person, no Asana comment, no publish ask, no access request: not for a missing credential, not for an MCP server that is not connected, not for a tool a hook or a permission refuses. The rule "ask before writing a line" (`conventions/rules.md` rule 1) was satisfied at line 2; a question born mid-build is parked, not asked.
46
53
  2. **Park it, build the rest.** Anything that needs a person is written into the release doc's Parked section (`releases/<id>.md`, committed on the docs branch so it survives a long run): the subtask, what exactly is needed, in the three-sentence shape of rule 7, ready to paste into the end list. Then build every subtask that does not depend on it.
47
54
  3. **Be optimistic about access.** When something is missing (a token, a connected service, a tool), write the code as if it will be granted, test what can be tested without it, and park the one step that cannot run (Darren: "lets be optimistic that access can be granted so work isn't held up"). The parked line names what the grant unblocks, so the close-out finishes that step and nothing else.
48
- 4. **Permissions never prompt.** The shared `.claude/settings.json` the agents package mirrors into every repo allows every Bash command, file writes, web fetches and every MCP tool; the hooks that refuse a step (read-before-write, drift, QA gate) return an error the skill handles. The release doctor confirms the mirrored settings file is present at line 1, so a machine that would prompt fails before the run, not in the middle of it.
55
+ 4. **Permissions never prompt.** The shared `.claude/settings.json` the agents package mirrors into every repo allows every Bash command, file writes, web fetches and every MCP tool, and names `../.worktrees` as an allowed directory, because a Write or Edit outside the allowed directories prompts the person whatever the allow list says (that is what stopped Butterscotch mid-build on 2026-10-22: its build agents edited files in the worktrees). Build agents dispatched with the Agent tool inherit the same settings, so they never prompt either; the hooks that refuse a step (read-before-write, drift, QA gate) return an error the skill handles. The release doctor confirms the mirrored settings file is present at line 1, so a machine that would prompt fails before the run, not in the middle of it.
49
56
  5. **The Local refresh asks nothing.** It runs once, at the start of line 4, and is skipped when the Releases board shows another release in Building, because that release's walk may be mid-flight on the same Local database. Then the build runs on Local as it stands.
50
57
  6. **Everything owed to a person comes out once**, as the end list in line 5, after every subtask that can be built has been built.
51
58
 
@@ -87,7 +94,7 @@ Only when every subtask that can be built has been built: each committed, `npm t
87
94
 
88
95
  1. One pull request per repo: `gh pr create --base develop --head feature/<id> --title "Release <id>: <task name>" --assignee <developer> --reviewer <developer> --body <the Scope table, the per-subtask commits, the QA reports' paths, and the migration's dev command if there is one>`. Components and utils target `main`.
89
96
  2. Every pull request body ends with the lane rule in one line: "Review any time, on the feature branch locally. Merge only when develop is free: one release on develop at a time, so this merges once the release before it is Released." Fill the Branches table in `releases/<id>.md` with the PR links; commit.
90
- 3. **How to test, on every subtask, for both readers.** Append to each subtask's description, under its Story lines, two headings (Darren, 2026-10-22: "steps for a developer to test via code, or locally, and a QA person's steps"). First, "Test locally (developer)": one numbered list with the branch to check out, the exact commands (`npm test` in the repo, the test file that proves the change, `npm run migrate -- <id> --dry --env local` when there is a migration, `npm run walk -- --local <path>` for a screen), the localhost URL and the result each command must print or show. Then, "Test on dev (QA)": one numbered list with the dev app to open first by URL (dashboard `https://dev.dashboard.trydrawbridge.com/...`, a share page `https://<slug>.dev.drwbrdg.com/...`, the website `https://dev.trydrawbridge.com/...`, the components app `https://components.trydrawbridge.com/...`), then one action per step, then what the tester must see. Every label in it is quoted from the Local walk and the QA reports of line 4, never from memory (`conventions/walk-the-app.md`), with dev URLs in place of localhost. A migration subtask says what the tester checks after the developer's dev run. The words go through `humanizer`. Both lists are written here, after the build, because only then are the commands and labels known (Darren, 2026-10-22: "include steps on how to test in the respective development apps"). The pull request body and the release doc's QA table point at the subtasks for these steps rather than repeating them.
97
+ 3. **How to test, on every subtask, for both readers.** Append to each subtask's description, under its Story lines, two headings (Darren, 2026-10-22: "steps for a developer to test via code, or locally, and a QA person's steps"). First, "Test locally (developer)": one numbered list with the branch to check out, the exact commands (`npm test` in the repo, the test file that proves the change, `npm run migrate -- <id> --dry --env local` when there is a migration, `npm run walk -- --local <path>` for a screen), the localhost URL and the result each command must print or show. Then, "Test on dev (QA)": one numbered list with the dev app to open first by URL, on the QA person's own organization from line 1 (dashboard `https://dev.dashboard.trydrawbridge.com/organizations/<their organization id>/...`, a share page `https://<slug>.dev.drwbrdg.com/...`, the website `https://dev.trydrawbridge.com/...`, the components app `https://components.trydrawbridge.com/...`), then one action per step, then what the tester must see. Every label in it is quoted from the Local walk and the QA reports of line 4, never from memory (`conventions/walk-the-app.md`), with dev URLs in place of localhost. A migration subtask says what the tester checks after the developer's dev run. The words go through `humanizer`. Both lists are written here, after the build, because only then are the commands and labels known (Darren, 2026-10-22: "include steps on how to test in the respective development apps"). The pull request body and the release doc's QA table point at the subtasks for these steps rather than repeating them.
91
98
  4. Attach every QA report's screenshots to the release task (`node lib/asana-attach.js <release id> <png>` from drawbridge-tests, one per scenario, named `<subtask id>-<scenario>.png`), because the reports under `results/qa/` are gitignored and exist only on the machine that ran them. Then put the PR links on the release task as ONE numbered list (`drawbridge-asana-comment`): this is the first Asana comment of the release, and the package pull request's link rides in it too. Assign the task to the developer and move it to Review (`POST /sections/1219762451512990/addTask`) only once every pull request is open, parked items included.
92
99
  5. Stop. Report the PR links.
93
100
 
@@ -119,7 +126,7 @@ The skill does none of this. For the record, so the skill can answer "what is th
119
126
 
120
127
  - Push `main`, deploy production, write to the production database, publish a package, merge a pull request, assign the QA person or move the task to QA or Approved. Those are a developer's or a tester's lines. On dev the skill writes nothing of its own either (the refresh only READS dev to copy it into Local); the dev migration runs on a developer's explicit instruction, by the developer or by an agent they ask.
121
128
  - Ask anything about npm publishing: who, whether, how, or for permission. The developer publishes, always; the skill hands them the one command in the end list and waits for the registry.
122
- - Name a reviewer or a release scope that nobody told it; both are asked in line 2. The tester is the developer's choice at line 6 and the window is the developer's at line 9; the skill asks for neither.
129
+ - Name a reviewer, a tester, their organizations or a release scope that nobody told it; the people are asked at line 1, the scope at line 2. The window is the developer's at line 9; the skill asks for it never.
123
130
  - Write a release document, branch or migration under any name but the Asana id.
124
131
  - Build or run the QA agent against dev or develop before the pull requests merge. Local only.
125
132
 
@@ -38,15 +38,39 @@ const envFileOk = (text) => {
38
38
  const readClaudeConfig = () => { try { return JSON.parse(fs.readFileSync(path.join(os.homedir(), '.claude.json'), 'utf8')) } catch (error) { return null } }
39
39
  const hasDigitalOcean = (config) => Boolean(config && config.mcpServers && config.mcpServers.digitalocean && config.mcpServers.digitalocean.url)
40
40
 
41
- // The mirrored settings file is what keeps an unattended run from prompting: the shared
42
- // allow list covers Bash, file writes, web fetches and every MCP tool.
41
+ // The mirrored settings file is what keeps an unattended run from prompting on EVERY
42
+ // machine: it is committed in each repo, so a clone carries it, and it covers Bash,
43
+ // file writes, web fetches and every MCP tool. Two per-machine files can still undo it:
44
+ // a drifted mirror (fixed by drawbridge-agents-sync) and a user-level deny rule in
45
+ // ~/.claude/settings.json, which beats any allow (Darren, 2026-10-23: "All machines
46
+ // using our agents repo should be exempt from system prompts").
47
+ // It must also name ../.worktrees as an allowed directory: the release builds in
48
+ // worktrees there, and a Write or Edit outside the allowed directories prompts the
49
+ // person no matter what the allow list says (Butterscotch, 2026-10-22, stopped mid-build).
43
50
  const settingsAllowAll = (text) => {
44
51
  try {
45
- const allow = JSON.parse(text).permissions.allow
46
- return [ 'Bash(*)', 'Write', 'Edit', 'mcp__*' ].every((rule) => allow.includes(rule))
52
+ const { allow, additionalDirectories } = JSON.parse(text).permissions
53
+ return [ 'Bash(*)', 'Write', 'Edit', 'mcp__*' ].every((rule) => allow.includes(rule)) && additionalDirectories.includes('../.worktrees')
47
54
  } catch (error) { return false }
48
55
  }
49
56
 
57
+ // The mirror must equal the installed package's template; a hand-edited copy is a
58
+ // machine that prompts where the others do not.
59
+ const settingsMatchTemplate = (mirror, template) => {
60
+ try { return JSON.stringify(JSON.parse(mirror).permissions) === JSON.stringify(JSON.parse(template).permissions) } catch (error) { return false }
61
+ }
62
+
63
+ // A user-level deny on Bash, Write, Edit, WebFetch or an MCP tool overrides the
64
+ // project's allow and reintroduces the prompt. `undefined` text means no user file,
65
+ // which is fine.
66
+ const userDenies = (text) => {
67
+ if (text == null) return []
68
+ try {
69
+ const deny = (JSON.parse(text).permissions || {}).deny || []
70
+ return deny.filter((rule) => /^(Bash|Write|Edit|MultiEdit|WebFetch|mcp__)/.test(rule))
71
+ } catch (error) { return [] }
72
+ }
73
+
50
74
  // The printed list: one numbered line per failure, each with its fix; nothing when all pass.
51
75
  const report = (results) => {
52
76
  const failed = results.filter((r) => !r.ok)
@@ -57,13 +81,16 @@ const report = (results) => {
57
81
  const checks = (projectsDir) => {
58
82
  const api = path.join(projectsDir, 'drawbridge-api')
59
83
  const read = (file) => { try { return fs.readFileSync(path.join(api, file), 'utf8') } catch (error) { return null } }
84
+ const readUser = () => { try { return fs.readFileSync(path.join(os.homedir(), '.claude', 'settings.json'), 'utf8') } catch (error) { return undefined } }
60
85
  return [
61
86
  { name: 'git', required: true, ok: Boolean(sh('git', [ '--version' ])), fix: 'install Xcode command line tools' },
62
87
  { name: 'gh signed in', required: true, ok: Boolean(sh('gh', [ 'auth', 'status' ])), fix: 'brew install gh && gh auth login' },
63
88
  { name: 'op with --environment (beta channel)', required: true, ok: /--environment/.test(sh('op', [ 'run', '--help' ]) || ''), fix: 'install the 1Password CLI beta: see drawbridge-growth/scripts/op.sh for the curl line' },
64
89
  { name: 'drawbridge-api/.env.local', required: true, ok: envFileOk(read('.env.local')), fix: 'two lines, OP_SERVICE_ACCOUNT_TOKEN and OP_ENVIRONMENT_ID, naming the Local Environment' },
65
90
  { name: 'drawbridge-api/.env.development', required: true, ok: envFileOk(read('.env.development')), fix: 'two lines naming the Development Environment' },
66
- { name: 'drawbridge-api/.claude/settings.json allows every tool', required: true, ok: settingsAllowAll(read(path.join('.claude', 'settings.json'))), fix: 'npx drawbridge-agents-sync in drawbridge-api mirrors the shared settings; without the allow list an overnight run stops on a permission prompt' },
91
+ { name: 'drawbridge-api/.claude/settings.json allows every tool and the worktrees folder', required: true, ok: settingsAllowAll(read(path.join('.claude', 'settings.json'))), fix: 'npx drawbridge-agents-sync in drawbridge-api mirrors the shared settings; without the allow list an overnight run stops on a permission prompt' },
92
+ { name: 'drawbridge-api/.claude/settings.json matches the installed agents template', required: true, ok: settingsMatchTemplate(read(path.join('.claude', 'settings.json')), read(path.join('node_modules', '@drawbridge', 'drawbridge-agents', '.claude-template', 'settings.json'))), fix: 'npx drawbridge-agents-sync in drawbridge-api; a hand-edited mirror prompts where other machines do not' },
93
+ { name: 'no user-level deny on the release tools', required: true, ok: userDenies(readUser()).length === 0, fix: 'remove the deny rules for Bash, Write, Edit, WebFetch or mcp__ from ~/.claude/settings.json; a deny beats the project allow and prompts mid-run' },
67
94
  { name: 'drawbridge-api/scripts/op.sh', required: true, ok: fs.existsSync(path.join(api, 'scripts', 'op.sh')), fix: 'pull develop in drawbridge-api' },
68
95
  { name: 'npm registry', required: true, ok: Boolean(sh('npm', [ 'view', '@drawbridge/drawbridge-agents', 'version' ])), fix: 'check the network or npm login' },
69
96
  { name: 'DigitalOcean MCP server in Claude Code', required: true, ok: hasDigitalOcean(readClaudeConfig()), fix: 'claude mcp add --scope user --transport http digitalocean https://apps.mcp.digitalocean.com/mcp --header "Authorization: Bearer <your DigitalOcean API token>" (the skill reads deployments through it; no doctl)' },
@@ -82,6 +109,6 @@ const main = async () => {
82
109
  process.exit(results.some((r) => r.required && !r.ok) ? 1 : 0)
83
110
  }
84
111
 
85
- module.exports = { checks, envFileOk, hasDigitalOcean, report, settingsAllowAll }
112
+ module.exports = { checks, envFileOk, hasDigitalOcean, report, settingsAllowAll, settingsMatchTemplate, userDenies }
86
113
 
87
114
  if (require.main === module) main()
@@ -68,8 +68,15 @@ skill) so it stops living only in tribal memory.
68
68
  Connections/Workflows warning dots reflect statuses `reconcileWorkflowStatus` writes — every
69
69
  handler must emit **after** the reconcile (regression: sync test/connection-emit-order.test.js).
70
70
  Emitting first hands the client a stale menu nothing re-emits to correct (the stuck-dot bug).
71
- Workflow doc changes have **no** socket event, so app-web workflow status mutations
72
- (pause/resume/delete) invalidate the menu client-side themselves.
71
+ **Since Butterscotch (release 1219790090574059; sync `stream/workflow.js`, components
72
+ `template-socket.js`)** a workflow doc change DOES have a socket event: sync emits
73
+ `organization.workflows` through `lib/emit.js` on every status change, on an `issue` write or
74
+ clear, and on delete, and the shared socket template refetches the open workflow, the list,
75
+ the organization (Next steps) and the menu dot on it. Every status writer passes through that
76
+ stream handler, so a new writer must not emit on its own, and app-web's own invalidation after
77
+ pause/resume/delete is belt and braces, not the mechanism. Before Butterscotch there was no
78
+ event and app-web invalidated the menu client-side itself; a branch cut before it merges still
79
+ behaves that way.
73
80
  - Notification dedupe has two distinct mechanisms — pick by intent. `notification.coalesce`
74
81
  is **last-write-wins supersede** (stream/notification.js deletes the prior doc sharing the
75
82
  key); `notification.key` is **first-write-wins idempotency** — a partial unique index in
@@ -412,7 +419,16 @@ skill) so it stops living only in tribal memory.
412
419
  `priority` for fetchpriority=high when it's the LCP element), `defer` gates only the player —
413
420
  never the placeholder, so deferring can't blank the box — and the native poster attribute is
414
421
  kept so unmounting the placeholder at player-ready isn't frame-timing-critical. `onError` fires
415
- exactly once, only after the hls→mp4 retry is exhausted. drawbridge-share's gallery carousel
422
+ exactly once. **Since Butterscotch (release 1219790090574059; components `video.js` and
423
+ `shared/lib/video.js` `videoErrorAction`)** when it fires is decided in one place: a non-fatal
424
+ hls.js error and an `AbortError` (a `play()` cut short by `pause()` or a source swap) are
425
+ ignored; a `NotAllowedError` (the browser refused to start playback, e.g. iOS Low Power Mode)
426
+ fails at once with NO mp4 retry, because the file is fine and the mp4 would be refused too; only
427
+ a FATAL hls.js error takes the one hls→mp4 retry, and `onError` fires when that is exhausted.
428
+ hls.js is bundled into the package and handed to react-player (`provideHls`, `window.Hls` set
429
+ before the player loads), so nothing is fetched from jsdelivr and an ad blocker cannot break
430
+ playback silently. Before Butterscotch, every player error took the retry and `onError` fired
431
+ only after it. drawbridge-share's gallery carousel
416
432
  depends on BOTH callbacks: it advances slides off `onDuration` OR `onError` registering a
417
433
  duration — remove or re-fire either and a broken video stalls the whole carousel (share
418
434
  `template-subdomain-gallery.js`, components `video.js`).
@@ -36,7 +36,7 @@ apps while leaving a sibling's peer dep on the old version triggers
36
36
  Before publishing a bump, grep peerDependencies across the family:
37
37
 
38
38
  ```sh
39
- grep -A8 peerDependencies /Users/darrenshea/Projects/drawbridge-*/package.json
39
+ grep -A8 peerDependencies ../drawbridge-*/package.json
40
40
  ```
41
41
 
42
42
  If a sibling package peer-pins something you just bumped, that sibling
@@ -50,8 +50,8 @@ paths that operate on that value. There are known copy-paste duplicates
50
50
  that drift silently when only one side is updated.
51
51
 
52
52
  ```sh
53
- grep -rn "<old-value>" /Users/darrenshea/Projects/drawbridge-* --include="*.js"
54
- grep -rn "<file-name-or-export>" /Users/darrenshea/Projects/drawbridge-* --include="*.js"
53
+ grep -rn "<old-value>" ../drawbridge-* --include="*.js"
54
+ grep -rn "<file-name-or-export>" ../drawbridge-* --include="*.js"
55
55
  ```
56
56
 
57
57
  Specifically watch for:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawbridge/drawbridge-agents",
3
- "version": "0.1.87",
3
+ "version": "0.1.89",
4
4
  "description": "Shared agent-instruction content (rules, code style, conventions) for the drawbridge-* monorepo.",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {