@integrity-labs/agt-cli 0.28.891 → 0.28.892

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.
Files changed (26) hide show
  1. package/dist/bin/agt.js +5 -5
  2. package/dist/{chunk-BH5RFBUM.js → chunk-FZ6KIIYX.js} +55 -15
  3. package/dist/chunk-FZ6KIIYX.js.map +1 -0
  4. package/dist/{chunk-2IVLMJXQ.js → chunk-SUVQ2KSP.js} +4 -4
  5. package/dist/{chunk-SXYTFXPO.js → chunk-WMJBXN6N.js} +2 -2
  6. package/dist/{claude-pair-runtime-TCDKO2CZ.js → claude-pair-runtime-RTD7ZCVS.js} +2 -2
  7. package/dist/lib/manager-worker.js +14 -39
  8. package/dist/lib/manager-worker.js.map +1 -1
  9. package/dist/mcp/direct-chat-channel.js +54 -14
  10. package/dist/mcp/index.js +54 -14
  11. package/dist/mcp/origami.js +54 -14
  12. package/dist/mcp/slack-channel.js +54 -14
  13. package/dist/mcp/telegram-channel.js +54 -14
  14. package/dist/{persistent-session-ZDZSEODJ.js → persistent-session-ARKZDYMX.js} +3 -3
  15. package/dist/{responsiveness-probe-7CY5VZMG.js → responsiveness-probe-X2WXPIUI.js} +3 -3
  16. package/dist/{session-auth-dead-65TG2DLW.js → session-auth-dead-BLEV4AUJ.js} +2 -2
  17. package/package.json +2 -2
  18. package/dist/assets/review/SKILL.md +0 -223
  19. package/dist/assets/review/SWEEP.md +0 -169
  20. package/dist/chunk-BH5RFBUM.js.map +0 -1
  21. /package/dist/{chunk-2IVLMJXQ.js.map → chunk-SUVQ2KSP.js.map} +0 -0
  22. /package/dist/{chunk-SXYTFXPO.js.map → chunk-WMJBXN6N.js.map} +0 -0
  23. /package/dist/{claude-pair-runtime-TCDKO2CZ.js.map → claude-pair-runtime-RTD7ZCVS.js.map} +0 -0
  24. /package/dist/{persistent-session-ZDZSEODJ.js.map → persistent-session-ARKZDYMX.js.map} +0 -0
  25. /package/dist/{responsiveness-probe-7CY5VZMG.js.map → responsiveness-probe-X2WXPIUI.js.map} +0 -0
  26. /package/dist/{session-auth-dead-65TG2DLW.js.map → session-auth-dead-BLEV4AUJ.js.map} +0 -0
@@ -34867,6 +34867,12 @@ function clampDirectChatHistoryLimit(raw) {
34867
34867
  return floored;
34868
34868
  }
34869
34869
 
34870
+ // ../core/dist/direct-chat/agent-history-notices.js
34871
+ var AGENT_HISTORY_TURNS_ONLY_OR_FILTER = [
34872
+ "payload->>kind.is.null",
34873
+ `payload->>kind.in.("",${[...USER_FACING_NOTICE_KINDS].sort().join(",")})`
34874
+ ].join(",");
34875
+
34870
34876
  // ../core/dist/onboarding/state-machine.js
