shraga 0.0.3 → 0.1.1

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 (180) hide show
  1. package/README.md +82 -23
  2. package/defaults/agents/summarizer.md +16 -0
  3. package/defaults/agents/trace-extractor.md +84 -0
  4. package/defaults/bin/claude +45 -0
  5. package/defaults/bin/claude-revive +17 -0
  6. package/defaults/extensions/README.md +70 -0
  7. package/defaults/extensions/selftest.ext.ts +43 -0
  8. package/defaults/extensions/stripe-webhook.ext.ts +58 -0
  9. package/defaults/gmail-triage-prompt.md +42 -0
  10. package/defaults/scripts/README +4 -0
  11. package/defaults/scripts/agent-once.ts +67 -0
  12. package/defaults/scripts/backfill-slack-usernames.ts +82 -0
  13. package/defaults/scripts/notifier-throttle.ts +44 -0
  14. package/defaults/scripts/summarize-conversations.ts +5 -0
  15. package/defaults/shraga.config.ts +29 -0
  16. package/defaults/skills/add-skill.md +14 -0
  17. package/defaults/skills/artifacts.md +116 -0
  18. package/defaults/skills/code-review.md +26 -0
  19. package/defaults/skills/communications.md +54 -0
  20. package/defaults/skills/context-audit.md +87 -0
  21. package/defaults/skills/debug.md +10 -0
  22. package/defaults/skills/garden.md +179 -0
  23. package/defaults/skills/github-contributor.md +35 -0
  24. package/defaults/skills/identity.md +30 -0
  25. package/defaults/skills/mcp-server.md +62 -0
  26. package/defaults/skills/mcps-sync.md +105 -0
  27. package/defaults/skills/plan.md +9 -0
  28. package/defaults/skills/platform.md +177 -0
  29. package/defaults/skills/reconcile.md +239 -0
  30. package/defaults/skills/scheduler.md +192 -0
  31. package/defaults/skills/self-aware.md +136 -0
  32. package/defaults/skills/shraga-know.md +333 -0
  33. package/defaults/skills/stripe.md +55 -0
  34. package/defaults/skills/write-tests.md +10 -0
  35. package/defaults/skills-defaults.json +1 -0
  36. package/defaults/system-prompt.md +46 -0
  37. package/defaults/workspace/context.md +28 -0
  38. package/defaults/workspace.md +50 -0
  39. package/defaults/zdotdir/.gitignore +8 -0
  40. package/defaults/zdotdir/.zlogin +3 -0
  41. package/defaults/zdotdir/.zprofile +1 -0
  42. package/defaults/zdotdir/.zshenv +4 -0
  43. package/defaults/zdotdir/.zshrc +3 -0
  44. package/dist/client/assets/index-BoHttkMt.js +1940 -0
  45. package/dist/client/assets/index-DdibEb2O.css +10 -0
  46. package/dist/client/index.html +22 -0
  47. package/package.json +59 -14
  48. package/src/cli.ts +71 -46
  49. package/src/client/App.tsx +510 -0
  50. package/src/client/components/ArtifactCard.tsx +26 -0
  51. package/src/client/components/ArtifactPanel.tsx +138 -0
  52. package/src/client/components/AuthedImage.tsx +85 -0
  53. package/src/client/components/AutocompleteTextarea.tsx +149 -0
  54. package/src/client/components/ChatView.tsx +866 -0
  55. package/src/client/components/CliAuthConsent.tsx +98 -0
  56. package/src/client/components/ConfigPanel.tsx +328 -0
  57. package/src/client/components/ConversationHeader.tsx +156 -0
  58. package/src/client/components/ConversationPane.tsx +277 -0
  59. package/src/client/components/LoginPage.tsx +81 -0
  60. package/src/client/components/MachineStats.tsx +77 -0
  61. package/src/client/components/McpManager.tsx +209 -0
  62. package/src/client/components/MessageInput.tsx +263 -0
  63. package/src/client/components/OAuthConsent.tsx +103 -0
  64. package/src/client/components/SchedulesManager.tsx +99 -0
  65. package/src/client/components/Sidebar.tsx +235 -0
  66. package/src/client/components/SkillsManager.tsx +280 -0
  67. package/src/client/components/SmartChart.tsx +167 -0
  68. package/src/client/components/Toast.tsx +54 -0
  69. package/src/client/components/WorkspaceTree.tsx +313 -0
  70. package/src/client/components/ZoomableImage.tsx +123 -0
  71. package/src/client/components/artifact-presets.ts +10 -0
  72. package/src/client/components/schedules/ScheduleEditor.tsx +264 -0
  73. package/src/client/components/schedules/ScheduleList.tsx +271 -0
  74. package/src/client/components/ui/accordion.tsx +50 -0
  75. package/src/client/components/ui/button.tsx +43 -0
  76. package/src/client/components/ui/dialog.tsx +82 -0
  77. package/src/client/components/ui/input.tsx +19 -0
  78. package/src/client/components/ui/scroll-area.tsx +39 -0
  79. package/src/client/components/ui/textarea.tsx +18 -0
  80. package/src/client/globals.css +51 -0
  81. package/src/client/hooks/useAgentSocket.ts +79 -0
  82. package/src/client/hooks/useArtifacts.ts +89 -0
  83. package/src/client/hooks/useAuth.ts +127 -0
  84. package/src/client/hooks/useConversation.ts +412 -0
  85. package/src/client/hooks/useDarkMode.ts +57 -0
  86. package/src/client/hooks/useIsMobile.ts +23 -0
  87. package/src/client/hooks/usePush.ts +127 -0
  88. package/src/client/hooks/useSchedules.ts +73 -0
  89. package/src/client/hooks/useUnread.ts +238 -0
  90. package/src/client/lib/desktopAttention.ts +75 -0
  91. package/src/client/lib/firebase.ts +32 -0
  92. package/src/client/lib/googleAuthNative.ts +94 -0
  93. package/src/client/lib/native.ts +43 -0
  94. package/src/client/lib/schedule-types.ts +34 -0
  95. package/src/client/lib/sessionApi.ts +58 -0
  96. package/src/client/lib/slots.tsx +79 -0
  97. package/src/client/lib/storage.ts +39 -0
  98. package/src/client/lib/utils.ts +26 -0
  99. package/src/client/lib/workspaceContext.tsx +54 -0
  100. package/src/client/lib/ws.ts +203 -0
  101. package/src/client/main.tsx +14 -0
  102. package/src/mcp-stdio-bridge.ts +70 -0
  103. package/src/scripts/summarize-conversations.ts +5 -0
  104. package/src/scripts/typecheck.ts +43 -0
  105. package/src/server/agents.ts +54 -0
  106. package/src/server/api-keys.ts +63 -0
  107. package/src/server/artifacts/artifacts.export.ts +85 -0
  108. package/src/server/artifacts/artifacts.handler.ts +93 -0
  109. package/src/server/artifacts/artifacts.routes.ts +43 -0
  110. package/src/server/artifacts/artifacts.service.ts +100 -0
  111. package/src/server/artifacts/artifacts.types.ts +31 -0
  112. package/src/server/auth.ts +262 -0
  113. package/src/server/claude.ts +394 -0
  114. package/src/server/commands.ts +21 -0
  115. package/src/server/contacts.ts +177 -0
  116. package/src/server/conversation-summarizer.ts +204 -0
  117. package/src/server/data-sync.ts +664 -0
  118. package/src/server/directives.ts +91 -0
  119. package/src/server/engine/claude-code.ts +514 -0
  120. package/src/server/engine/index.ts +41 -0
  121. package/src/server/engine/registry.ts +21 -0
  122. package/src/server/engine/shared.ts +47 -0
  123. package/src/server/engine/types.ts +48 -0
  124. package/src/server/env-resolve.ts +71 -0
  125. package/src/server/env-sanitize.ts +9 -0
  126. package/src/server/events/bus.ts +29 -0
  127. package/src/server/events/dispatcher.ts +48 -0
  128. package/src/server/events/routes.ts +19 -0
  129. package/src/server/events/types.ts +9 -0
  130. package/src/server/extensions.ts +101 -0
  131. package/src/server/features.ts +109 -0
  132. package/src/server/file-inject.ts +45 -0
  133. package/src/server/hooks.ts +142 -0
  134. package/src/server/idempotency.ts +25 -0
  135. package/src/server/index.ts +1715 -0
  136. package/src/server/integrity-audit.ts +132 -0
  137. package/src/server/mcp-catalog.ts +70 -0
  138. package/src/server/mcp-oauth.ts +198 -0
  139. package/src/server/mcp-progress.ts +45 -0
  140. package/src/server/mcp-server.ts +456 -0
  141. package/src/server/mcp-sidecar.ts +87 -0
  142. package/src/server/mcp.ts +291 -0
  143. package/src/server/model-aliases.ts +76 -0
  144. package/src/server/paths.ts +24 -0
  145. package/src/server/polls.ts +175 -0
  146. package/src/server/push/apns.ts +113 -0
  147. package/src/server/push/fcm.ts +108 -0
  148. package/src/server/push/push.ts +66 -0
  149. package/src/server/push/store.ts +84 -0
  150. package/src/server/push/triggers.ts +99 -0
  151. package/src/server/scheduler/builtins.ts +157 -0
  152. package/src/server/scheduler/engine.ts +432 -0
  153. package/src/server/scheduler/index.ts +4 -0
  154. package/src/server/scheduler/runner.ts +334 -0
  155. package/src/server/scheduler/storage.ts +98 -0
  156. package/src/server/scheduler/timing.ts +70 -0
  157. package/src/server/scheduler/types.ts +62 -0
  158. package/src/server/sdk-utils.ts +45 -0
  159. package/src/server/seed.ts +174 -0
  160. package/src/server/session-bus.ts +18 -0
  161. package/src/server/sessions.ts +559 -0
  162. package/src/server/shraga-config.ts +167 -0
  163. package/src/server/skills.ts +372 -0
  164. package/src/server/slack/api.ts +37 -0
  165. package/src/server/slack/bot.ts +391 -0
  166. package/src/server/slack/context-cache.ts +42 -0
  167. package/src/server/slack/feature.ts +59 -0
  168. package/src/server/slack/mention-rewrite.ts +59 -0
  169. package/src/server/slack/oauth.ts +102 -0
  170. package/src/server/slack/questions.ts +112 -0
  171. package/src/server/slack/sessions.ts +139 -0
  172. package/src/server/stats.ts +106 -0
  173. package/src/server/summarize.ts +11 -0
  174. package/src/server/turn-context.ts +61 -0
  175. package/src/server/unclaw-config.ts +19 -0
  176. package/src/server/unread.ts +79 -0
  177. package/src/server/user-context.ts +33 -0
  178. package/src/server/vendor-sync.ts +52 -0
  179. package/src/server/voice-provider.ts +74 -0
  180. package/src/server/workspace.ts +249 -0
