@otto-assistant/bridge 0.4.97 → 0.4.101
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.
- package/dist/agent-model.e2e.test.js +7 -1
- package/dist/anthropic-auth-plugin.js +227 -176
- package/dist/cli-send-thread.e2e.test.js +4 -7
- package/dist/cli.js +2 -2
- package/dist/commands/login.js +6 -4
- package/dist/commands/screenshare.js +1 -1
- package/dist/commands/screenshare.test.js +2 -2
- package/dist/commands/vscode.js +269 -0
- package/dist/context-awareness-plugin.js +8 -38
- package/dist/db.js +1 -0
- package/dist/discord-command-registration.js +5 -0
- package/dist/gateway-proxy-reconnect.e2e.test.js +2 -2
- package/dist/interaction-handler.js +4 -0
- package/dist/kimaki-opencode-plugin.js +3 -1
- package/dist/memory-overview-plugin.js +126 -0
- package/dist/system-message.js +23 -22
- package/dist/system-message.test.js +23 -22
- package/dist/system-prompt-drift-plugin.js +41 -11
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/src/agent-model.e2e.test.ts +8 -1
- package/src/anthropic-auth-plugin.ts +574 -451
- package/src/cli-send-thread.e2e.test.ts +6 -7
- package/src/cli.ts +2 -2
- package/src/commands/login.ts +6 -4
- package/src/commands/screenshare.test.ts +2 -2
- package/src/commands/screenshare.ts +1 -1
- package/src/commands/vscode.ts +342 -0
- package/src/context-awareness-plugin.ts +11 -42
- package/src/db.ts +1 -0
- package/src/discord-command-registration.ts +7 -0
- package/src/gateway-proxy-reconnect.e2e.test.ts +2 -2
- package/src/interaction-handler.ts +5 -0
- package/src/kimaki-opencode-plugin.ts +3 -1
- package/src/memory-overview-plugin.ts +161 -0
- package/src/system-message.test.ts +23 -22
- package/src/system-message.ts +23 -22
- package/src/system-prompt-drift-plugin.ts +48 -12
- package/src/utils.ts +1 -1
package/dist/system-message.js
CHANGED
|
@@ -255,7 +255,7 @@ export function getOpencodeSystemMessage({ sessionId, channelId, guildId, thread
|
|
|
255
255
|
.join('\n')}`
|
|
256
256
|
: '';
|
|
257
257
|
return `
|
|
258
|
-
The user is reading your messages from inside Discord, via kimaki.
|
|
258
|
+
The user is reading your messages from inside Discord, via kimaki.dev
|
|
259
259
|
|
|
260
260
|
## bash tool
|
|
261
261
|
|
|
@@ -322,39 +322,40 @@ ${channelId
|
|
|
322
322
|
|
|
323
323
|
To start a new thread/session in this channel pro-grammatically, run:
|
|
324
324
|
|
|
325
|
-
kimaki send --channel ${channelId} --prompt "your prompt here"
|
|
325
|
+
kimaki send --channel ${channelId} --prompt "your prompt here" --agent <current_agent>${userArg}
|
|
326
326
|
|
|
327
327
|
You can use this to "spawn" parallel helper sessions like teammates: start new threads with focused prompts, then come back and collect the results.
|
|
328
|
+
Prefer passing the current agent with \`--agent <current_agent>\` so spawned or scheduled sessions keep the same agent unless you are intentionally switching. Replace \`<current_agent>\` with the value from the per-turn \`Current agent\` reminder.
|
|
328
329
|
|
|
329
330
|
IMPORTANT: NEVER use \`--worktree\` unless the user explicitly asks for a worktree. Default to creating normal threads without worktrees.
|
|
330
331
|
|
|
331
332
|
To send a prompt to an existing thread instead of creating a new one:
|
|
332
333
|
|
|
333
|
-
kimaki send --thread <thread_id> --prompt "follow-up prompt"
|
|
334
|
+
kimaki send --thread <thread_id> --prompt "follow-up prompt" --agent <current_agent>
|
|
334
335
|
|
|
335
336
|
Use this when you already have the Discord thread ID.
|
|
336
337
|
|
|
337
338
|
To send to the thread associated with a known session:
|
|
338
339
|
|
|
339
|
-
kimaki send --session <session_id> --prompt "follow-up prompt"
|
|
340
|
+
kimaki send --session <session_id> --prompt "follow-up prompt" --agent <current_agent>
|
|
340
341
|
|
|
341
342
|
Use this when you have the OpenCode session ID.
|
|
342
343
|
|
|
343
344
|
Use --notify-only to create a notification thread without starting an AI session:
|
|
344
345
|
|
|
345
|
-
kimaki send --channel ${channelId} --prompt "User cancelled subscription" --notify-only
|
|
346
|
+
kimaki send --channel ${channelId} --prompt "User cancelled subscription" --notify-only --agent <current_agent>${userArg}
|
|
346
347
|
|
|
347
348
|
Use --user to add a specific Discord user to the new thread:
|
|
348
349
|
|
|
349
|
-
kimaki send --channel ${channelId} --prompt "Review the latest CI failure"
|
|
350
|
+
kimaki send --channel ${channelId} --prompt "Review the latest CI failure" --agent <current_agent>${userArg}
|
|
350
351
|
|
|
351
352
|
Use --worktree to create a git worktree for the session (ONLY when the user explicitly asks for a worktree):
|
|
352
353
|
|
|
353
|
-
kimaki send --channel ${channelId} --prompt "Add dark mode support" --worktree dark-mode
|
|
354
|
+
kimaki send --channel ${channelId} --prompt "Add dark mode support" --worktree dark-mode --agent <current_agent>${userArg}
|
|
354
355
|
|
|
355
356
|
Use --cwd to start a session in an existing git worktree directory (must be a worktree of the project):
|
|
356
357
|
|
|
357
|
-
kimaki send --channel ${channelId} --prompt "Continue work on feature" --cwd /path/to/existing-worktree
|
|
358
|
+
kimaki send --channel ${channelId} --prompt "Continue work on feature" --cwd /path/to/existing-worktree --agent <current_agent>${userArg}
|
|
358
359
|
|
|
359
360
|
Important:
|
|
360
361
|
- NEVER use \`--worktree\` unless the user explicitly requests a worktree. Most tasks should use normal threads without worktrees.
|
|
@@ -372,8 +373,8 @@ ${availableAgentsContext}
|
|
|
372
373
|
|
|
373
374
|
You can trigger registered opencode commands (slash commands, skills, MCP prompts) by starting the \`--prompt\` with \`/commandname\`:
|
|
374
375
|
|
|
375
|
-
kimaki send --thread <thread_id> --prompt "/review fix the auth module"
|
|
376
|
-
kimaki send --channel ${channelId} --prompt "/build-cmd update dependencies"
|
|
376
|
+
kimaki send --thread <thread_id> --prompt "/review fix the auth module" --agent <current_agent>
|
|
377
|
+
kimaki send --channel ${channelId} --prompt "/build-cmd update dependencies" --agent <current_agent>${userArg}
|
|
377
378
|
|
|
378
379
|
The command name must match a registered opencode command. If the command is not recognized, the prompt is sent as plain text to the model. This works for both new threads (\`--channel\`) and existing threads (\`--thread\`/\`--session\`).
|
|
379
380
|
|
|
@@ -383,14 +384,14 @@ The user can switch the active agent mid-session using the Discord slash command
|
|
|
383
384
|
|
|
384
385
|
You can also switch agents via \`kimaki send\`:
|
|
385
386
|
|
|
386
|
-
kimaki send --thread <thread_id> --prompt "/<agentname>-agent"
|
|
387
|
+
kimaki send --thread <thread_id> --prompt "/<agentname>-agent" --agent <current_agent>
|
|
387
388
|
|
|
388
389
|
## scheduled sends and task management
|
|
389
390
|
|
|
390
391
|
Use \`--send-at\` to schedule a one-time or recurring task:
|
|
391
392
|
|
|
392
|
-
kimaki send --channel ${channelId} --prompt "Reminder: review open PRs" --send-at "2026-03-01T09:00:00Z"
|
|
393
|
-
kimaki send --channel ${channelId} --prompt "Run weekly test suite and summarize failures" --send-at "0 9 * * 1"
|
|
393
|
+
kimaki send --channel ${channelId} --prompt "Reminder: review open PRs" --send-at "2026-03-01T09:00:00Z" --agent <current_agent>${userArg}
|
|
394
|
+
kimaki send --channel ${channelId} --prompt "Run weekly test suite and summarize failures" --send-at "0 9 * * 1" --agent <current_agent>${userArg}
|
|
394
395
|
|
|
395
396
|
ALL scheduling is in UTC. Dates must be UTC ISO format ending with \`Z\`. Cron expressions also fire in UTC (e.g. \`0 9 * * 1\` means 9:00 UTC every Monday).
|
|
396
397
|
When the user specifies a time without a timezone, ask them to confirm their timezone or the UTC equivalent. Never guess the user's timezone.
|
|
@@ -424,13 +425,13 @@ kimaki task delete <id>
|
|
|
424
425
|
|
|
425
426
|
Use case patterns:
|
|
426
427
|
- Reminder flows: create deadline reminders in this channel with one-time \`--send-at\`; mention only if action is required.
|
|
427
|
-
- Proactive reminders: when you encounter time-sensitive information during your work (e.g. creating an API key that expires in 90 days, a certificate with an expiration date, a trial period ending, a deadline mentioned in code comments), proactively schedule a \`--notify-only\` reminder before the expiration so the user gets notified in time. For example, if you generate an API key expiring on 2026-06-01, schedule a reminder a few days before: \`kimaki send --channel ${channelId} --prompt "Reminder: <@USER_ID> the API key created on 2026-03-01 expires on 2026-06-01. Renew it before it breaks production." --send-at "2026-05-28T09:00:00Z" --notify-only
|
|
428
|
+
- Proactive reminders: when you encounter time-sensitive information during your work (e.g. creating an API key that expires in 90 days, a certificate with an expiration date, a trial period ending, a deadline mentioned in code comments), proactively schedule a \`--notify-only\` reminder before the expiration so the user gets notified in time. For example, if you generate an API key expiring on 2026-06-01, schedule a reminder a few days before: \`kimaki send --channel ${channelId} --prompt "Reminder: <@USER_ID> the API key created on 2026-03-01 expires on 2026-06-01. Renew it before it breaks production." --send-at "2026-05-28T09:00:00Z" --notify-only --agent <current_agent>\`. Always tell the user you scheduled the reminder so they know.
|
|
428
429
|
- Weekly QA: schedule "run full test suite, inspect failures, post summary, and mention @username only when failures require review".
|
|
429
430
|
- Weekly benchmark automation: schedule a benchmark prompt that runs model evals, writes JSON outputs in the repo, commits results, and mentions only for regressions.
|
|
430
431
|
- Recurring maintenance: use cron \`--send-at\` for repetitive tasks like rotating secrets, checking dependency updates, running security audits, or cleaning up stale branches. Example: \`--send-at "0 9 1 * *"\` to run on the 1st of every month.
|
|
431
432
|
- Thread reminders: when the user says "remind me about this in 2 hours" (or any duration), use \`--send-at\` with \`--thread\` to resurface the current thread. Compute the future UTC time and send a mention so Discord shows a notification:
|
|
432
433
|
|
|
433
|
-
kimaki send --session ${sessionId} --prompt "Reminder: <@USER_ID> you asked to be reminded about this thread." --send-at "<future_UTC_time>" --notify-only
|
|
434
|
+
kimaki send --session ${sessionId} --prompt "Reminder: <@USER_ID> you asked to be reminded about this thread." --send-at "<future_UTC_time>" --notify-only --agent <current_agent>
|
|
434
435
|
|
|
435
436
|
Replace \`<future_UTC_time>\` with the computed UTC ISO timestamp. The \`--notify-only\` flag creates just a notification message without starting a new AI session. The \`<@userId>\` mention ensures the user gets a Discord notification.
|
|
436
437
|
|
|
@@ -445,7 +446,7 @@ ONLY create worktrees when the user explicitly asks for one. Never proactively u
|
|
|
445
446
|
When the user asks to "create a worktree" or "make a worktree", they mean you should use the kimaki CLI to create it. Do NOT use raw \`git worktree add\` commands. Instead use:
|
|
446
447
|
|
|
447
448
|
\`\`\`bash
|
|
448
|
-
kimaki send --channel ${channelId} --prompt "your task description" --worktree worktree-name
|
|
449
|
+
kimaki send --channel ${channelId} --prompt "your task description" --worktree worktree-name --agent <current_agent>${userArg}
|
|
449
450
|
\`\`\`
|
|
450
451
|
|
|
451
452
|
This creates a new Discord thread with an isolated git worktree and starts a session in it. The worktree name should be kebab-case and descriptive of the task.
|
|
@@ -461,7 +462,7 @@ Critical recursion guard:
|
|
|
461
462
|
Use \`--cwd\` to start a session in an existing git worktree directory instead of creating a new one:
|
|
462
463
|
|
|
463
464
|
\`\`\`bash
|
|
464
|
-
kimaki send --channel ${channelId} --prompt "Continue work on feature X" --cwd /path/to/existing-worktree
|
|
465
|
+
kimaki send --channel ${channelId} --prompt "Continue work on feature X" --cwd /path/to/existing-worktree --agent <current_agent>${userArg}
|
|
465
466
|
\`\`\`
|
|
466
467
|
|
|
467
468
|
The path must be a git worktree of the project (validated via \`git worktree list\`). The session resolves to the correct project channel but uses the worktree as its working directory. Use \`--worktree\` to create a new worktree, \`--cwd\` to reuse an existing one.
|
|
@@ -475,7 +476,7 @@ This is useful for automation (cron jobs, GitHub webhooks, n8n, etc.)
|
|
|
475
476
|
When you are approaching the **context window limit** or the user explicitly asks to **handoff to a new thread**, use the \`kimaki send\` command to start a fresh session with context:
|
|
476
477
|
|
|
477
478
|
\`\`\`bash
|
|
478
|
-
kimaki send --channel ${channelId} --prompt "Continuing from previous session: <summary of current task and state>"
|
|
479
|
+
kimaki send --channel ${channelId} --prompt "Continuing from previous session: <summary of current task and state>" --agent <current_agent>${userArg}
|
|
479
480
|
\`\`\`
|
|
480
481
|
|
|
481
482
|
The command automatically handles long prompts (over 2000 chars) by sending them as file attachments.
|
|
@@ -533,10 +534,10 @@ To send a task to another project:
|
|
|
533
534
|
|
|
534
535
|
\`\`\`bash
|
|
535
536
|
# Send to a specific channel
|
|
536
|
-
kimaki send --channel <channel_id> --prompt "Plan how to update the API client to v2"
|
|
537
|
+
kimaki send --channel <channel_id> --prompt "Plan how to update the API client to v2" --agent <current_agent>
|
|
537
538
|
|
|
538
539
|
# Or use --project to resolve from directory
|
|
539
|
-
kimaki send --project /path/to/other-repo --prompt "Plan how to bump version to 1.2.0"
|
|
540
|
+
kimaki send --project /path/to/other-repo --prompt "Plan how to bump version to 1.2.0" --agent <current_agent>
|
|
540
541
|
\`\`\`
|
|
541
542
|
|
|
542
543
|
When sending prompts to other projects, always ask the agent to plan first, never build upfront. The prompt should start with "Plan how to ..." so the user can review before greenlighting implementation.
|
|
@@ -559,10 +560,10 @@ If your Bash tool timeout triggers anyway, fall back to reading the session outp
|
|
|
559
560
|
|
|
560
561
|
\`\`\`bash
|
|
561
562
|
# Start a session and wait for it to finish
|
|
562
|
-
kimaki send --channel <channel_id> --prompt "Fix the auth bug" --wait
|
|
563
|
+
kimaki send --channel <channel_id> --prompt "Fix the auth bug" --wait --agent <current_agent>
|
|
563
564
|
|
|
564
565
|
# Send to an existing thread and wait
|
|
565
|
-
kimaki send --thread <thread_id> --prompt "Run the tests" --wait
|
|
566
|
+
kimaki send --thread <thread_id> --prompt "Run the tests" --wait --agent <current_agent>
|
|
566
567
|
\`\`\`
|
|
567
568
|
|
|
568
569
|
The command exits with the session markdown on stdout once the model finishes responding.
|
|
@@ -16,7 +16,7 @@ describe('system-message', () => {
|
|
|
16
16
|
],
|
|
17
17
|
}).replace(/`[^`]*\/kimaki\.log`/, '`<data-dir>/kimaki.log`')).toMatchInlineSnapshot(`
|
|
18
18
|
"
|
|
19
|
-
The user is reading your messages from inside Discord, via kimaki.
|
|
19
|
+
The user is reading your messages from inside Discord, via kimaki.dev
|
|
20
20
|
|
|
21
21
|
## bash tool
|
|
22
22
|
|
|
@@ -85,39 +85,40 @@ describe('system-message', () => {
|
|
|
85
85
|
|
|
86
86
|
To start a new thread/session in this channel pro-grammatically, run:
|
|
87
87
|
|
|
88
|
-
kimaki send --channel chan_123 --prompt "your prompt here" --user "Tommy"
|
|
88
|
+
kimaki send --channel chan_123 --prompt "your prompt here" --agent <current_agent> --user "Tommy"
|
|
89
89
|
|
|
90
90
|
You can use this to "spawn" parallel helper sessions like teammates: start new threads with focused prompts, then come back and collect the results.
|
|
91
|
+
Prefer passing the current agent with \`--agent <current_agent>\` so spawned or scheduled sessions keep the same agent unless you are intentionally switching. Replace \`<current_agent>\` with the value from the per-turn \`Current agent\` reminder.
|
|
91
92
|
|
|
92
93
|
IMPORTANT: NEVER use \`--worktree\` unless the user explicitly asks for a worktree. Default to creating normal threads without worktrees.
|
|
93
94
|
|
|
94
95
|
To send a prompt to an existing thread instead of creating a new one:
|
|
95
96
|
|
|
96
|
-
kimaki send --thread <thread_id> --prompt "follow-up prompt"
|
|
97
|
+
kimaki send --thread <thread_id> --prompt "follow-up prompt" --agent <current_agent>
|
|
97
98
|
|
|
98
99
|
Use this when you already have the Discord thread ID.
|
|
99
100
|
|
|
100
101
|
To send to the thread associated with a known session:
|
|
101
102
|
|
|
102
|
-
kimaki send --session <session_id> --prompt "follow-up prompt"
|
|
103
|
+
kimaki send --session <session_id> --prompt "follow-up prompt" --agent <current_agent>
|
|
103
104
|
|
|
104
105
|
Use this when you have the OpenCode session ID.
|
|
105
106
|
|
|
106
107
|
Use --notify-only to create a notification thread without starting an AI session:
|
|
107
108
|
|
|
108
|
-
kimaki send --channel chan_123 --prompt "User cancelled subscription" --notify-only --user "Tommy"
|
|
109
|
+
kimaki send --channel chan_123 --prompt "User cancelled subscription" --notify-only --agent <current_agent> --user "Tommy"
|
|
109
110
|
|
|
110
111
|
Use --user to add a specific Discord user to the new thread:
|
|
111
112
|
|
|
112
|
-
kimaki send --channel chan_123 --prompt "Review the latest CI failure" --user "Tommy"
|
|
113
|
+
kimaki send --channel chan_123 --prompt "Review the latest CI failure" --agent <current_agent> --user "Tommy"
|
|
113
114
|
|
|
114
115
|
Use --worktree to create a git worktree for the session (ONLY when the user explicitly asks for a worktree):
|
|
115
116
|
|
|
116
|
-
kimaki send --channel chan_123 --prompt "Add dark mode support" --worktree dark-mode --user "Tommy"
|
|
117
|
+
kimaki send --channel chan_123 --prompt "Add dark mode support" --worktree dark-mode --agent <current_agent> --user "Tommy"
|
|
117
118
|
|
|
118
119
|
Use --cwd to start a session in an existing git worktree directory (must be a worktree of the project):
|
|
119
120
|
|
|
120
|
-
kimaki send --channel chan_123 --prompt "Continue work on feature" --cwd /path/to/existing-worktree --user "Tommy"
|
|
121
|
+
kimaki send --channel chan_123 --prompt "Continue work on feature" --cwd /path/to/existing-worktree --agent <current_agent> --user "Tommy"
|
|
121
122
|
|
|
122
123
|
Important:
|
|
123
124
|
- NEVER use \`--worktree\` unless the user explicitly requests a worktree. Most tasks should use normal threads without worktrees.
|
|
@@ -139,8 +140,8 @@ describe('system-message', () => {
|
|
|
139
140
|
|
|
140
141
|
You can trigger registered opencode commands (slash commands, skills, MCP prompts) by starting the \`--prompt\` with \`/commandname\`:
|
|
141
142
|
|
|
142
|
-
kimaki send --thread <thread_id> --prompt "/review fix the auth module"
|
|
143
|
-
kimaki send --channel chan_123 --prompt "/build-cmd update dependencies" --user "Tommy"
|
|
143
|
+
kimaki send --thread <thread_id> --prompt "/review fix the auth module" --agent <current_agent>
|
|
144
|
+
kimaki send --channel chan_123 --prompt "/build-cmd update dependencies" --agent <current_agent> --user "Tommy"
|
|
144
145
|
|
|
145
146
|
The command name must match a registered opencode command. If the command is not recognized, the prompt is sent as plain text to the model. This works for both new threads (\`--channel\`) and existing threads (\`--thread\`/\`--session\`).
|
|
146
147
|
|
|
@@ -150,14 +151,14 @@ describe('system-message', () => {
|
|
|
150
151
|
|
|
151
152
|
You can also switch agents via \`kimaki send\`:
|
|
152
153
|
|
|
153
|
-
kimaki send --thread <thread_id> --prompt "/<agentname>-agent"
|
|
154
|
+
kimaki send --thread <thread_id> --prompt "/<agentname>-agent" --agent <current_agent>
|
|
154
155
|
|
|
155
156
|
## scheduled sends and task management
|
|
156
157
|
|
|
157
158
|
Use \`--send-at\` to schedule a one-time or recurring task:
|
|
158
159
|
|
|
159
|
-
kimaki send --channel chan_123 --prompt "Reminder: review open PRs" --send-at "2026-03-01T09:00:00Z" --user "Tommy"
|
|
160
|
-
kimaki send --channel chan_123 --prompt "Run weekly test suite and summarize failures" --send-at "0 9 * * 1" --user "Tommy"
|
|
160
|
+
kimaki send --channel chan_123 --prompt "Reminder: review open PRs" --send-at "2026-03-01T09:00:00Z" --agent <current_agent> --user "Tommy"
|
|
161
|
+
kimaki send --channel chan_123 --prompt "Run weekly test suite and summarize failures" --send-at "0 9 * * 1" --agent <current_agent> --user "Tommy"
|
|
161
162
|
|
|
162
163
|
ALL scheduling is in UTC. Dates must be UTC ISO format ending with \`Z\`. Cron expressions also fire in UTC (e.g. \`0 9 * * 1\` means 9:00 UTC every Monday).
|
|
163
164
|
When the user specifies a time without a timezone, ask them to confirm their timezone or the UTC equivalent. Never guess the user's timezone.
|
|
@@ -191,13 +192,13 @@ describe('system-message', () => {
|
|
|
191
192
|
|
|
192
193
|
Use case patterns:
|
|
193
194
|
- Reminder flows: create deadline reminders in this channel with one-time \`--send-at\`; mention only if action is required.
|
|
194
|
-
- Proactive reminders: when you encounter time-sensitive information during your work (e.g. creating an API key that expires in 90 days, a certificate with an expiration date, a trial period ending, a deadline mentioned in code comments), proactively schedule a \`--notify-only\` reminder before the expiration so the user gets notified in time. For example, if you generate an API key expiring on 2026-06-01, schedule a reminder a few days before: \`kimaki send --channel chan_123 --prompt "Reminder: <@USER_ID> the API key created on 2026-03-01 expires on 2026-06-01. Renew it before it breaks production." --send-at "2026-05-28T09:00:00Z" --notify-only
|
|
195
|
+
- Proactive reminders: when you encounter time-sensitive information during your work (e.g. creating an API key that expires in 90 days, a certificate with an expiration date, a trial period ending, a deadline mentioned in code comments), proactively schedule a \`--notify-only\` reminder before the expiration so the user gets notified in time. For example, if you generate an API key expiring on 2026-06-01, schedule a reminder a few days before: \`kimaki send --channel chan_123 --prompt "Reminder: <@USER_ID> the API key created on 2026-03-01 expires on 2026-06-01. Renew it before it breaks production." --send-at "2026-05-28T09:00:00Z" --notify-only --agent <current_agent>\`. Always tell the user you scheduled the reminder so they know.
|
|
195
196
|
- Weekly QA: schedule "run full test suite, inspect failures, post summary, and mention @username only when failures require review".
|
|
196
197
|
- Weekly benchmark automation: schedule a benchmark prompt that runs model evals, writes JSON outputs in the repo, commits results, and mentions only for regressions.
|
|
197
198
|
- Recurring maintenance: use cron \`--send-at\` for repetitive tasks like rotating secrets, checking dependency updates, running security audits, or cleaning up stale branches. Example: \`--send-at "0 9 1 * *"\` to run on the 1st of every month.
|
|
198
199
|
- Thread reminders: when the user says "remind me about this in 2 hours" (or any duration), use \`--send-at\` with \`--thread\` to resurface the current thread. Compute the future UTC time and send a mention so Discord shows a notification:
|
|
199
200
|
|
|
200
|
-
kimaki send --session ses_123 --prompt "Reminder: <@USER_ID> you asked to be reminded about this thread." --send-at "<future_UTC_time>" --notify-only
|
|
201
|
+
kimaki send --session ses_123 --prompt "Reminder: <@USER_ID> you asked to be reminded about this thread." --send-at "<future_UTC_time>" --notify-only --agent <current_agent>
|
|
201
202
|
|
|
202
203
|
Replace \`<future_UTC_time>\` with the computed UTC ISO timestamp. The \`--notify-only\` flag creates just a notification message without starting a new AI session. The \`<@userId>\` mention ensures the user gets a Discord notification.
|
|
203
204
|
|
|
@@ -212,7 +213,7 @@ describe('system-message', () => {
|
|
|
212
213
|
When the user asks to "create a worktree" or "make a worktree", they mean you should use the kimaki CLI to create it. Do NOT use raw \`git worktree add\` commands. Instead use:
|
|
213
214
|
|
|
214
215
|
\`\`\`bash
|
|
215
|
-
kimaki send --channel chan_123 --prompt "your task description" --worktree worktree-name --user "Tommy"
|
|
216
|
+
kimaki send --channel chan_123 --prompt "your task description" --worktree worktree-name --agent <current_agent> --user "Tommy"
|
|
216
217
|
\`\`\`
|
|
217
218
|
|
|
218
219
|
This creates a new Discord thread with an isolated git worktree and starts a session in it. The worktree name should be kebab-case and descriptive of the task.
|
|
@@ -228,7 +229,7 @@ describe('system-message', () => {
|
|
|
228
229
|
Use \`--cwd\` to start a session in an existing git worktree directory instead of creating a new one:
|
|
229
230
|
|
|
230
231
|
\`\`\`bash
|
|
231
|
-
kimaki send --channel chan_123 --prompt "Continue work on feature X" --cwd /path/to/existing-worktree --user "Tommy"
|
|
232
|
+
kimaki send --channel chan_123 --prompt "Continue work on feature X" --cwd /path/to/existing-worktree --agent <current_agent> --user "Tommy"
|
|
232
233
|
\`\`\`
|
|
233
234
|
|
|
234
235
|
The path must be a git worktree of the project (validated via \`git worktree list\`). The session resolves to the correct project channel but uses the worktree as its working directory. Use \`--worktree\` to create a new worktree, \`--cwd\` to reuse an existing one.
|
|
@@ -242,7 +243,7 @@ describe('system-message', () => {
|
|
|
242
243
|
When you are approaching the **context window limit** or the user explicitly asks to **handoff to a new thread**, use the \`kimaki send\` command to start a fresh session with context:
|
|
243
244
|
|
|
244
245
|
\`\`\`bash
|
|
245
|
-
kimaki send --channel chan_123 --prompt "Continuing from previous session: <summary of current task and state>" --user "Tommy"
|
|
246
|
+
kimaki send --channel chan_123 --prompt "Continuing from previous session: <summary of current task and state>" --agent <current_agent> --user "Tommy"
|
|
246
247
|
\`\`\`
|
|
247
248
|
|
|
248
249
|
The command automatically handles long prompts (over 2000 chars) by sending them as file attachments.
|
|
@@ -300,10 +301,10 @@ describe('system-message', () => {
|
|
|
300
301
|
|
|
301
302
|
\`\`\`bash
|
|
302
303
|
# Send to a specific channel
|
|
303
|
-
kimaki send --channel <channel_id> --prompt "Plan how to update the API client to v2"
|
|
304
|
+
kimaki send --channel <channel_id> --prompt "Plan how to update the API client to v2" --agent <current_agent>
|
|
304
305
|
|
|
305
306
|
# Or use --project to resolve from directory
|
|
306
|
-
kimaki send --project /path/to/other-repo --prompt "Plan how to bump version to 1.2.0"
|
|
307
|
+
kimaki send --project /path/to/other-repo --prompt "Plan how to bump version to 1.2.0" --agent <current_agent>
|
|
307
308
|
\`\`\`
|
|
308
309
|
|
|
309
310
|
When sending prompts to other projects, always ask the agent to plan first, never build upfront. The prompt should start with "Plan how to ..." so the user can review before greenlighting implementation.
|
|
@@ -326,10 +327,10 @@ describe('system-message', () => {
|
|
|
326
327
|
|
|
327
328
|
\`\`\`bash
|
|
328
329
|
# Start a session and wait for it to finish
|
|
329
|
-
kimaki send --channel <channel_id> --prompt "Fix the auth bug" --wait
|
|
330
|
+
kimaki send --channel <channel_id> --prompt "Fix the auth bug" --wait --agent <current_agent>
|
|
330
331
|
|
|
331
332
|
# Send to an existing thread and wait
|
|
332
|
-
kimaki send --thread <thread_id> --prompt "Run the tests" --wait
|
|
333
|
+
kimaki send --thread <thread_id> --prompt "Run the tests" --wait --agent <current_agent>
|
|
333
334
|
\`\`\`
|
|
334
335
|
|
|
335
336
|
The command exits with the session markdown on stdout once the model finishes responding.
|
|
@@ -70,7 +70,6 @@ function writeSystemPromptDiffFile({ dataDir, sessionId, beforePrompt, afterProm
|
|
|
70
70
|
const timestamp = new Date().toISOString().replaceAll(':', '-');
|
|
71
71
|
const sessionDir = path.join(getSystemPromptDiffDir({ dataDir }), sessionId);
|
|
72
72
|
const filePath = path.join(sessionDir, `${timestamp}.diff`);
|
|
73
|
-
const latestPromptPath = path.join(sessionDir, `${timestamp}.md`);
|
|
74
73
|
const fileContent = [
|
|
75
74
|
`Session: ${sessionId}`,
|
|
76
75
|
`Created: ${new Date().toISOString()}`,
|
|
@@ -88,7 +87,6 @@ function writeSystemPromptDiffFile({ dataDir, sessionId, beforePrompt, afterProm
|
|
|
88
87
|
additions: diff.additions,
|
|
89
88
|
deletions: diff.deletions,
|
|
90
89
|
filePath,
|
|
91
|
-
latestPromptPath,
|
|
92
90
|
};
|
|
93
91
|
},
|
|
94
92
|
catch: (error) => {
|
|
@@ -109,6 +107,7 @@ function getOrCreateSessionState({ sessions, sessionId, }) {
|
|
|
109
107
|
comparedTurn: 0,
|
|
110
108
|
previousTurnContext: undefined,
|
|
111
109
|
currentTurnContext: undefined,
|
|
110
|
+
pendingCompareTimeout: undefined,
|
|
112
111
|
};
|
|
113
112
|
sessions.set(sessionId, state);
|
|
114
113
|
return state;
|
|
@@ -162,8 +161,7 @@ async function handleSystemTransform({ input, output, sessions, dataDir, client,
|
|
|
162
161
|
message: appendToastSessionMarker({
|
|
163
162
|
sessionId,
|
|
164
163
|
message: `system prompt changed since the previous message (+${diffFileResult.additions} / -${diffFileResult.deletions}). ` +
|
|
165
|
-
`Diff: \`${abbreviatePath(diffFileResult.filePath)}\`. `
|
|
166
|
-
`Latest prompt: \`${abbreviatePath(diffFileResult.latestPromptPath)}\``,
|
|
164
|
+
`Diff: \`${abbreviatePath(diffFileResult.filePath)}\`. `
|
|
167
165
|
}),
|
|
168
166
|
},
|
|
169
167
|
});
|
|
@@ -193,13 +191,41 @@ const systemPromptDriftPlugin = async ({ client, directory }) => {
|
|
|
193
191
|
'experimental.chat.system.transform': async (input, output) => {
|
|
194
192
|
const result = await errore.tryAsync({
|
|
195
193
|
try: async () => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
194
|
+
const sessionId = input.sessionID;
|
|
195
|
+
if (!sessionId) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const state = getOrCreateSessionState({ sessions, sessionId });
|
|
199
|
+
if (state.pendingCompareTimeout) {
|
|
200
|
+
clearTimeout(state.pendingCompareTimeout);
|
|
201
|
+
}
|
|
202
|
+
// Delay one tick so other system-transform hooks can finish mutating
|
|
203
|
+
// output.system before we snapshot it for drift detection.
|
|
204
|
+
state.pendingCompareTimeout = setTimeout(() => {
|
|
205
|
+
state.pendingCompareTimeout = undefined;
|
|
206
|
+
void errore.tryAsync({
|
|
207
|
+
try: async () => {
|
|
208
|
+
await handleSystemTransform({
|
|
209
|
+
input,
|
|
210
|
+
output,
|
|
211
|
+
sessions,
|
|
212
|
+
dataDir,
|
|
213
|
+
client,
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
catch: (error) => {
|
|
217
|
+
return new Error('system prompt drift transform hook failed', {
|
|
218
|
+
cause: error,
|
|
219
|
+
});
|
|
220
|
+
},
|
|
221
|
+
}).then((delayedResult) => {
|
|
222
|
+
if (!(delayedResult instanceof Error)) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
logger.warn(`[system-prompt-drift-plugin] ${formatPluginErrorWithStack(delayedResult)}`);
|
|
226
|
+
void notifyError(delayedResult, 'system prompt drift plugin transform hook failed');
|
|
227
|
+
});
|
|
228
|
+
}, 0);
|
|
203
229
|
},
|
|
204
230
|
catch: (error) => {
|
|
205
231
|
return new Error('system prompt drift transform hook failed', {
|
|
@@ -222,6 +248,10 @@ const systemPromptDriftPlugin = async ({ client, directory }) => {
|
|
|
222
248
|
if (!deletedSessionId) {
|
|
223
249
|
return;
|
|
224
250
|
}
|
|
251
|
+
const state = sessions.get(deletedSessionId);
|
|
252
|
+
if (state?.pendingCompareTimeout) {
|
|
253
|
+
clearTimeout(state.pendingCompareTimeout);
|
|
254
|
+
}
|
|
225
255
|
sessions.delete(deletedSessionId);
|
|
226
256
|
},
|
|
227
257
|
catch: (error) => {
|
package/dist/utils.js
CHANGED
|
@@ -50,7 +50,7 @@ export function generateBotInstallUrl({ clientId, permissions = [
|
|
|
50
50
|
return url.toString();
|
|
51
51
|
}
|
|
52
52
|
export const KIMAKI_GATEWAY_APP_ID = process.env.KIMAKI_GATEWAY_APP_ID || '1477605701202481173';
|
|
53
|
-
export const KIMAKI_WEBSITE_URL = process.env.KIMAKI_WEBSITE_URL || 'https://kimaki.
|
|
53
|
+
export const KIMAKI_WEBSITE_URL = process.env.KIMAKI_WEBSITE_URL || 'https://kimaki.dev';
|
|
54
54
|
export function generateDiscordInstallUrlForBot({ appId, mode, clientId, clientSecret, gatewayCallbackUrl, reachableUrl, }) {
|
|
55
55
|
if (mode !== 'gateway') {
|
|
56
56
|
return generateBotInstallUrl({ clientId: appId });
|
package/package.json
CHANGED
|
@@ -542,7 +542,14 @@ describe('agent model resolution', () => {
|
|
|
542
542
|
afterAuthorId: discord.botUserId,
|
|
543
543
|
})
|
|
544
544
|
|
|
545
|
-
|
|
545
|
+
const threadText = (await discord.thread(thread.id).text())
|
|
546
|
+
.split('\n')
|
|
547
|
+
.filter((line) => {
|
|
548
|
+
return !line.startsWith('⬦ info: Context cache discarded:')
|
|
549
|
+
})
|
|
550
|
+
.join('\n')
|
|
551
|
+
|
|
552
|
+
expect(threadText).toMatchInlineSnapshot(`
|
|
546
553
|
"--- from: user (agent-model-tester)
|
|
547
554
|
first message in thread
|
|
548
555
|
Reply with exactly: reply-context-check
|