34871
34877
  var AREA_ORDER = [
34872
34878
  "framing",
@@ -37532,16 +37538,36 @@ var FLAG_REGISTRY = [
37532
37538
  },
37533
37539
  {
37534
37540
  key: "ninjafy-brand",
37535
- description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is the USER-FACING BRAND PRESENTATION \u2014 text AND VISUAL THEME. ENG-8858 widened this from text alone: the Ninjafy palette is gated here too, because a colour theme is not text. It stays ONE key rather than gaining a `ninjafy-theme` sibling, so a half-branded state \u2014 ninjafy wordmark over Augmented green \u2014 is unreachable and the rebrand keeps a single kill switch. It must never gate a code identifier, package name, env var or CLI name. EXISTING identifiers stay `Augmented`/`agt` per the CLAUDE.md naming contract, which protects them from premature renaming \u2014 the deep rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here. That contract does NOT require NEW code to carry the old brand: artefacts created specifically for the rebrand take Ninjafy naming (ENG-8078 decision 9; see the CLAUDE.md rebrand carve-out). Either way it is a naming rule, not a flag concern \u2014 this key gates presentation, never an identifier. Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot a subset while everyone else still sees Augmented. Overrides resolve at FOUR grains, most specific first \u2014 agent, team, host, then org-wide (evaluate.ts:79-81); organization_id is always required, so there is no global override. Org and team are the useful pilot grains for THIS flag: there is now exactly ONE consumer \u2014 (dashboard)/layout.tsx via getPublicBooleanFlagServer \u2014 evaluating in the active-org cookie scope, so a host- or agent-scoped row is accepted by the table but never reached by the console. It resolves the key ONCE per request and passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop. Resolution is SERVER-side deliberately: the client hook starts at its default and updates after an async GET /flags, so anything gated on it paints Augmented and then repaints. ENG-8858 moved the PALETTE for that reason (a full-page colour flash); ENG-9227 moved the WORDMARK, which had been the last surface still swapping after hydration. A consequence worth knowing: /login and the marketing routes stay on the Augmented palette whatever an org sets, because getPublicBooleanFlagServer returns the default without a verified session and a pre-auth page has neither a session nor an active org \u2014 a PER-ORG flag structurally cannot brand one. Those surfaces follow only when the stage-wide default flips. Ships dark.',
37541
+ description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is the USER-FACING BRAND PRESENTATION \u2014 text AND VISUAL THEME. ENG-8858 widened this from text alone: the Ninjafy palette is gated here too, because a colour theme is not text. It stays ONE key rather than gaining a `ninjafy-theme` sibling, so a half-branded state \u2014 ninjafy wordmark over Augmented green \u2014 is unreachable and the rebrand keeps a single kill switch. It must never gate a code identifier, package name, env var or CLI name. EXISTING identifiers stay `Augmented`/`agt` per the CLAUDE.md naming contract, which protects them from premature renaming \u2014 the deep rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here. That contract does NOT require NEW code to carry the old brand: artefacts created specifically for the rebrand take Ninjafy naming (ENG-8078 decision 9; see the CLAUDE.md rebrand carve-out). Either way it is a naming rule, not a flag concern \u2014 this key gates presentation, never an identifier. Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot a subset while everyone else still sees Augmented. Overrides resolve at FOUR grains, most specific first \u2014 agent, team, host, then org-wide (evaluate.ts:79-81); organization_id is always required, so there is no global override. Org and team are the useful pilot grains for THIS flag: there is now exactly ONE consumer \u2014 (dashboard)/layout.tsx via getPublicBooleanFlagServer \u2014 evaluating in the active-org cookie scope, so a host- or agent-scoped row is accepted by the table but never reached by the console. It resolves the key ONCE per request and passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop. Resolution is SERVER-side deliberately: the client hook starts at its default and updates after an async GET /flags, so anything gated on it paints Augmented and then repaints. ENG-8858 moved the PALETTE for that reason (a full-page colour flash); ENG-9227 moved the WORDMARK, which had been the last surface still swapping after hydration. A consequence worth knowing: /login and the marketing routes stay on the Augmented palette whatever an org sets, because fetchPublicFlags returns null without a verified session and a pre-auth page has neither a session nor an active org \u2014 a PER-ORG flag structurally cannot brand one. ENG-9830 CORRECTS what used to be written here ("those surfaces follow only when the stage-wide default flips"): they do not follow it at all. Two reasons. The value returned on a null fetch is the CALL SITE\u2019s passed argument, not this registry default; and six such pages (/login, /reset-password, /auth/confirm, the pre-redeem member-signin gate and the two public Slack-install terminal pages) do not mount <BrandStamp/> AT ALL \u2014 deliberately, enumerated with per-page reasons in eng-9266-brand-stamp-coverage.test.ts. They become branded when the flag is REMOVED at cutover step 2 and the palette moves into bare :root, with no read left to gate it. NO LONGER DARK: ENG-9830 cutover step 1 flipped the default to true, so an org with no override now sees Ninjafy. The key survives only until cutover step 2 deletes it.',
37536
37542
  flagType: "boolean",
37537
- // Declared safe value is `false`: the pre-rebrand brand. `false` is also the
37538
- // fail-closed direction if the flag DB is unreachable we must show the brand
37539
- // that is currently live and contractually correct, never leak an unannounced
37540
- // rebrand to every customer at once.
37541
- defaultValue: false,
37543
+ // ENG-9830 (cutover step 1): flipped `false` -> `true`. The comment this
37544
+ // replaces argued `false` was the fail-closed direction "never leak an
37545
+ // UNANNOUNCED rebrand to every customer at once". That was correct for as
37546
+ // long as the rebrand was unannounced. It is not any more: Ninjafy is the
37547
+ // live, announced brand (ENG-9613 reconciled the console onto the master
37548
+ // assets while the flag was already ON in production), so `false` now points
37549
+ // at the brand we no longer ship. A flags outage that reverted a customer to
37550
+ // Augmented would be the incident, not the safe harbour.
37551
+ //
37552
+ // The old rationale is recorded rather than deleted because it is a correct
37553
+ // argument whose PREMISE expired — reading the change without it looks like
37554
+ // someone overriding a deliberate fail-closed default.
37555
+ //
37556
+ // NOTE this value is only consulted by the API evaluator when building the
37557
+ // `GET /flags` map for an org with no override. It is NOT the fallback the
37558
+ // webapp uses on an outage: `getPublicBooleanFlagServer(key, defaultValue)`
37559
+ // returns its own PASSED argument when the fetch fails, so the call sites in
37560
+ // (dashboard)/layout.tsx and components/brand-stamp.tsx carry `true` too.
37561
+ // Flipping only one of the two leaves the cutover half-applied.
37562
+ defaultValue: true,
37542
37563
  // ENG-9227: there are NO client readers of this key left. (dashboard)/
37543
37564
  // layout.tsx resolves it ONCE server-side via getPublicBooleanFlagServer and
37544
37565
  // passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop.
37566
+ // "ONCE" is about the chrome, not the key: components/brand-stamp.tsx is a
37567
+ // SECOND, independent server read of `ninjafy-brand` (CodeRabbit, #5385).
37568
+ // Both are listed in the note above because both carry an outage fallback
37569
+ // that has to move together — reading this paragraph alone would leave you
37570
+ // updating one of the two.
37545
37571
  // ENG-8858 did that for the THEME; ENG-9227 finished the job for the
37546
37572
  // WORDMARK, which had kept usePublicBooleanFlag and so kept swapping
37547
37573
  // "augmented.team" to "ninjafy" after hydration.
@@ -37563,24 +37589,38 @@ var FLAG_REGISTRY = [
37563
37589
  },
37564
37590
  {
37565
37591
  key: "ninjafy-logo",
37566
- description: "Which Ninjafy logo TREATMENT the console chrome renders (ENG-9365). This is a SUB-SELECTION under ninjafy-brand, not a second brand gate: it is consulted only once ninjafy-brand has already resolved ON, so with the brand off the value is inert and the half-branded state that flag's description calls unreachable stays unreachable. ninjafy-brand remains the single kill switch for the rebrand. It exists so candidate logo treatments can be put in front of a human and compared in the running console, rather than judged from a static export. lockup = mark and wordmark together, both in the brand blue \u2014 exactly what ENG-9298 shipped, so an unset flag is a no-op. two-tone = the mark in brand blue with the wordmark in the neutral text colour (the treatment of the blue-icon/black-wordmark artwork). wordmark = the word alone, no mark. Every treatment is composed from the ENG-9298 geometry \u2014 ENG-9312 pins that the lockup's blue path IS the mark subpath followed by the wordmark subpaths, byte for byte \u2014 so a new treatment is a composition, never a fresh trace, and the three drawings cannot drift apart. Surfaces are the dashboard sidebar and the top nav. The top nav shows the WORDMARK portion at every width whatever the treatment, because ENG-9342 decided that deliberately (a full lockup at the header's icon height crowds the team switcher on a phone) \u2014 so a treatment changes the word's colour there, never whether a mark appears. The admin sidebar (ENG-9323) is NOT wired to this key and always renders the mark; widening it is a separate decision. Resolved SERVER-SIDE in (dashboard)/layout.tsx via getPublicEnumFlagServer, beside ninjafy-brand and in the same single GET /flags round trip, then passed down as a required prop. That is not a style preference: the client hook starts at its default and updates after an async fetch, so a client read would paint one logo and swap it after hydration \u2014 the exact flash ENG-9227 removed from the wordmark and ENG-8858 removed from the palette. Org and team are the useful pilot grains, as for ninjafy-brand: the single consumer evaluates in the active-org cookie scope, so a host- or agent-scoped override row is accepted by the table but never reached by the console.",
37592
+ description: "Which Ninjafy logo TREATMENT the console chrome renders (ENG-9365). This is a SUB-SELECTION under ninjafy-brand, not a second brand gate: it is consulted only once ninjafy-brand has already resolved ON, so with the brand off the value is inert and the half-branded state that flag's description calls unreachable stays unreachable. ninjafy-brand remains the single kill switch for the rebrand. It existed so candidate logo treatments could be put in front of a human and compared in the running console, rather than judged from a static export. That comparison has happened: ENG-9830 cutover step 1 chose TWO-TONE, so that is now the default and an unset flag renders it. NOTE this reverses the property this description used to claim \u2014 an unset flag was a no-op while the default was lockup (what ENG-9298 shipped), and that is deliberately given up at cutover: the default MOVING is the change. The key survives only until cutover step 2 hardcodes the chosen treatment and deletes it. lockup = mark and wordmark together, both in the brand blue \u2014 what ENG-9298 shipped. two-tone = the mark in brand blue with the wordmark in the neutral text colour (the treatment of the blue-icon/black-wordmark artwork); the chosen one. wordmark = the word alone, no mark. Every treatment is composed from the ENG-9298 geometry \u2014 ENG-9312 pins that the lockup's blue path IS the mark subpath followed by the wordmark subpaths, byte for byte \u2014 so a new treatment is a composition, never a fresh trace, and the three drawings cannot drift apart. Surfaces are the dashboard sidebar and the top nav. The top nav shows the WORDMARK portion at every width whatever the treatment, because ENG-9342 decided that deliberately (a full lockup at the header's icon height crowds the team switcher on a phone) \u2014 so a treatment changes the word's colour there, never whether a mark appears. The admin sidebar (ENG-9323) is NOT wired to this key and always renders the mark; widening it is a separate decision. Resolved SERVER-SIDE in (dashboard)/layout.tsx via getPublicEnumFlagServer, beside ninjafy-brand and in the same single GET /flags round trip, then passed down as a required prop. That is not a style preference: the client hook starts at its default and updates after an async fetch, so a client read would paint one logo and swap it after hydration \u2014 the exact flash ENG-9227 removed from the wordmark and ENG-8858 removed from the palette. Org and team are the useful pilot grains, as for ninjafy-brand: the single consumer evaluates in the active-org cookie scope, so a host- or agent-scoped override row is accepted by the table but never reached by the console.",
37567
37593
  flagType: "enum",
37568
37594
  allowedValues: ["lockup", "two-tone", "wordmark"],
37569
- // Declared safe value is `lockup` what ENG-9298 shipped. This flag has no
37570
- // "off" direction: it selects among presentations that are all live-safe, so
37571
- // fail-safe here means "the treatment currently in production", not the
37595
+ // ENG-9830 (cutover step 1): `lockup` -> `two-tone`. The treatments existed
37596
+ // so they could be compared in the running console rather than judged from a
37597
+ // static export (ENG-9365); that comparison has now happened and `two-tone`
37598
+ // — the mark in brand blue with the wordmark in the neutral text colour — is
37599
+ // the chosen treatment. It becomes the hardcoded one when this key is
37600
+ // removed at cutover step 2.
37601
+ //
37602
+ // The rule this value obeys is unchanged: this flag has no "off" direction,
37603
+ // so fail-safe means "the treatment currently in production", not the
37572
37604
  // narrowest one. A flag-DB read error, an archived row, or a stored value
37573
37605
  // outside allowedValues all resolve here (evaluate.ts normalizeFlagValue),
37574
- // which is what makes an experimental value impossible to strand.
37575
- defaultValue: "lockup",
37606
+ // which is what makes an experimental value impossible to strand. Only which
37607
+ // treatment holds that position has moved.
37608
+ //
37609
+ // Same split as ninjafy-brand above: this governs the API evaluation path
37610
+ // only. The webapp's outage fallback is the argument passed at the
37611
+ // (dashboard)/layout.tsx call site, which carries 'two-tone' to match.
37612
+ defaultValue: "two-tone",
37576
37613
  // Same trap as ninjafy-brand, and it bites harder here because there are no
37577
37614
  // client readers of this key AT ALL — it is server-resolved by construction.
37578
37615
  // `public` does NOT mean "read by a browser"; it means "readable through the
37579
37616
  // public map". getPublicEnumFlagServer resolves against the same GET /flags
37580
37617
  // endpoint the browser uses, and that route filters to listPublicFlagKeys()
37581
37618
  // (routes/flags.ts). Drop `public` and the key is simply absent from the map,
37582
- // so the helper falls through to its default and returns `lockup` FOREVER
37583
- // the dropdown appearing to do nothing, with no error raised anywhere.
37619
+ // so the helper falls through to the fallback passed at that call site and
37620
+ // returns it FOREVER — the dropdown appearing to do nothing, with no error
37621
+ // raised anywhere. Named as the call site rather than as a literal on
37622
+ // purpose: this comment said `lockup` for exactly as long as `lockup` was
37623
+ // the answer, and ENG-9830 flipping the winner is what made it a lie.
37584
37624
  public: true
37585
37625
  },
37586
37626
  {
package/dist/mcp/index.js CHANGED
@@ -27363,6 +27363,12 @@ var CURSOR_SHORTFALL_REASONS = [
27363
27363
  var NON_SHORTFALL_KEYS = new Set(CURSOR_ADVANCE_NON_SHORTFALL_KEYS);
27364
27364
  var KNOWN_REASONS = new Set(CURSOR_SHORTFALL_REASONS.filter((k) => !NON_SHORTFALL_KEYS.has(k)));
27365
27365
 
27366
+ // ../core/dist/direct-chat/agent-history-notices.js
27367
+ var AGENT_HISTORY_TURNS_ONLY_OR_FILTER = [
27368
+ "payload->>kind.is.null",
27369
+ `payload->>kind.in.("",${[...USER_FACING_NOTICE_KINDS].sort().join(",")})`
27370
+ ].join(",");
27371
+
27366
27372
  // ../core/dist/onboarding/state-machine.js
27367
27373
  var AREA_ORDER = [
27368
27374
  "framing",
@@ -29827,16 +29833,36 @@ var FLAG_REGISTRY = [
29827
29833
  },
29828
29834
  {
29829
29835
  key: "ninjafy-brand",
29830
- description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is the USER-FACING BRAND PRESENTATION \u2014 text AND VISUAL THEME. ENG-8858 widened this from text alone: the Ninjafy palette is gated here too, because a colour theme is not text. It stays ONE key rather than gaining a `ninjafy-theme` sibling, so a half-branded state \u2014 ninjafy wordmark over Augmented green \u2014 is unreachable and the rebrand keeps a single kill switch. It must never gate a code identifier, package name, env var or CLI name. EXISTING identifiers stay `Augmented`/`agt` per the CLAUDE.md naming contract, which protects them from premature renaming \u2014 the deep rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here. That contract does NOT require NEW code to carry the old brand: artefacts created specifically for the rebrand take Ninjafy naming (ENG-8078 decision 9; see the CLAUDE.md rebrand carve-out). Either way it is a naming rule, not a flag concern \u2014 this key gates presentation, never an identifier. Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot a subset while everyone else still sees Augmented. Overrides resolve at FOUR grains, most specific first \u2014 agent, team, host, then org-wide (evaluate.ts:79-81); organization_id is always required, so there is no global override. Org and team are the useful pilot grains for THIS flag: there is now exactly ONE consumer \u2014 (dashboard)/layout.tsx via getPublicBooleanFlagServer \u2014 evaluating in the active-org cookie scope, so a host- or agent-scoped row is accepted by the table but never reached by the console. It resolves the key ONCE per request and passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop. Resolution is SERVER-side deliberately: the client hook starts at its default and updates after an async GET /flags, so anything gated on it paints Augmented and then repaints. ENG-8858 moved the PALETTE for that reason (a full-page colour flash); ENG-9227 moved the WORDMARK, which had been the last surface still swapping after hydration. A consequence worth knowing: /login and the marketing routes stay on the Augmented palette whatever an org sets, because getPublicBooleanFlagServer returns the default without a verified session and a pre-auth page has neither a session nor an active org \u2014 a PER-ORG flag structurally cannot brand one. Those surfaces follow only when the stage-wide default flips. Ships dark.',
29836
+ description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is the USER-FACING BRAND PRESENTATION \u2014 text AND VISUAL THEME. ENG-8858 widened this from text alone: the Ninjafy palette is gated here too, because a colour theme is not text. It stays ONE key rather than gaining a `ninjafy-theme` sibling, so a half-branded state \u2014 ninjafy wordmark over Augmented green \u2014 is unreachable and the rebrand keeps a single kill switch. It must never gate a code identifier, package name, env var or CLI name. EXISTING identifiers stay `Augmented`/`agt` per the CLAUDE.md naming contract, which protects them from premature renaming \u2014 the deep rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here. That contract does NOT require NEW code to carry the old brand: artefacts created specifically for the rebrand take Ninjafy naming (ENG-8078 decision 9; see the CLAUDE.md rebrand carve-out). Either way it is a naming rule, not a flag concern \u2014 this key gates presentation, never an identifier. Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot a subset while everyone else still sees Augmented. Overrides resolve at FOUR grains, most specific first \u2014 agent, team, host, then org-wide (evaluate.ts:79-81); organization_id is always required, so there is no global override. Org and team are the useful pilot grains for THIS flag: there is now exactly ONE consumer \u2014 (dashboard)/layout.tsx via getPublicBooleanFlagServer \u2014 evaluating in the active-org cookie scope, so a host- or agent-scoped row is accepted by the table but never reached by the console. It resolves the key ONCE per request and passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop. Resolution is SERVER-side deliberately: the client hook starts at its default and updates after an async GET /flags, so anything gated on it paints Augmented and then repaints. ENG-8858 moved the PALETTE for that reason (a full-page colour flash); ENG-9227 moved the WORDMARK, which had been the last surface still swapping after hydration. A consequence worth knowing: /login and the marketing routes stay on the Augmented palette whatever an org sets, because fetchPublicFlags returns null without a verified session and a pre-auth page has neither a session nor an active org \u2014 a PER-ORG flag structurally cannot brand one. ENG-9830 CORRECTS what used to be written here ("those surfaces follow only when the stage-wide default flips"): they do not follow it at all. Two reasons. The value returned on a null fetch is the CALL SITE\u2019s passed argument, not this registry default; and six such pages (/login, /reset-password, /auth/confirm, the pre-redeem member-signin gate and the two public Slack-install terminal pages) do not mount <BrandStamp/> AT ALL \u2014 deliberately, enumerated with per-page reasons in eng-9266-brand-stamp-coverage.test.ts. They become branded when the flag is REMOVED at cutover step 2 and the palette moves into bare :root, with no read left to gate it. NO LONGER DARK: ENG-9830 cutover step 1 flipped the default to true, so an org with no override now sees Ninjafy. The key survives only until cutover step 2 deletes it.',
29831
29837
  flagType: "boolean",
29832
- // Declared safe value is `false`: the pre-rebrand brand. `false` is also the
29833
- // fail-closed direction if the flag DB is unreachable we must show the brand
29834
- // that is currently live and contractually correct, never leak an unannounced
29835
- // rebrand to every customer at once.
29836
- defaultValue: false,
29838
+ // ENG-9830 (cutover step 1): flipped `false` -> `true`. The comment this
29839
+ // replaces argued `false` was the fail-closed direction "never leak an
29840
+ // UNANNOUNCED rebrand to every customer at once". That was correct for as
29841
+ // long as the rebrand was unannounced. It is not any more: Ninjafy is the
29842
+ // live, announced brand (ENG-9613 reconciled the console onto the master
29843
+ // assets while the flag was already ON in production), so `false` now points
29844
+ // at the brand we no longer ship. A flags outage that reverted a customer to
29845
+ // Augmented would be the incident, not the safe harbour.
29846
+ //
29847
+ // The old rationale is recorded rather than deleted because it is a correct
29848
+ // argument whose PREMISE expired — reading the change without it looks like
29849
+ // someone overriding a deliberate fail-closed default.
29850
+ //
29851
+ // NOTE this value is only consulted by the API evaluator when building the
29852
+ // `GET /flags` map for an org with no override. It is NOT the fallback the
29853
+ // webapp uses on an outage: `getPublicBooleanFlagServer(key, defaultValue)`
29854
+ // returns its own PASSED argument when the fetch fails, so the call sites in
29855
+ // (dashboard)/layout.tsx and components/brand-stamp.tsx carry `true` too.
29856
+ // Flipping only one of the two leaves the cutover half-applied.
29857
+ defaultValue: true,
29837
29858
  // ENG-9227: there are NO client readers of this key left. (dashboard)/
29838
29859
  // layout.tsx resolves it ONCE server-side via getPublicBooleanFlagServer and
29839
29860
  // passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop.
29861
+ // "ONCE" is about the chrome, not the key: components/brand-stamp.tsx is a
29862
+ // SECOND, independent server read of `ninjafy-brand` (CodeRabbit, #5385).
29863
+ // Both are listed in the note above because both carry an outage fallback
29864
+ // that has to move together — reading this paragraph alone would leave you
29865
+ // updating one of the two.
29840
29866
  // ENG-8858 did that for the THEME; ENG-9227 finished the job for the
29841
29867
  // WORDMARK, which had kept usePublicBooleanFlag and so kept swapping
29842
29868
  // "augmented.team" to "ninjafy" after hydration.
@@ -29858,24 +29884,38 @@ var FLAG_REGISTRY = [
29858
29884
  },
29859
29885
  {
29860
29886
  key: "ninjafy-logo",
29861
- description: "Which Ninjafy logo TREATMENT the console chrome renders (ENG-9365). This is a SUB-SELECTION under ninjafy-brand, not a second brand gate: it is consulted only once ninjafy-brand has already resolved ON, so with the brand off the value is inert and the half-branded state that flag's description calls unreachable stays unreachable. ninjafy-brand remains the single kill switch for the rebrand. It exists so candidate logo treatments can be put in front of a human and compared in the running console, rather than judged from a static export. lockup = mark and wordmark together, both in the brand blue \u2014 exactly what ENG-9298 shipped, so an unset flag is a no-op. two-tone = the mark in brand blue with the wordmark in the neutral text colour (the treatment of the blue-icon/black-wordmark artwork). wordmark = the word alone, no mark. Every treatment is composed from the ENG-9298 geometry \u2014 ENG-9312 pins that the lockup's blue path IS the mark subpath followed by the wordmark subpaths, byte for byte \u2014 so a new treatment is a composition, never a fresh trace, and the three drawings cannot drift apart. Surfaces are the dashboard sidebar and the top nav. The top nav shows the WORDMARK portion at every width whatever the treatment, because ENG-9342 decided that deliberately (a full lockup at the header's icon height crowds the team switcher on a phone) \u2014 so a treatment changes the word's colour there, never whether a mark appears. The admin sidebar (ENG-9323) is NOT wired to this key and always renders the mark; widening it is a separate decision. Resolved SERVER-SIDE in (dashboard)/layout.tsx via getPublicEnumFlagServer, beside ninjafy-brand and in the same single GET /flags round trip, then passed down as a required prop. That is not a style preference: the client hook starts at its default and updates after an async fetch, so a client read would paint one logo and swap it after hydration \u2014 the exact flash ENG-9227 removed from the wordmark and ENG-8858 removed from the palette. Org and team are the useful pilot grains, as for ninjafy-brand: the single consumer evaluates in the active-org cookie scope, so a host- or agent-scoped override row is accepted by the table but never reached by the console.",
29887
+ description: "Which Ninjafy logo TREATMENT the console chrome renders (ENG-9365). This is a SUB-SELECTION under ninjafy-brand, not a second brand gate: it is consulted only once ninjafy-brand has already resolved ON, so with the brand off the value is inert and the half-branded state that flag's description calls unreachable stays unreachable. ninjafy-brand remains the single kill switch for the rebrand. It existed so candidate logo treatments could be put in front of a human and compared in the running console, rather than judged from a static export. That comparison has happened: ENG-9830 cutover step 1 chose TWO-TONE, so that is now the default and an unset flag renders it. NOTE this reverses the property this description used to claim \u2014 an unset flag was a no-op while the default was lockup (what ENG-9298 shipped), and that is deliberately given up at cutover: the default MOVING is the change. The key survives only until cutover step 2 hardcodes the chosen treatment and deletes it. lockup = mark and wordmark together, both in the brand blue \u2014 what ENG-9298 shipped. two-tone = the mark in brand blue with the wordmark in the neutral text colour (the treatment of the blue-icon/black-wordmark artwork); the chosen one. wordmark = the word alone, no mark. Every treatment is composed from the ENG-9298 geometry \u2014 ENG-9312 pins that the lockup's blue path IS the mark subpath followed by the wordmark subpaths, byte for byte \u2014 so a new treatment is a composition, never a fresh trace, and the three drawings cannot drift apart. Surfaces are the dashboard sidebar and the top nav. The top nav shows the WORDMARK portion at every width whatever the treatment, because ENG-9342 decided that deliberately (a full lockup at the header's icon height crowds the team switcher on a phone) \u2014 so a treatment changes the word's colour there, never whether a mark appears. The admin sidebar (ENG-9323) is NOT wired to this key and always renders the mark; widening it is a separate decision. Resolved SERVER-SIDE in (dashboard)/layout.tsx via getPublicEnumFlagServer, beside ninjafy-brand and in the same single GET /flags round trip, then passed down as a required prop. That is not a style preference: the client hook starts at its default and updates after an async fetch, so a client read would paint one logo and swap it after hydration \u2014 the exact flash ENG-9227 removed from the wordmark and ENG-8858 removed from the palette. Org and team are the useful pilot grains, as for ninjafy-brand: the single consumer evaluates in the active-org cookie scope, so a host- or agent-scoped override row is accepted by the table but never reached by the console.",
29862
29888
  flagType: "enum",
29863
29889
  allowedValues: ["lockup", "two-tone", "wordmark"],
29864
- // Declared safe value is `lockup` what ENG-9298 shipped. This flag has no
29865
- // "off" direction: it selects among presentations that are all live-safe, so
29866
- // fail-safe here means "the treatment currently in production", not the
29890
+ // ENG-9830 (cutover step 1): `lockup` -> `two-tone`. The treatments existed
29891
+ // so they could be compared in the running console rather than judged from a
29892
+ // static export (ENG-9365); that comparison has now happened and `two-tone`
29893
+ // — the mark in brand blue with the wordmark in the neutral text colour — is
29894
+ // the chosen treatment. It becomes the hardcoded one when this key is
29895
+ // removed at cutover step 2.
29896
+ //
29897
+ // The rule this value obeys is unchanged: this flag has no "off" direction,
29898
+ // so fail-safe means "the treatment currently in production", not the
29867
29899
  // narrowest one. A flag-DB read error, an archived row, or a stored value
29868
29900
  // outside allowedValues all resolve here (evaluate.ts normalizeFlagValue),
29869
- // which is what makes an experimental value impossible to strand.
29870
- defaultValue: "lockup",
29901
+ // which is what makes an experimental value impossible to strand. Only which
29902
+ // treatment holds that position has moved.
29903
+ //
29904
+ // Same split as ninjafy-brand above: this governs the API evaluation path
29905
+ // only. The webapp's outage fallback is the argument passed at the
29906
+ // (dashboard)/layout.tsx call site, which carries 'two-tone' to match.
29907
+ defaultValue: "two-tone",
29871
29908
  // Same trap as ninjafy-brand, and it bites harder here because there are no
29872
29909
  // client readers of this key AT ALL — it is server-resolved by construction.
29873
29910
  // `public` does NOT mean "read by a browser"; it means "readable through the
29874
29911
  // public map". getPublicEnumFlagServer resolves against the same GET /flags
29875
29912
  // endpoint the browser uses, and that route filters to listPublicFlagKeys()
29876
29913
  // (routes/flags.ts). Drop `public` and the key is simply absent from the map,
29877
- // so the helper falls through to its default and returns `lockup` FOREVER
29878
- // the dropdown appearing to do nothing, with no error raised anywhere.
29914
+ // so the helper falls through to the fallback passed at that call site and
29915
+ // returns it FOREVER — the dropdown appearing to do nothing, with no error
29916
+ // raised anywhere. Named as the call site rather than as a literal on
29917
+ // purpose: this comment said `lockup` for exactly as long as `lockup` was
29918
+ // the answer, and ENG-9830 flipping the winner is what made it a lie.
29879
29919
  public: true
29880
29920
  },
29881
29921
  {
@@ -41494,6 +41494,12 @@ var CURSOR_SHORTFALL_REASONS = [
41494
41494
  var NON_SHORTFALL_KEYS = new Set(CURSOR_ADVANCE_NON_SHORTFALL_KEYS);
41495
41495
  var KNOWN_REASONS = new Set(CURSOR_SHORTFALL_REASONS.filter((k) => !NON_SHORTFALL_KEYS.has(k)));
41496
41496
 
41497
+ // ../core/dist/direct-chat/agent-history-notices.js
41498
+ var AGENT_HISTORY_TURNS_ONLY_OR_FILTER = [
41499
+ "payload->>kind.is.null",
41500
+ `payload->>kind.in.("",${[...USER_FACING_NOTICE_KINDS].sort().join(",")})`
41501
+ ].join(",");
41502
+
41497
41503
  // ../core/dist/onboarding/state-machine.js
41498
41504
  var AREA_ORDER = [
41499
41505
  "framing",
@@ -43755,16 +43761,36 @@ var FLAG_REGISTRY = [
43755
43761
  },
43756
43762
  {
43757
43763
  key: "ninjafy-brand",
43758
- description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is the USER-FACING BRAND PRESENTATION \u2014 text AND VISUAL THEME. ENG-8858 widened this from text alone: the Ninjafy palette is gated here too, because a colour theme is not text. It stays ONE key rather than gaining a `ninjafy-theme` sibling, so a half-branded state \u2014 ninjafy wordmark over Augmented green \u2014 is unreachable and the rebrand keeps a single kill switch. It must never gate a code identifier, package name, env var or CLI name. EXISTING identifiers stay `Augmented`/`agt` per the CLAUDE.md naming contract, which protects them from premature renaming \u2014 the deep rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here. That contract does NOT require NEW code to carry the old brand: artefacts created specifically for the rebrand take Ninjafy naming (ENG-8078 decision 9; see the CLAUDE.md rebrand carve-out). Either way it is a naming rule, not a flag concern \u2014 this key gates presentation, never an identifier. Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot a subset while everyone else still sees Augmented. Overrides resolve at FOUR grains, most specific first \u2014 agent, team, host, then org-wide (evaluate.ts:79-81); organization_id is always required, so there is no global override. Org and team are the useful pilot grains for THIS flag: there is now exactly ONE consumer \u2014 (dashboard)/layout.tsx via getPublicBooleanFlagServer \u2014 evaluating in the active-org cookie scope, so a host- or agent-scoped row is accepted by the table but never reached by the console. It resolves the key ONCE per request and passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop. Resolution is SERVER-side deliberately: the client hook starts at its default and updates after an async GET /flags, so anything gated on it paints Augmented and then repaints. ENG-8858 moved the PALETTE for that reason (a full-page colour flash); ENG-9227 moved the WORDMARK, which had been the last surface still swapping after hydration. A consequence worth knowing: /login and the marketing routes stay on the Augmented palette whatever an org sets, because getPublicBooleanFlagServer returns the default without a verified session and a pre-auth page has neither a session nor an active org \u2014 a PER-ORG flag structurally cannot brand one. Those surfaces follow only when the stage-wide default flips. Ships dark.',
43764
+ description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is the USER-FACING BRAND PRESENTATION \u2014 text AND VISUAL THEME. ENG-8858 widened this from text alone: the Ninjafy palette is gated here too, because a colour theme is not text. It stays ONE key rather than gaining a `ninjafy-theme` sibling, so a half-branded state \u2014 ninjafy wordmark over Augmented green \u2014 is unreachable and the rebrand keeps a single kill switch. It must never gate a code identifier, package name, env var or CLI name. EXISTING identifiers stay `Augmented`/`agt` per the CLAUDE.md naming contract, which protects them from premature renaming \u2014 the deep rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here. That contract does NOT require NEW code to carry the old brand: artefacts created specifically for the rebrand take Ninjafy naming (ENG-8078 decision 9; see the CLAUDE.md rebrand carve-out). Either way it is a naming rule, not a flag concern \u2014 this key gates presentation, never an identifier. Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot a subset while everyone else still sees Augmented. Overrides resolve at FOUR grains, most specific first \u2014 agent, team, host, then org-wide (evaluate.ts:79-81); organization_id is always required, so there is no global override. Org and team are the useful pilot grains for THIS flag: there is now exactly ONE consumer \u2014 (dashboard)/layout.tsx via getPublicBooleanFlagServer \u2014 evaluating in the active-org cookie scope, so a host- or agent-scoped row is accepted by the table but never reached by the console. It resolves the key ONCE per request and passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop. Resolution is SERVER-side deliberately: the client hook starts at its default and updates after an async GET /flags, so anything gated on it paints Augmented and then repaints. ENG-8858 moved the PALETTE for that reason (a full-page colour flash); ENG-9227 moved the WORDMARK, which had been the last surface still swapping after hydration. A consequence worth knowing: /login and the marketing routes stay on the Augmented palette whatever an org sets, because fetchPublicFlags returns null without a verified session and a pre-auth page has neither a session nor an active org \u2014 a PER-ORG flag structurally cannot brand one. ENG-9830 CORRECTS what used to be written here ("those surfaces follow only when the stage-wide default flips"): they do not follow it at all. Two reasons. The value returned on a null fetch is the CALL SITE\u2019s passed argument, not this registry default; and six such pages (/login, /reset-password, /auth/confirm, the pre-redeem member-signin gate and the two public Slack-install terminal pages) do not mount <BrandStamp/> AT ALL \u2014 deliberately, enumerated with per-page reasons in eng-9266-brand-stamp-coverage.test.ts. They become branded when the flag is REMOVED at cutover step 2 and the palette moves into bare :root, with no read left to gate it. NO LONGER DARK: ENG-9830 cutover step 1 flipped the default to true, so an org with no override now sees Ninjafy. The key survives only until cutover step 2 deletes it.',
43759
43765
  flagType: "boolean",
43760
- // Declared safe value is `false`: the pre-rebrand brand. `false` is also the
43761
- // fail-closed direction if the flag DB is unreachable we must show the brand
43762
- // that is currently live and contractually correct, never leak an unannounced
43763
- // rebrand to every customer at once.
43764
- defaultValue: false,
43766
+ // ENG-9830 (cutover step 1): flipped `false` -> `true`. The comment this
43767
+ // replaces argued `false` was the fail-closed direction "never leak an
43768
+ // UNANNOUNCED rebrand to every customer at once". That was correct for as
43769
+ // long as the rebrand was unannounced. It is not any more: Ninjafy is the
43770
+ // live, announced brand (ENG-9613 reconciled the console onto the master
43771
+ // assets while the flag was already ON in production), so `false` now points
43772
+ // at the brand we no longer ship. A flags outage that reverted a customer to
43773
+ // Augmented would be the incident, not the safe harbour.
43774
+ //
43775
+ // The old rationale is recorded rather than deleted because it is a correct
43776
+ // argument whose PREMISE expired — reading the change without it looks like
43777
+ // someone overriding a deliberate fail-closed default.
43778
+ //
43779
+ // NOTE this value is only consulted by the API evaluator when building the
43780
+ // `GET /flags` map for an org with no override. It is NOT the fallback the
43781
+ // webapp uses on an outage: `getPublicBooleanFlagServer(key, defaultValue)`
43782
+ // returns its own PASSED argument when the fetch fails, so the call sites in
43783
+ // (dashboard)/layout.tsx and components/brand-stamp.tsx carry `true` too.
43784
+ // Flipping only one of the two leaves the cutover half-applied.
43785
+ defaultValue: true,
43765
43786
  // ENG-9227: there are NO client readers of this key left. (dashboard)/
43766
43787
  // layout.tsx resolves it ONCE server-side via getPublicBooleanFlagServer and
43767
43788
  // passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop.
43789
+ // "ONCE" is about the chrome, not the key: components/brand-stamp.tsx is a
43790
+ // SECOND, independent server read of `ninjafy-brand` (CodeRabbit, #5385).
43791
+ // Both are listed in the note above because both carry an outage fallback
43792
+ // that has to move together — reading this paragraph alone would leave you
43793
+ // updating one of the two.
43768
43794
  // ENG-8858 did that for the THEME; ENG-9227 finished the job for the
43769
43795
  // WORDMARK, which had kept usePublicBooleanFlag and so kept swapping
43770
43796
  // "augmented.team" to "ninjafy" after hydration.
@@ -43786,24 +43812,38 @@ var FLAG_REGISTRY = [
43786
43812
  },
43787
43813
  {
43788
43814
  key: "ninjafy-logo",
43789
- description: "Which Ninjafy logo TREATMENT the console chrome renders (ENG-9365). This is a SUB-SELECTION under ninjafy-brand, not a second brand gate: it is consulted only once ninjafy-brand has already resolved ON, so with the brand off the value is inert and the half-branded state that flag's description calls unreachable stays unreachable. ninjafy-brand remains the single kill switch for the rebrand. It exists so candidate logo treatments can be put in front of a human and compared in the running console, rather than judged from a static export. lockup = mark and wordmark together, both in the brand blue \u2014 exactly what ENG-9298 shipped, so an unset flag is a no-op. two-tone = the mark in brand blue with the wordmark in the neutral text colour (the treatment of the blue-icon/black-wordmark artwork). wordmark = the word alone, no mark. Every treatment is composed from the ENG-9298 geometry \u2014 ENG-9312 pins that the lockup's blue path IS the mark subpath followed by the wordmark subpaths, byte for byte \u2014 so a new treatment is a composition, never a fresh trace, and the three drawings cannot drift apart. Surfaces are the dashboard sidebar and the top nav. The top nav shows the WORDMARK portion at every width whatever the treatment, because ENG-9342 decided that deliberately (a full lockup at the header's icon height crowds the team switcher on a phone) \u2014 so a treatment changes the word's colour there, never whether a mark appears. The admin sidebar (ENG-9323) is NOT wired to this key and always renders the mark; widening it is a separate decision. Resolved SERVER-SIDE in (dashboard)/layout.tsx via getPublicEnumFlagServer, beside ninjafy-brand and in the same single GET /flags round trip, then passed down as a required prop. That is not a style preference: the client hook starts at its default and updates after an async fetch, so a client read would paint one logo and swap it after hydration \u2014 the exact flash ENG-9227 removed from the wordmark and ENG-8858 removed from the palette. Org and team are the useful pilot grains, as for ninjafy-brand: the single consumer evaluates in the active-org cookie scope, so a host- or agent-scoped override row is accepted by the table but never reached by the console.",
43815
+ description: "Which Ninjafy logo TREATMENT the console chrome renders (ENG-9365). This is a SUB-SELECTION under ninjafy-brand, not a second brand gate: it is consulted only once ninjafy-brand has already resolved ON, so with the brand off the value is inert and the half-branded state that flag's description calls unreachable stays unreachable. ninjafy-brand remains the single kill switch for the rebrand. It existed so candidate logo treatments could be put in front of a human and compared in the running console, rather than judged from a static export. That comparison has happened: ENG-9830 cutover step 1 chose TWO-TONE, so that is now the default and an unset flag renders it. NOTE this reverses the property this description used to claim \u2014 an unset flag was a no-op while the default was lockup (what ENG-9298 shipped), and that is deliberately given up at cutover: the default MOVING is the change. The key survives only until cutover step 2 hardcodes the chosen treatment and deletes it. lockup = mark and wordmark together, both in the brand blue \u2014 what ENG-9298 shipped. two-tone = the mark in brand blue with the wordmark in the neutral text colour (the treatment of the blue-icon/black-wordmark artwork); the chosen one. wordmark = the word alone, no mark. Every treatment is composed from the ENG-9298 geometry \u2014 ENG-9312 pins that the lockup's blue path IS the mark subpath followed by the wordmark subpaths, byte for byte \u2014 so a new treatment is a composition, never a fresh trace, and the three drawings cannot drift apart. Surfaces are the dashboard sidebar and the top nav. The top nav shows the WORDMARK portion at every width whatever the treatment, because ENG-9342 decided that deliberately (a full lockup at the header's icon height crowds the team switcher on a phone) \u2014 so a treatment changes the word's colour there, never whether a mark appears. The admin sidebar (ENG-9323) is NOT wired to this key and always renders the mark; widening it is a separate decision. Resolved SERVER-SIDE in (dashboard)/layout.tsx via getPublicEnumFlagServer, beside ninjafy-brand and in the same single GET /flags round trip, then passed down as a required prop. That is not a style preference: the client hook starts at its default and updates after an async fetch, so a client read would paint one logo and swap it after hydration \u2014 the exact flash ENG-9227 removed from the wordmark and ENG-8858 removed from the palette. Org and team are the useful pilot grains, as for ninjafy-brand: the single consumer evaluates in the active-org cookie scope, so a host- or agent-scoped override row is accepted by the table but never reached by the console.",
43790
43816
  flagType: "enum",
43791
43817
  allowedValues: ["lockup", "two-tone", "wordmark"],
43792
- // Declared safe value is `lockup` what ENG-9298 shipped. This flag has no
43793
- // "off" direction: it selects among presentations that are all live-safe, so
43794
- // fail-safe here means "the treatment currently in production", not the
43818
+ // ENG-9830 (cutover step 1): `lockup` -> `two-tone`. The treatments existed
43819
+ // so they could be compared in the running console rather than judged from a
43820
+ // static export (ENG-9365); that comparison has now happened and `two-tone`
43821
+ // — the mark in brand blue with the wordmark in the neutral text colour — is
43822
+ // the chosen treatment. It becomes the hardcoded one when this key is
43823
+ // removed at cutover step 2.
43824
+ //
43825
+ // The rule this value obeys is unchanged: this flag has no "off" direction,
43826
+ // so fail-safe means "the treatment currently in production", not the
43795
43827
  // narrowest one. A flag-DB read error, an archived row, or a stored value
43796
43828
  // outside allowedValues all resolve here (evaluate.ts normalizeFlagValue),
43797
- // which is what makes an experimental value impossible to strand.
43798
- defaultValue: "lockup",
43829
+ // which is what makes an experimental value impossible to strand. Only which
43830
+ // treatment holds that position has moved.
43831
+ //
43832
+ // Same split as ninjafy-brand above: this governs the API evaluation path
43833
+ // only. The webapp's outage fallback is the argument passed at the
43834
+ // (dashboard)/layout.tsx call site, which carries 'two-tone' to match.
43835
+ defaultValue: "two-tone",
43799
43836
  // Same trap as ninjafy-brand, and it bites harder here because there are no
43800
43837
  // client readers of this key AT ALL — it is server-resolved by construction.
43801
43838
  // `public` does NOT mean "read by a browser"; it means "readable through the
43802
43839
  // public map". getPublicEnumFlagServer resolves against the same GET /flags
43803
43840
  // endpoint the browser uses, and that route filters to listPublicFlagKeys()
43804
43841
  // (routes/flags.ts). Drop `public` and the key is simply absent from the map,
43805
- // so the helper falls through to its default and returns `lockup` FOREVER
43806
- // the dropdown appearing to do nothing, with no error raised anywhere.
43842
+ // so the helper falls through to the fallback passed at that call site and
43843
+ // returns it FOREVER — the dropdown appearing to do nothing, with no error
43844
+ // raised anywhere. Named as the call site rather than as a literal on
43845
+ // purpose: this comment said `lockup` for exactly as long as `lockup` was
43846
+ // the answer, and ENG-9830 flipping the winner is what made it a lie.
43807
43847
  public: true
43808
43848
  },
43809
43849
  {
@@ -35724,6 +35724,12 @@ var CURSOR_SHORTFALL_REASONS = [
35724
35724
  var NON_SHORTFALL_KEYS = new Set(CURSOR_ADVANCE_NON_SHORTFALL_KEYS);
35725
35725
  var KNOWN_REASONS = new Set(CURSOR_SHORTFALL_REASONS.filter((k) => !NON_SHORTFALL_KEYS.has(k)));
35726
35726
 
35727
+ // ../core/dist/direct-chat/agent-history-notices.js
35728
+ var AGENT_HISTORY_TURNS_ONLY_OR_FILTER = [
35729
+ "payload->>kind.is.null",
35730
+ `payload->>kind.in.("",${[...USER_FACING_NOTICE_KINDS].sort().join(",")})`
35731
+ ].join(",");
35732
+
35727
35733
  // ../core/dist/onboarding/state-machine.js
35728
35734
  var AREA_ORDER = [
35729
35735
  "framing",
@@ -38392,16 +38398,36 @@ var FLAG_REGISTRY = [
38392
38398
  },
38393
38399
  {
38394
38400
  key: "ninjafy-brand",
38395
- description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is the USER-FACING BRAND PRESENTATION \u2014 text AND VISUAL THEME. ENG-8858 widened this from text alone: the Ninjafy palette is gated here too, because a colour theme is not text. It stays ONE key rather than gaining a `ninjafy-theme` sibling, so a half-branded state \u2014 ninjafy wordmark over Augmented green \u2014 is unreachable and the rebrand keeps a single kill switch. It must never gate a code identifier, package name, env var or CLI name. EXISTING identifiers stay `Augmented`/`agt` per the CLAUDE.md naming contract, which protects them from premature renaming \u2014 the deep rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here. That contract does NOT require NEW code to carry the old brand: artefacts created specifically for the rebrand take Ninjafy naming (ENG-8078 decision 9; see the CLAUDE.md rebrand carve-out). Either way it is a naming rule, not a flag concern \u2014 this key gates presentation, never an identifier. Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot a subset while everyone else still sees Augmented. Overrides resolve at FOUR grains, most specific first \u2014 agent, team, host, then org-wide (evaluate.ts:79-81); organization_id is always required, so there is no global override. Org and team are the useful pilot grains for THIS flag: there is now exactly ONE consumer \u2014 (dashboard)/layout.tsx via getPublicBooleanFlagServer \u2014 evaluating in the active-org cookie scope, so a host- or agent-scoped row is accepted by the table but never reached by the console. It resolves the key ONCE per request and passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop. Resolution is SERVER-side deliberately: the client hook starts at its default and updates after an async GET /flags, so anything gated on it paints Augmented and then repaints. ENG-8858 moved the PALETTE for that reason (a full-page colour flash); ENG-9227 moved the WORDMARK, which had been the last surface still swapping after hydration. A consequence worth knowing: /login and the marketing routes stay on the Augmented palette whatever an org sets, because getPublicBooleanFlagServer returns the default without a verified session and a pre-auth page has neither a session nor an active org \u2014 a PER-ORG flag structurally cannot brand one. Those surfaces follow only when the stage-wide default flips. Ships dark.',
38401
+ description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is the USER-FACING BRAND PRESENTATION \u2014 text AND VISUAL THEME. ENG-8858 widened this from text alone: the Ninjafy palette is gated here too, because a colour theme is not text. It stays ONE key rather than gaining a `ninjafy-theme` sibling, so a half-branded state \u2014 ninjafy wordmark over Augmented green \u2014 is unreachable and the rebrand keeps a single kill switch. It must never gate a code identifier, package name, env var or CLI name. EXISTING identifiers stay `Augmented`/`agt` per the CLAUDE.md naming contract, which protects them from premature renaming \u2014 the deep rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here. That contract does NOT require NEW code to carry the old brand: artefacts created specifically for the rebrand take Ninjafy naming (ENG-8078 decision 9; see the CLAUDE.md rebrand carve-out). Either way it is a naming rule, not a flag concern \u2014 this key gates presentation, never an identifier. Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot a subset while everyone else still sees Augmented. Overrides resolve at FOUR grains, most specific first \u2014 agent, team, host, then org-wide (evaluate.ts:79-81); organization_id is always required, so there is no global override. Org and team are the useful pilot grains for THIS flag: there is now exactly ONE consumer \u2014 (dashboard)/layout.tsx via getPublicBooleanFlagServer \u2014 evaluating in the active-org cookie scope, so a host- or agent-scoped row is accepted by the table but never reached by the console. It resolves the key ONCE per request and passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop. Resolution is SERVER-side deliberately: the client hook starts at its default and updates after an async GET /flags, so anything gated on it paints Augmented and then repaints. ENG-8858 moved the PALETTE for that reason (a full-page colour flash); ENG-9227 moved the WORDMARK, which had been the last surface still swapping after hydration. A consequence worth knowing: /login and the marketing routes stay on the Augmented palette whatever an org sets, because fetchPublicFlags returns null without a verified session and a pre-auth page has neither a session nor an active org \u2014 a PER-ORG flag structurally cannot brand one. ENG-9830 CORRECTS what used to be written here ("those surfaces follow only when the stage-wide default flips"): they do not follow it at all. Two reasons. The value returned on a null fetch is the CALL SITE\u2019s passed argument, not this registry default; and six such pages (/login, /reset-password, /auth/confirm, the pre-redeem member-signin gate and the two public Slack-install terminal pages) do not mount <BrandStamp/> AT ALL \u2014 deliberately, enumerated with per-page reasons in eng-9266-brand-stamp-coverage.test.ts. They become branded when the flag is REMOVED at cutover step 2 and the palette moves into bare :root, with no read left to gate it. NO LONGER DARK: ENG-9830 cutover step 1 flipped the default to true, so an org with no override now sees Ninjafy. The key survives only until cutover step 2 deletes it.',
38396
38402
  flagType: "boolean",
38397
- // Declared safe value is `false`: the pre-rebrand brand. `false` is also the
38398
- // fail-closed direction if the flag DB is unreachable we must show the brand
38399
- // that is currently live and contractually correct, never leak an unannounced
38400
- // rebrand to every customer at once.
38401
- defaultValue: false,
38403
+ // ENG-9830 (cutover step 1): flipped `false` -> `true`. The comment this
38404
+ // replaces argued `false` was the fail-closed direction "never leak an
38405
+ // UNANNOUNCED rebrand to every customer at once". That was correct for as
38406
+ // long as the rebrand was unannounced. It is not any more: Ninjafy is the
38407
+ // live, announced brand (ENG-9613 reconciled the console onto the master
38408
+ // assets while the flag was already ON in production), so `false` now points
38409
+ // at the brand we no longer ship. A flags outage that reverted a customer to
38410
+ // Augmented would be the incident, not the safe harbour.
38411
+ //
38412
+ // The old rationale is recorded rather than deleted because it is a correct
38413
+ // argument whose PREMISE expired — reading the change without it looks like
38414
+ // someone overriding a deliberate fail-closed default.
38415
+ //
38416
+ // NOTE this value is only consulted by the API evaluator when building the
38417
+ // `GET /flags` map for an org with no override. It is NOT the fallback the
38418
+ // webapp uses on an outage: `getPublicBooleanFlagServer(key, defaultValue)`
38419
+ // returns its own PASSED argument when the fetch fails, so the call sites in
38420
+ // (dashboard)/layout.tsx and components/brand-stamp.tsx carry `true` too.
38421
+ // Flipping only one of the two leaves the cutover half-applied.
38422
+ defaultValue: true,
38402
38423
  // ENG-9227: there are NO client readers of this key left. (dashboard)/
38403
38424
  // layout.tsx resolves it ONCE server-side via getPublicBooleanFlagServer and
38404
38425
  // passes the boolean down to sidebar.tsx and top-nav.tsx as a required prop.
38426
+ // "ONCE" is about the chrome, not the key: components/brand-stamp.tsx is a
38427
+ // SECOND, independent server read of `ninjafy-brand` (CodeRabbit, #5385).
38428
+ // Both are listed in the note above because both carry an outage fallback
38429
+ // that has to move together — reading this paragraph alone would leave you
38430
+ // updating one of the two.
38405
38431
  // ENG-8858 did that for the THEME; ENG-9227 finished the job for the
38406
38432
  // WORDMARK, which had kept usePublicBooleanFlag and so kept swapping
38407
38433
  // "augmented.team" to "ninjafy" after hydration.
@@ -38423,24 +38449,38 @@ var FLAG_REGISTRY = [
38423
38449
  },
38424
38450
  {
38425
38451
  key: "ninjafy-logo",
38426
- description: "Which Ninjafy logo TREATMENT the console chrome renders (ENG-9365). This is a SUB-SELECTION under ninjafy-brand, not a second brand gate: it is consulted only once ninjafy-brand has already resolved ON, so with the brand off the value is inert and the half-branded state that flag's description calls unreachable stays unreachable. ninjafy-brand remains the single kill switch for the rebrand. It exists so candidate logo treatments can be put in front of a human and compared in the running console, rather than judged from a static export. lockup = mark and wordmark together, both in the brand blue \u2014 exactly what ENG-9298 shipped, so an unset flag is a no-op. two-tone = the mark in brand blue with the wordmark in the neutral text colour (the treatment of the blue-icon/black-wordmark artwork). wordmark = the word alone, no mark. Every treatment is composed from the ENG-9298 geometry \u2014 ENG-9312 pins that the lockup's blue path IS the mark subpath followed by the wordmark subpaths, byte for byte \u2014 so a new treatment is a composition, never a fresh trace, and the three drawings cannot drift apart. Surfaces are the dashboard sidebar and the top nav. The top nav shows the WORDMARK portion at every width whatever the treatment, because ENG-9342 decided that deliberately (a full lockup at the header's icon height crowds the team switcher on a phone) \u2014 so a treatment changes the word's colour there, never whether a mark appears. The admin sidebar (ENG-9323) is NOT wired to this key and always renders the mark; widening it is a separate decision. Resolved SERVER-SIDE in (dashboard)/layout.tsx via getPublicEnumFlagServer, beside ninjafy-brand and in the same single GET /flags round trip, then passed down as a required prop. That is not a style preference: the client hook starts at its default and updates after an async fetch, so a client read would paint one logo and swap it after hydration \u2014 the exact flash ENG-9227 removed from the wordmark and ENG-8858 removed from the palette. Org and team are the useful pilot grains, as for ninjafy-brand: the single consumer evaluates in the active-org cookie scope, so a host- or agent-scoped override row is accepted by the table but never reached by the console.",
38452
+ description: "Which Ninjafy logo TREATMENT the console chrome renders (ENG-9365). This is a SUB-SELECTION under ninjafy-brand, not a second brand gate: it is consulted only once ninjafy-brand has already resolved ON, so with the brand off the value is inert and the half-branded state that flag's description calls unreachable stays unreachable. ninjafy-brand remains the single kill switch for the rebrand. It existed so candidate logo treatments could be put in front of a human and compared in the running console, rather than judged from a static export. That comparison has happened: ENG-9830 cutover step 1 chose TWO-TONE, so that is now the default and an unset flag renders it. NOTE this reverses the property this description used to claim \u2014 an unset flag was a no-op while the default was lockup (what ENG-9298 shipped), and that is deliberately given up at cutover: the default MOVING is the change. The key survives only until cutover step 2 hardcodes the chosen treatment and deletes it. lockup = mark and wordmark together, both in the brand blue \u2014 what ENG-9298 shipped. two-tone = the mark in brand blue with the wordmark in the neutral text colour (the treatment of the blue-icon/black-wordmark artwork); the chosen one. wordmark = the word alone, no mark. Every treatment is composed from the ENG-9298 geometry \u2014 ENG-9312 pins that the lockup's blue path IS the mark subpath followed by the wordmark subpaths, byte for byte \u2014 so a new treatment is a composition, never a fresh trace, and the three drawings cannot drift apart. Surfaces are the dashboard sidebar and the top nav. The top nav shows the WORDMARK portion at every width whatever the treatment, because ENG-9342 decided that deliberately (a full lockup at the header's icon height crowds the team switcher on a phone) \u2014 so a treatment changes the word's colour there, never whether a mark appears. The admin sidebar (ENG-9323) is NOT wired to this key and always renders the mark; widening it is a separate decision. Resolved SERVER-SIDE in (dashboard)/layout.tsx via getPublicEnumFlagServer, beside ninjafy-brand and in the same single GET /flags round trip, then passed down as a required prop. That is not a style preference: the client hook starts at its default and updates after an async fetch, so a client read would paint one logo and swap it after hydration \u2014 the exact flash ENG-9227 removed from the wordmark and ENG-8858 removed from the palette. Org and team are the useful pilot grains, as for ninjafy-brand: the single consumer evaluates in the active-org cookie scope, so a host- or agent-scoped override row is accepted by the table but never reached by the console.",
38427
38453
  flagType: "enum",
38428
38454
  allowedValues: ["lockup", "two-tone", "wordmark"],
38429
- // Declared safe value is `lockup` what ENG-9298 shipped. This flag has no
38430
- // "off" direction: it selects among presentations that are all live-safe, so
38431
- // fail-safe here means "the treatment currently in production", not the
38455
+ // ENG-9830 (cutover step 1): `lockup` -> `two-tone`. The treatments existed
38456
+ // so they could be compared in the running console rather than judged from a
38457
+ // static export (ENG-9365); that comparison has now happened and `two-tone`
38458
+ // — the mark in brand blue with the wordmark in the neutral text colour — is
38459
+ // the chosen treatment. It becomes the hardcoded one when this key is
38460
+ // removed at cutover step 2.
38461
+ //
38462
+ // The rule this value obeys is unchanged: this flag has no "off" direction,
38463
+ // so fail-safe means "the treatment currently in production", not the
38432
38464
  // narrowest one. A flag-DB read error, an archived row, or a stored value
38433
38465
  // outside allowedValues all resolve here (evaluate.ts normalizeFlagValue),
38434
- // which is what makes an experimental value impossible to strand.
38435
- defaultValue: "lockup",
38466
+ // which is what makes an experimental value impossible to strand. Only which
38467
+ // treatment holds that position has moved.
38468
+ //
38469
+ // Same split as ninjafy-brand above: this governs the API evaluation path
38470
+ // only. The webapp's outage fallback is the argument passed at the
38471
+ // (dashboard)/layout.tsx call site, which carries 'two-tone' to match.
38472
+ defaultValue: "two-tone",
38436
38473
  // Same trap as ninjafy-brand, and it bites harder here because there are no
38437
38474
  // client readers of this key AT ALL — it is server-resolved by construction.
38438
38475
  // `public` does NOT mean "read by a browser"; it means "readable through the
38439
38476
  // public map". getPublicEnumFlagServer resolves against the same GET /flags
38440
38477
  // endpoint the browser uses, and that route filters to listPublicFlagKeys()
38441
38478
  // (routes/flags.ts). Drop `public` and the key is simply absent from the map,
38442
- // so the helper falls through to its default and returns `lockup` FOREVER
38443
- // the dropdown appearing to do nothing, with no error raised anywhere.
38479
+ // so the helper falls through to the fallback passed at that call site and
38480
+ // returns it FOREVER — the dropdown appearing to do nothing, with no error
38481
+ // raised anywhere. Named as the call site rather than as a literal on
38482
+ // purpose: this comment said `lockup` for exactly as long as `lockup` was
38483
+ // the answer, and ENG-9830 flipping the winner is what made it a lie.
38444
38484
  public: true
38445
38485
  },
38446
38486
  {