@@ -0,0 +1,142 @@
1
+ /**
2
+ * SDK hooks — PreToolUse / PostToolUse callbacks wired into query().
3
+ *
4
+ * Hooks intercept tool calls inside the Claude Code CLI subprocess.
5
+ * Unlike `canUseTool` (permission gate), hooks can modify input, inject
6
+ * context, and guide model behavior through denial reasons.
7
+ */
8
+ import type { HookCallback, HookCallbackMatcher, HookEvent, PreToolUseHookInput } from '@anthropic-ai/claude-agent-sdk';
9
+ import { rewriteSlackMentions } from './slack/mention-rewrite.ts';
10
+
11
+ /** Patterns that indicate a long-running script the model should background. */
12
+ const LONG_RUNNING_PATTERNS = [
13
+ /\bdata\/scripts\//,
14
+ ];
15
+
16
+ /**
17
+ * Deny foreground Bash calls matching known long-running patterns.
18
+ * The denial reason tells the model to retry with `run_in_background: true`,
19
+ * which lets the CLI manage the process asynchronously (the model can
20
+ * continue working and gets notified when the command finishes).
21
+ */
22
+ const forceBackgroundForScripts: HookCallback = async (input) => {
23
+ if (input.hook_event_name !== 'PreToolUse') return {};
24
+ const { tool_name, tool_input } = input as PreToolUseHookInput;
25
+ if (tool_name !== 'Bash') return {};
26
+
27
+ const ti = tool_input as Record<string, unknown>;
28
+ const cmd = ti.command as string | undefined;
29
+ if (!cmd || ti.run_in_background) return {};
30
+
31
+ const isLongRunning = LONG_RUNNING_PATTERNS.some(p => p.test(cmd));
32
+ if (!isLongRunning) return {};
33
+
34
+ console.log(`[hooks] Denying foreground Bash for long-running script: ${cmd.slice(0, 120)}`);
35
+ return {
36
+ hookSpecificOutput: {
37
+ hookEventName: 'PreToolUse' as const,
38
+ permissionDecision: 'deny' as const,
39
+ permissionDecisionReason:
40
+ 'This script may take several minutes. Use run_in_background: true so you can continue working while it runs.',
41
+ },
42
+ };
43
+ };
44
+
45
+ /**
46
+ * Text fields per Slack MCP tool that may carry `@name` prose the agent typed.
47
+ * (Not `post_slack_poll` — its options are structured labels, not mention prose.)
48
+ */
49
+ const SLACK_MENTION_FIELDS: Record<string, string[]> = {
50
+ post_slack_message: ['text'],
51
+ post_slack_update: ['text'],
52
+ post_slack_reply: ['text'],
53
+ post_slack_files: ['initial_comment'],
54
+ };
55
+
56
+ /**
57
+ * Rewrite human-readable `@name (operator)` / `@name` display strings in
58
+ * outbound Slack text back into real `<@U…>` mention tokens, so mentions the
59
+ * agent typed from its readable context actually fire a notification.
60
+ * Closes the inbound/outbound asymmetry (resolveUserMentions has no reverse).
61
+ */
62
+ const resolveSlackMentions: HookCallback = async (input) => {
63
+ if (input.hook_event_name !== 'PreToolUse') return {};
64
+ const { tool_name, tool_input } = input as PreToolUseHookInput;
65
+ const m = /^mcp__mcp-slack__(post_slack_\w+)$/.exec(tool_name);
66
+ if (!m) return {};
67
+ const fields = SLACK_MENTION_FIELDS[m[1]];
68
+ if (!fields) return {};
69
+
70
+ const ti = { ...(tool_input as Record<string, unknown>) };
71
+ let changed = false;
72
+ for (const f of fields) {
73
+ const val = ti[f];
74
+ if (typeof val !== 'string') continue;
75
+ const r = rewriteSlackMentions(val);
76
+ if (r.changed) { ti[f] = r.text; changed = true; }
77
+ }
78
+ if (!changed) return {};
79
+
80
+ console.log(`[hooks] Resolved @name display strings to <@U…> mention tokens in ${tool_name}`);
81
+ return {
82
+ hookSpecificOutput: {
83
+ hookEventName: 'PreToolUse' as const,
84
+ updatedInput: ti,
85
+ },
86
+ };
87
+ };
88
+
89
+ /**
90
+ * Guardrail for the AGF Firebase RTDB MCPs. The `agf-rtdb` skill's rules only bind
91
+ * the model when that skill is loaded — but it auto-injects only on a trigger match,
92
+ * so a query phrased without the trigger vocabulary (e.g. "the currently alive room")
93
+ * leaves the model flying blind. It then does the exact thing Rule #1 forbids:
94
+ * `get_db path=agf` (or `agf/session`) → a whole-DB read that errors `too_big` / hangs.
95
+ * This deny is a HARD backstop independent of phrasing or the model remembering: block
96
+ * the two dangerous shapes and hand back the corrective recipe + a pointer to the skill.
97
+ */
98
+ const FIREBASE_HUGE_PATHS = new Set(['', 'agf', 'agf/session']);
99
+ const norm = (p: unknown) => String(p ?? '').trim().replace(/^\/+|\/+$/g, '');
100
+
101
+ const guardFirebaseReads: HookCallback = async (input) => {
102
+ if (input.hook_event_name !== 'PreToolUse') return {};
103
+ const { tool_name, tool_input } = input as PreToolUseHookInput;
104
+ const m = /^mcp__mcp-firebase-(?:prod|lab)__(get_db|get_db_keys|get_db_query)$/.exec(tool_name);
105
+ if (!m) return {};
106
+ const method = m[1];
107
+ const ti = tool_input as Record<string, unknown>;
108
+ const path = norm(ti.path);
109
+
110
+ let reason: string | null = null;
111
+ // Rule #1: full-value read of a HUGE node. (get_db_keys is keys-only → safe even on agf.)
112
+ if (method === 'get_db' && FIREBASE_HUGE_PATHS.has(path)) {
113
+ reason = `Blocked: get_db on "${path || '/'}" reads the whole node — it errors too_big / hangs (agf-rtdb skill Rule #1: never read /agf or /agf/session directly). ` +
114
+ `For the currently-active session(s): get_db_query path=agf/session orderBy="timing/status" equalTo="Active" limitToFirst=10 (status is Capitalized + case-sensitive). ` +
115
+ `Then drill into small sub-paths (…/timing, …/participantsActivity, …/speakers) — never the full session node. Read data/skills/agf-rtdb.md for the full recipes.`;
116
+ } else if (method === 'get_db_query' && !norm(ti.orderBy)) {
117
+ // Rule #2: query without orderBy pulls the whole node first.
118
+ reason = `Blocked: get_db_query without orderBy pulls the entire node before filtering (agf-rtdb skill Rule #2). ` +
119
+ `Add an INDEXED orderBy: on agf/session use "timing/status" or "timing/startTime"; any push-keyed list uses "$key". Read data/skills/agf-rtdb.md for indexed fields.`;
120
+ }
121
+ if (!reason) return {};
122
+
123
+ console.log(`[hooks] Firebase guardrail blocked ${tool_name} path="${path}" — steering to agf-rtdb skill`);
124
+ return {
125
+ hookSpecificOutput: {
126
+ hookEventName: 'PreToolUse' as const,
127
+ permissionDecision: 'deny' as const,
128
+ permissionDecisionReason: reason,
129
+ },
130
+ };
131
+ };
132
+
133
+ /** Build the hooks map to pass into SDK query() options. */
134
+ export function buildHooks(): Partial<Record<HookEvent, HookCallbackMatcher[]>> {
135
+ return {
136
+ PreToolUse: [
137
+ { matcher: 'Bash', hooks: [forceBackgroundForScripts] },
138
+ { matcher: 'mcp__mcp-slack__post_slack_.*', hooks: [resolveSlackMentions] },
139
+ { matcher: 'mcp__mcp-firebase-(?:prod|lab)__get_db.*', hooks: [guardFirebaseReads] },
140
+ ],
141
+ };
142
+ }
@@ -0,0 +1,25 @@
1
+ // In-memory idempotency for chat turns. Maps a caller-supplied request id to the
2
+ // sessionId that first handled it, so a retried submit (e.g. after an MCP client
3
+ // timeout) reuses the running session instead of spawning a duplicate.
4
+ // TTL-scoped: keys expire after the window, so the same id is reusable later.
5
+
6
+ const TTL_MS = 15 * 60 * 1000; // 15 min
7
+
8
+ type Entry = { sessionId: string; ts: number };
9
+ const store = new Map<string, Entry>();
10
+
11
+ const mapKey = (uid: string, key: string) => `${uid}::${key}`;
12
+
13
+ /** Returns the sessionId previously bound to (uid, key) if still within TTL, else null. */
14
+ export function lookupIdempotent(uid: string, key: string): string | null {
15
+ const k = mapKey(uid, key);
16
+ const e = store.get(k);
17
+ if (!e) return null;
18
+ if (Date.now() - e.ts > TTL_MS) { store.delete(k); return null; }
19
+ return e.sessionId;
20
+ }
21
+
22
+ /** Binds (uid, key) → sessionId for the TTL window. */
23
+ export function rememberIdempotent(uid: string, key: string, sessionId: string): void {
24
+ store.set(mapKey(uid, key), { sessionId, ts: Date.now() });
25
+ }