reflectt-node 0.1.8 → 0.1.12
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/defaults/TEAM-ROLES.yaml +317 -5
- package/dist/agent-config.d.ts +51 -0
- package/dist/agent-config.d.ts.map +1 -0
- package/dist/agent-config.js +129 -0
- package/dist/agent-config.js.map +1 -0
- package/dist/agent-config.test.d.ts +2 -0
- package/dist/agent-config.test.d.ts.map +1 -0
- package/dist/agent-config.test.js +91 -0
- package/dist/agent-config.test.js.map +1 -0
- package/dist/agent-memories.d.ts +58 -0
- package/dist/agent-memories.d.ts.map +1 -0
- package/dist/agent-memories.js +168 -0
- package/dist/agent-memories.js.map +1 -0
- package/dist/agent-memories.test.d.ts +2 -0
- package/dist/agent-memories.test.d.ts.map +1 -0
- package/dist/agent-memories.test.js +327 -0
- package/dist/agent-memories.test.js.map +1 -0
- package/dist/agent-messaging.d.ts +50 -0
- package/dist/agent-messaging.d.ts.map +1 -0
- package/dist/agent-messaging.js +103 -0
- package/dist/agent-messaging.js.map +1 -0
- package/dist/agent-messaging.test.d.ts +2 -0
- package/dist/agent-messaging.test.d.ts.map +1 -0
- package/dist/agent-messaging.test.js +105 -0
- package/dist/agent-messaging.test.js.map +1 -0
- package/dist/agent-runs.d.ts +158 -0
- package/dist/agent-runs.d.ts.map +1 -0
- package/dist/agent-runs.js +514 -0
- package/dist/agent-runs.js.map +1 -0
- package/dist/agent-runs.test.d.ts +2 -0
- package/dist/agent-runs.test.d.ts.map +1 -0
- package/dist/agent-runs.test.js +386 -0
- package/dist/agent-runs.test.js.map +1 -0
- package/dist/approval-queue.test.d.ts +2 -0
- package/dist/approval-queue.test.d.ts.map +1 -0
- package/dist/approval-queue.test.js +118 -0
- package/dist/approval-queue.test.js.map +1 -0
- package/dist/artifact-store.d.ts +55 -0
- package/dist/artifact-store.d.ts.map +1 -0
- package/dist/artifact-store.js +128 -0
- package/dist/artifact-store.js.map +1 -0
- package/dist/artifact-store.test.d.ts +2 -0
- package/dist/artifact-store.test.d.ts.map +1 -0
- package/dist/artifact-store.test.js +119 -0
- package/dist/artifact-store.test.js.map +1 -0
- package/dist/boardHealthWorker.d.ts +28 -0
- package/dist/boardHealthWorker.d.ts.map +1 -1
- package/dist/boardHealthWorker.js +33 -1
- package/dist/boardHealthWorker.js.map +1 -1
- package/dist/canvas-input.test.d.ts +2 -0
- package/dist/canvas-input.test.d.ts.map +1 -0
- package/dist/canvas-input.test.js +96 -0
- package/dist/canvas-input.test.js.map +1 -0
- package/dist/canvas-render.test.d.ts +2 -0
- package/dist/canvas-render.test.d.ts.map +1 -0
- package/dist/canvas-render.test.js +95 -0
- package/dist/canvas-render.test.js.map +1 -0
- package/dist/capabilities/browser.d.ts +75 -0
- package/dist/capabilities/browser.d.ts.map +1 -0
- package/dist/capabilities/browser.js +172 -0
- package/dist/capabilities/browser.js.map +1 -0
- package/dist/channels.d.ts +1 -1
- package/dist/cli.js +4 -2
- package/dist/cli.js.map +1 -1
- package/dist/cloud.d.ts +2 -0
- package/dist/cloud.d.ts.map +1 -1
- package/dist/cloud.js +135 -3
- package/dist/cloud.js.map +1 -1
- package/dist/cost-enforcement.d.ts +38 -0
- package/dist/cost-enforcement.d.ts.map +1 -0
- package/dist/cost-enforcement.js +84 -0
- package/dist/cost-enforcement.js.map +1 -0
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/dashboard.js +8 -0
- package/dist/dashboard.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +131 -0
- package/dist/db.js.map +1 -1
- package/dist/e2e-loop-proof.test.d.ts +2 -0
- package/dist/e2e-loop-proof.test.d.ts.map +1 -0
- package/dist/e2e-loop-proof.test.js +104 -0
- package/dist/e2e-loop-proof.test.js.map +1 -0
- package/dist/email-sms-send.test.d.ts +2 -0
- package/dist/email-sms-send.test.d.ts.map +1 -0
- package/dist/email-sms-send.test.js +96 -0
- package/dist/email-sms-send.test.js.map +1 -0
- package/dist/events.d.ts +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +2 -0
- package/dist/events.js.map +1 -1
- package/dist/fingerprint.d.ts.map +1 -1
- package/dist/fingerprint.js +5 -10
- package/dist/fingerprint.js.map +1 -1
- package/dist/github-webhook-chat.d.ts +75 -0
- package/dist/github-webhook-chat.d.ts.map +1 -0
- package/dist/github-webhook-chat.js +108 -0
- package/dist/github-webhook-chat.js.map +1 -0
- package/dist/handoff-state.test.d.ts +2 -0
- package/dist/handoff-state.test.d.ts.map +1 -0
- package/dist/handoff-state.test.js +102 -0
- package/dist/handoff-state.test.js.map +1 -0
- package/dist/health.d.ts +9 -0
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +18 -0
- package/dist/health.js.map +1 -1
- package/dist/host-error-correlation.d.ts +65 -0
- package/dist/host-error-correlation.d.ts.map +1 -0
- package/dist/host-error-correlation.js +123 -0
- package/dist/host-error-correlation.js.map +1 -0
- package/dist/index.js +39 -10
- package/dist/index.js.map +1 -1
- package/dist/notificationDedupeGuard.d.ts +4 -0
- package/dist/notificationDedupeGuard.d.ts.map +1 -1
- package/dist/notificationDedupeGuard.js +8 -4
- package/dist/notificationDedupeGuard.js.map +1 -1
- package/dist/presence.d.ts +37 -5
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js +127 -16
- package/dist/presence.js.map +1 -1
- package/dist/review-sla.d.ts +9 -0
- package/dist/review-sla.d.ts.map +1 -0
- package/dist/review-sla.js +51 -0
- package/dist/review-sla.js.map +1 -0
- package/dist/routing-enforcement.test.d.ts +2 -0
- package/dist/routing-enforcement.test.d.ts.map +1 -0
- package/dist/routing-enforcement.test.js +86 -0
- package/dist/routing-enforcement.test.js.map +1 -0
- package/dist/run-retention.test.d.ts +2 -0
- package/dist/run-retention.test.d.ts.map +1 -0
- package/dist/run-retention.test.js +57 -0
- package/dist/run-retention.test.js.map +1 -0
- package/dist/run-stream.test.d.ts +2 -0
- package/dist/run-stream.test.d.ts.map +1 -0
- package/dist/run-stream.test.js +70 -0
- package/dist/run-stream.test.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1301 -75
- package/dist/server.js.map +1 -1
- package/dist/tasks.d.ts.map +1 -1
- package/dist/tasks.js +45 -0
- package/dist/tasks.js.map +1 -1
- package/dist/todoHoardingGuard.d.ts +17 -0
- package/dist/todoHoardingGuard.d.ts.map +1 -1
- package/dist/todoHoardingGuard.js +25 -2
- package/dist/todoHoardingGuard.js.map +1 -1
- package/dist/webhook-storage.d.ts +50 -0
- package/dist/webhook-storage.d.ts.map +1 -0
- package/dist/webhook-storage.js +102 -0
- package/dist/webhook-storage.js.map +1 -0
- package/dist/webhook-storage.test.d.ts +2 -0
- package/dist/webhook-storage.test.d.ts.map +1 -0
- package/dist/webhook-storage.test.js +86 -0
- package/dist/webhook-storage.test.js.map +1 -0
- package/dist/workflow-templates.d.ts +44 -0
- package/dist/workflow-templates.d.ts.map +1 -0
- package/dist/workflow-templates.js +154 -0
- package/dist/workflow-templates.js.map +1 -0
- package/dist/workflow-templates.test.d.ts +2 -0
- package/dist/workflow-templates.test.d.ts.map +1 -0
- package/dist/workflow-templates.test.js +76 -0
- package/dist/workflow-templates.test.js.map +1 -0
- package/package.json +3 -1
- package/public/dashboard.js +76 -1
- package/public/design-tokens-platform.md +118 -0
- package/public/design-tokens.css +195 -0
- package/public/docs.md +131 -2
- package/public/presence-loop-demo.html +473 -0
package/defaults/TEAM-ROLES.yaml
CHANGED
|
@@ -236,25 +236,332 @@ agents:
|
|
|
236
236
|
- brand-copy
|
|
237
237
|
wipCap: 1
|
|
238
238
|
|
|
239
|
+
- name: cos
|
|
240
|
+
role: chief-of-staff
|
|
241
|
+
description: Alignment and escalation router. Maintains decision log, tracks who owes what by when, packages escalations, prevents thrash. No final product/design decisions.
|
|
242
|
+
affinityTags:
|
|
243
|
+
- alignment
|
|
244
|
+
- escalation
|
|
245
|
+
- decisions
|
|
246
|
+
- process
|
|
247
|
+
- coordination
|
|
248
|
+
- strategy
|
|
249
|
+
routingMode: opt-in
|
|
250
|
+
neverRouteUnlessLane: alignment
|
|
251
|
+
alwaysRoute:
|
|
252
|
+
- alignment
|
|
253
|
+
- escalation
|
|
254
|
+
- process
|
|
255
|
+
neverRoute:
|
|
256
|
+
- backend
|
|
257
|
+
- frontend
|
|
258
|
+
- ui
|
|
259
|
+
- design
|
|
260
|
+
- security-review
|
|
261
|
+
- code-review
|
|
262
|
+
wipCap: 2
|
|
263
|
+
|
|
264
|
+
- name: coo
|
|
265
|
+
role: operations
|
|
266
|
+
description: Board execution, lane health, and ops monitoring. Owns board hygiene, task gate enforcement, EOD signal generation, SOUL.md patch cycle.
|
|
267
|
+
affinityTags:
|
|
268
|
+
- ops
|
|
269
|
+
- board-health
|
|
270
|
+
- lane-health
|
|
271
|
+
- monitoring
|
|
272
|
+
- execution
|
|
273
|
+
- watchdog
|
|
274
|
+
routingMode: opt-in
|
|
275
|
+
neverRouteUnlessLane: ops
|
|
276
|
+
alwaysRoute:
|
|
277
|
+
- ops
|
|
278
|
+
- board-health
|
|
279
|
+
- execution
|
|
280
|
+
neverRoute:
|
|
281
|
+
- backend
|
|
282
|
+
- frontend
|
|
283
|
+
- ui
|
|
284
|
+
- design
|
|
285
|
+
wipCap: 2
|
|
286
|
+
|
|
287
|
+
- name: pm
|
|
288
|
+
role: product-manager
|
|
289
|
+
description: Product spec, acceptance criteria, lane metrics, and shipping reports. Translates business goals into scoped tasks.
|
|
290
|
+
affinityTags:
|
|
291
|
+
- product
|
|
292
|
+
- spec
|
|
293
|
+
- ac
|
|
294
|
+
- reporting
|
|
295
|
+
- metrics
|
|
296
|
+
- prioritization
|
|
297
|
+
routingMode: opt-in
|
|
298
|
+
neverRouteUnlessLane: product
|
|
299
|
+
alwaysRoute:
|
|
300
|
+
- product
|
|
301
|
+
- spec
|
|
302
|
+
- reporting
|
|
303
|
+
neverRoute:
|
|
304
|
+
- backend
|
|
305
|
+
- ui
|
|
306
|
+
- security-review
|
|
307
|
+
wipCap: 2
|
|
308
|
+
|
|
309
|
+
- name: qa
|
|
310
|
+
role: quality
|
|
311
|
+
description: Regression testing, audit checklists, mobile QA, and test coverage validation.
|
|
312
|
+
affinityTags:
|
|
313
|
+
- qa
|
|
314
|
+
- testing
|
|
315
|
+
- regression
|
|
316
|
+
- audit
|
|
317
|
+
- checklist
|
|
318
|
+
- coverage
|
|
319
|
+
- mobile-qa
|
|
320
|
+
alwaysRoute:
|
|
321
|
+
- qa
|
|
322
|
+
- testing
|
|
323
|
+
- regression
|
|
324
|
+
neverRoute:
|
|
325
|
+
- brand-copy
|
|
326
|
+
- marketing
|
|
327
|
+
wipCap: 2
|
|
328
|
+
|
|
329
|
+
- name: swift
|
|
330
|
+
role: ios-engineer
|
|
331
|
+
description: iOS app development — Swift/SwiftUI, TestFlight pipeline, Apple Watch companion, App Store submission.
|
|
332
|
+
affinityTags:
|
|
333
|
+
- ios
|
|
334
|
+
- swift
|
|
335
|
+
- swiftui
|
|
336
|
+
- testflight
|
|
337
|
+
- apple
|
|
338
|
+
- watchos
|
|
339
|
+
- mobile
|
|
340
|
+
alwaysRoute:
|
|
341
|
+
- ios
|
|
342
|
+
- swift
|
|
343
|
+
- apple
|
|
344
|
+
neverRoute:
|
|
345
|
+
- android
|
|
346
|
+
- backend
|
|
347
|
+
- design
|
|
348
|
+
wipCap: 2
|
|
349
|
+
|
|
350
|
+
- name: kotlin
|
|
351
|
+
role: android-engineer
|
|
352
|
+
description: Android app development — Kotlin, Play Store submission, Firebase integration, CI/CD pipeline.
|
|
353
|
+
affinityTags:
|
|
354
|
+
- android
|
|
355
|
+
- kotlin
|
|
356
|
+
- play-store
|
|
357
|
+
- firebase
|
|
358
|
+
- mobile
|
|
359
|
+
- gradle
|
|
360
|
+
alwaysRoute:
|
|
361
|
+
- android
|
|
362
|
+
- kotlin
|
|
363
|
+
- play-store
|
|
364
|
+
neverRoute:
|
|
365
|
+
- ios
|
|
366
|
+
- backend
|
|
367
|
+
- design
|
|
368
|
+
wipCap: 2
|
|
369
|
+
|
|
370
|
+
- name: shield
|
|
371
|
+
role: security
|
|
372
|
+
description: Security audits — RLS policy review, IDOR checks, rate limiting, env var hygiene, Vercel config.
|
|
373
|
+
affinityTags:
|
|
374
|
+
- security
|
|
375
|
+
- rls
|
|
376
|
+
- audit
|
|
377
|
+
- idor
|
|
378
|
+
- rate-limiting
|
|
379
|
+
- env
|
|
380
|
+
- compliance
|
|
381
|
+
alwaysRoute:
|
|
382
|
+
- security
|
|
383
|
+
- rls
|
|
384
|
+
- security-review
|
|
385
|
+
neverRoute:
|
|
386
|
+
- brand-copy
|
|
387
|
+
- marketing
|
|
388
|
+
- design
|
|
389
|
+
protectedDomains:
|
|
390
|
+
- security
|
|
391
|
+
wipCap: 1
|
|
392
|
+
|
|
393
|
+
- name: artdirector
|
|
394
|
+
role: art-director
|
|
395
|
+
description: Visual design direction — host detail pages, design specs, screenshot audits, mobile layout direction.
|
|
396
|
+
affinityTags:
|
|
397
|
+
- design
|
|
398
|
+
- visual
|
|
399
|
+
- layout
|
|
400
|
+
- art-direction
|
|
401
|
+
- spec
|
|
402
|
+
- mockup
|
|
403
|
+
routingMode: opt-in
|
|
404
|
+
neverRouteUnlessLane: design
|
|
405
|
+
alwaysRoute:
|
|
406
|
+
- art-direction
|
|
407
|
+
- design-spec
|
|
408
|
+
neverRoute:
|
|
409
|
+
- backend
|
|
410
|
+
- security-review
|
|
411
|
+
- code-review
|
|
412
|
+
wipCap: 1
|
|
413
|
+
|
|
414
|
+
- name: uipolish
|
|
415
|
+
role: ui-polisher
|
|
416
|
+
description: Frontend polish — mobile layout fixes, density improvements, empty states, scroll affordances, visual regressions.
|
|
417
|
+
affinityTags:
|
|
418
|
+
- ui
|
|
419
|
+
- polish
|
|
420
|
+
- mobile
|
|
421
|
+
- css
|
|
422
|
+
- layout
|
|
423
|
+
- visual
|
|
424
|
+
- frontend
|
|
425
|
+
alwaysRoute:
|
|
426
|
+
- ui-polish
|
|
427
|
+
- visual-polish
|
|
428
|
+
- mobile
|
|
429
|
+
neverRoute:
|
|
430
|
+
- backend
|
|
431
|
+
- security-review
|
|
432
|
+
- api
|
|
433
|
+
wipCap: 2
|
|
434
|
+
|
|
435
|
+
- name: kindling
|
|
436
|
+
role: community
|
|
437
|
+
description: Community engagement — Discord posts, UTM tracking, community onboarding content.
|
|
438
|
+
affinityTags:
|
|
439
|
+
- community
|
|
440
|
+
- discord
|
|
441
|
+
- utm
|
|
442
|
+
- onboarding-content
|
|
443
|
+
- social
|
|
444
|
+
routingMode: opt-in
|
|
445
|
+
neverRouteUnlessLane: community
|
|
446
|
+
alwaysRoute:
|
|
447
|
+
- community
|
|
448
|
+
- discord
|
|
449
|
+
neverRoute:
|
|
450
|
+
- backend
|
|
451
|
+
- security-review
|
|
452
|
+
- code-review
|
|
453
|
+
wipCap: 1
|
|
454
|
+
|
|
455
|
+
- name: quill
|
|
456
|
+
role: writer
|
|
457
|
+
description: Long-form content — dev.to articles, changelogs, shipping summaries, community posts.
|
|
458
|
+
affinityTags:
|
|
459
|
+
- writing
|
|
460
|
+
- content
|
|
461
|
+
- changelog
|
|
462
|
+
- blog
|
|
463
|
+
- devto
|
|
464
|
+
- community-post
|
|
465
|
+
routingMode: opt-in
|
|
466
|
+
neverRouteUnlessLane: content
|
|
467
|
+
alwaysRoute:
|
|
468
|
+
- writing
|
|
469
|
+
- changelog
|
|
470
|
+
- blog
|
|
471
|
+
neverRoute:
|
|
472
|
+
- backend
|
|
473
|
+
- security-review
|
|
474
|
+
- code-review
|
|
475
|
+
- ui
|
|
476
|
+
wipCap: 1
|
|
477
|
+
|
|
478
|
+
- name: funnel
|
|
479
|
+
role: growth-funnel
|
|
480
|
+
description: Conversion funnel optimization — install drop-off fixes, onboarding UX, PATH guidance, curl installer.
|
|
481
|
+
affinityTags:
|
|
482
|
+
- funnel
|
|
483
|
+
- conversion
|
|
484
|
+
- install
|
|
485
|
+
- onboarding
|
|
486
|
+
- growth
|
|
487
|
+
- drop-off
|
|
488
|
+
alwaysRoute:
|
|
489
|
+
- funnel
|
|
490
|
+
- install
|
|
491
|
+
- onboarding-ux
|
|
492
|
+
neverRoute:
|
|
493
|
+
- security-review
|
|
494
|
+
- backend-infra
|
|
495
|
+
wipCap: 1
|
|
496
|
+
|
|
497
|
+
- name: attribution
|
|
498
|
+
role: analytics
|
|
499
|
+
description: Cost and attribution analytics — cost dashboards, spend alerts, model effectiveness tracking, UTM attribution.
|
|
500
|
+
affinityTags:
|
|
501
|
+
- analytics
|
|
502
|
+
- cost
|
|
503
|
+
- attribution
|
|
504
|
+
- spend
|
|
505
|
+
- reporting
|
|
506
|
+
- dashboard
|
|
507
|
+
- metrics
|
|
508
|
+
alwaysRoute:
|
|
509
|
+
- analytics
|
|
510
|
+
- cost-tracking
|
|
511
|
+
- attribution
|
|
512
|
+
neverRoute:
|
|
513
|
+
- security-review
|
|
514
|
+
- brand-copy
|
|
515
|
+
wipCap: 1
|
|
516
|
+
|
|
239
517
|
# Removed agent-1/2/3 fallback entries — were leaking into dashboard as ghost agents
|
|
240
518
|
|
|
519
|
+
# Decision authority — what the team owns vs. what requires a human
|
|
520
|
+
# This section survives cold-start and new installs.
|
|
521
|
+
# Agents reading this on first boot should NOT default to Ryan for decisions in the team-decides list.
|
|
522
|
+
decision_authority:
|
|
523
|
+
team_decides:
|
|
524
|
+
- Product feature scope and prioritization (P0/P1/P2/P3 assignment)
|
|
525
|
+
- Architecture and technical decisions (API shape, data model, infra choices)
|
|
526
|
+
- Pricing tier structure and copy
|
|
527
|
+
- PR merges within approved feature scope
|
|
528
|
+
- Task creation, assignment, reassignment, and cancellation
|
|
529
|
+
- Agent role definitions and team composition changes
|
|
530
|
+
- API spend thresholds and monitoring rules
|
|
531
|
+
- Design, UX, and content decisions
|
|
532
|
+
- Marketing copy, social posts, and community messaging
|
|
533
|
+
- Internal process decisions (SOUL.md patches, PROGRAM.md updates, TEAM-STANDARDS.md)
|
|
534
|
+
- Review approvals and rejections
|
|
535
|
+
- Budget allocation between work streams (within overall investment context)
|
|
536
|
+
- Continuity loop configuration and agent protocols
|
|
537
|
+
escalate_to_human:
|
|
538
|
+
- External credentials and secrets (Apple Developer enrollment, Play Console, API keys, OAuth tokens)
|
|
539
|
+
- Legal agreements, terms of service, and compliance sign-offs
|
|
540
|
+
- Founder vision conflicts or major strategic pivots (e.g., changing the core product direction)
|
|
541
|
+
- Privacy policy content and publication (requires human approval before going live)
|
|
542
|
+
- External service account creation requiring identity verification (app store developer accounts)
|
|
543
|
+
- Any decision where a mistake could cause irreversible public harm or legal liability
|
|
544
|
+
escalation_channel: cloud app task assignment or email — never #general chat @mention
|
|
545
|
+
note: When in doubt, make the call. A reversible decision made by the team beats a correct decision that
|
|
546
|
+
waits for Ryan. Escalate only when the decision is genuinely irreversible or legally significant.
|
|
547
|
+
|
|
241
548
|
# Lane definitions for ready-queue engine.
|
|
242
549
|
# Each lane groups agents into a work stream with floor + WIP controls.
|
|
243
550
|
# readyFloor — minimum unblocked todo tasks per agent before sweeper fires
|
|
244
551
|
# wipLimit — max simultaneous doing tasks per agent (/tasks/next enforces this)
|
|
245
552
|
lanes:
|
|
246
553
|
- name: engineering
|
|
247
|
-
agents: [link]
|
|
554
|
+
agents: [link, swift, kotlin]
|
|
248
555
|
readyFloor: 2
|
|
249
556
|
wipLimit: 2
|
|
250
557
|
|
|
251
558
|
- name: design
|
|
252
|
-
agents: [pixel]
|
|
559
|
+
agents: [pixel, artdirector, uipolish]
|
|
253
560
|
readyFloor: 1
|
|
254
561
|
wipLimit: 1
|
|
255
562
|
|
|
256
563
|
- name: operations
|
|
257
|
-
agents: [sage, rhythm]
|
|
564
|
+
agents: [sage, rhythm, coo, cos, pm, qa]
|
|
258
565
|
readyFloor: 1
|
|
259
566
|
wipLimit: 1
|
|
260
567
|
|
|
@@ -264,11 +571,16 @@ lanes:
|
|
|
264
571
|
wipLimit: 1
|
|
265
572
|
|
|
266
573
|
- name: growth
|
|
267
|
-
agents: [spark]
|
|
574
|
+
agents: [spark, funnel, attribution]
|
|
268
575
|
readyFloor: 1
|
|
269
576
|
wipLimit: 1
|
|
270
577
|
|
|
271
578
|
- name: content
|
|
272
|
-
agents: [echo]
|
|
579
|
+
agents: [echo, quill, kindling]
|
|
580
|
+
readyFloor: 1
|
|
581
|
+
wipLimit: 1
|
|
582
|
+
|
|
583
|
+
- name: security
|
|
584
|
+
agents: [shield]
|
|
273
585
|
readyFloor: 1
|
|
274
586
|
wipLimit: 1
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface AgentConfig {
|
|
2
|
+
agentId: string;
|
|
3
|
+
teamId: string;
|
|
4
|
+
model: string | null;
|
|
5
|
+
fallbackModel: string | null;
|
|
6
|
+
costCapDaily: number | null;
|
|
7
|
+
costCapMonthly: number | null;
|
|
8
|
+
maxTokensPerCall: number | null;
|
|
9
|
+
settings: Record<string, unknown>;
|
|
10
|
+
createdAt: number;
|
|
11
|
+
updatedAt: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get config for a specific agent. Returns null if not set.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAgentConfig(agentId: string): AgentConfig | null;
|
|
17
|
+
/**
|
|
18
|
+
* List all agent configs, optionally filtered by team.
|
|
19
|
+
*/
|
|
20
|
+
export declare function listAgentConfigs(opts?: {
|
|
21
|
+
teamId?: string;
|
|
22
|
+
}): AgentConfig[];
|
|
23
|
+
/**
|
|
24
|
+
* Set (upsert) config for an agent.
|
|
25
|
+
*/
|
|
26
|
+
export declare function setAgentConfig(agentId: string, updates: {
|
|
27
|
+
teamId?: string;
|
|
28
|
+
model?: string | null;
|
|
29
|
+
fallbackModel?: string | null;
|
|
30
|
+
costCapDaily?: number | null;
|
|
31
|
+
costCapMonthly?: number | null;
|
|
32
|
+
maxTokensPerCall?: number | null;
|
|
33
|
+
settings?: Record<string, unknown>;
|
|
34
|
+
}): AgentConfig;
|
|
35
|
+
/**
|
|
36
|
+
* Delete config for an agent.
|
|
37
|
+
*/
|
|
38
|
+
export declare function deleteAgentConfig(agentId: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Check if an agent is within its cost cap.
|
|
41
|
+
* Returns { allowed, remaining, cap, spent, action } for the cost enforcement hook.
|
|
42
|
+
*/
|
|
43
|
+
export declare function checkCostCap(agentId: string, currentDailySpend: number, currentMonthlySpend: number): {
|
|
44
|
+
allowed: boolean;
|
|
45
|
+
dailyRemaining: number | null;
|
|
46
|
+
monthlyRemaining: number | null;
|
|
47
|
+
action: 'allow' | 'warn' | 'downgrade' | 'deny';
|
|
48
|
+
model: string | null;
|
|
49
|
+
fallbackModel: string | null;
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=agent-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-config.d.ts","sourceRoot":"","sources":["../src/agent-config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AA8BD;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAIlE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,EAAE,CAQ1E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;IACvD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC,GAAG,WAAW,CAwCd;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAI1D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,GAAG;IACrG,OAAO,EAAE,OAAO,CAAA;IAChB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAA;IAC/C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B,CAwCA"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Agent configuration API — model preference + cost cap per agent
|
|
3
|
+
import { getDb } from './db.js';
|
|
4
|
+
function rowToConfig(row) {
|
|
5
|
+
return {
|
|
6
|
+
agentId: row.agent_id,
|
|
7
|
+
teamId: row.team_id,
|
|
8
|
+
model: row.model,
|
|
9
|
+
fallbackModel: row.fallback_model,
|
|
10
|
+
costCapDaily: row.cost_cap_daily,
|
|
11
|
+
costCapMonthly: row.cost_cap_monthly,
|
|
12
|
+
maxTokensPerCall: row.max_tokens_per_call,
|
|
13
|
+
settings: JSON.parse(row.settings || '{}'),
|
|
14
|
+
createdAt: row.created_at,
|
|
15
|
+
updatedAt: row.updated_at,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get config for a specific agent. Returns null if not set.
|
|
20
|
+
*/
|
|
21
|
+
export function getAgentConfig(agentId) {
|
|
22
|
+
const db = getDb();
|
|
23
|
+
const row = db.prepare('SELECT * FROM agent_config WHERE agent_id = ?').get(agentId);
|
|
24
|
+
return row ? rowToConfig(row) : null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* List all agent configs, optionally filtered by team.
|
|
28
|
+
*/
|
|
29
|
+
export function listAgentConfigs(opts) {
|
|
30
|
+
const db = getDb();
|
|
31
|
+
if (opts?.teamId) {
|
|
32
|
+
const rows = db.prepare('SELECT * FROM agent_config WHERE team_id = ? ORDER BY agent_id').all(opts.teamId);
|
|
33
|
+
return rows.map(rowToConfig);
|
|
34
|
+
}
|
|
35
|
+
const rows = db.prepare('SELECT * FROM agent_config ORDER BY agent_id').all();
|
|
36
|
+
return rows.map(rowToConfig);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Set (upsert) config for an agent.
|
|
40
|
+
*/
|
|
41
|
+
export function setAgentConfig(agentId, updates) {
|
|
42
|
+
const db = getDb();
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
const existing = getAgentConfig(agentId);
|
|
45
|
+
if (existing) {
|
|
46
|
+
// Update
|
|
47
|
+
const model = updates.model !== undefined ? updates.model : existing.model;
|
|
48
|
+
const fallbackModel = updates.fallbackModel !== undefined ? updates.fallbackModel : existing.fallbackModel;
|
|
49
|
+
const costCapDaily = updates.costCapDaily !== undefined ? updates.costCapDaily : existing.costCapDaily;
|
|
50
|
+
const costCapMonthly = updates.costCapMonthly !== undefined ? updates.costCapMonthly : existing.costCapMonthly;
|
|
51
|
+
const maxTokensPerCall = updates.maxTokensPerCall !== undefined ? updates.maxTokensPerCall : existing.maxTokensPerCall;
|
|
52
|
+
const settings = updates.settings !== undefined ? updates.settings : existing.settings;
|
|
53
|
+
const teamId = updates.teamId ?? existing.teamId;
|
|
54
|
+
db.prepare(`
|
|
55
|
+
UPDATE agent_config SET
|
|
56
|
+
team_id = ?, model = ?, fallback_model = ?, cost_cap_daily = ?,
|
|
57
|
+
cost_cap_monthly = ?, max_tokens_per_call = ?, settings = ?, updated_at = ?
|
|
58
|
+
WHERE agent_id = ?
|
|
59
|
+
`).run(teamId, model, fallbackModel, costCapDaily, costCapMonthly, maxTokensPerCall, JSON.stringify(settings), now, agentId);
|
|
60
|
+
return { agentId, teamId, model, fallbackModel, costCapDaily, costCapMonthly, maxTokensPerCall, settings, createdAt: existing.createdAt, updatedAt: now };
|
|
61
|
+
}
|
|
62
|
+
// Insert
|
|
63
|
+
const teamId = updates.teamId ?? 'default';
|
|
64
|
+
const model = updates.model ?? null;
|
|
65
|
+
const fallbackModel = updates.fallbackModel ?? null;
|
|
66
|
+
const costCapDaily = updates.costCapDaily ?? null;
|
|
67
|
+
const costCapMonthly = updates.costCapMonthly ?? null;
|
|
68
|
+
const maxTokensPerCall = updates.maxTokensPerCall ?? null;
|
|
69
|
+
const settings = updates.settings ?? {};
|
|
70
|
+
db.prepare(`
|
|
71
|
+
INSERT INTO agent_config (agent_id, team_id, model, fallback_model, cost_cap_daily, cost_cap_monthly, max_tokens_per_call, settings, created_at, updated_at)
|
|
72
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
73
|
+
`).run(agentId, teamId, model, fallbackModel, costCapDaily, costCapMonthly, maxTokensPerCall, JSON.stringify(settings), now, now);
|
|
74
|
+
return { agentId, teamId, model, fallbackModel, costCapDaily, costCapMonthly, maxTokensPerCall, settings, createdAt: now, updatedAt: now };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Delete config for an agent.
|
|
78
|
+
*/
|
|
79
|
+
export function deleteAgentConfig(agentId) {
|
|
80
|
+
const db = getDb();
|
|
81
|
+
const result = db.prepare('DELETE FROM agent_config WHERE agent_id = ?').run(agentId);
|
|
82
|
+
return result.changes > 0;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if an agent is within its cost cap.
|
|
86
|
+
* Returns { allowed, remaining, cap, spent, action } for the cost enforcement hook.
|
|
87
|
+
*/
|
|
88
|
+
export function checkCostCap(agentId, currentDailySpend, currentMonthlySpend) {
|
|
89
|
+
const config = getAgentConfig(agentId);
|
|
90
|
+
if (!config) {
|
|
91
|
+
return { allowed: true, dailyRemaining: null, monthlyRemaining: null, action: 'allow', model: null, fallbackModel: null };
|
|
92
|
+
}
|
|
93
|
+
let action = 'allow';
|
|
94
|
+
let dailyRemaining = null;
|
|
95
|
+
let monthlyRemaining = null;
|
|
96
|
+
if (config.costCapDaily !== null) {
|
|
97
|
+
dailyRemaining = config.costCapDaily - currentDailySpend;
|
|
98
|
+
if (dailyRemaining <= 0) {
|
|
99
|
+
action = 'deny';
|
|
100
|
+
}
|
|
101
|
+
else if (dailyRemaining < config.costCapDaily * 0.1) {
|
|
102
|
+
action = 'downgrade'; // < 10% remaining → use fallback model
|
|
103
|
+
}
|
|
104
|
+
else if (dailyRemaining < config.costCapDaily * 0.2) {
|
|
105
|
+
action = action === 'allow' ? 'warn' : action; // < 20% remaining → warn
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (config.costCapMonthly !== null) {
|
|
109
|
+
monthlyRemaining = config.costCapMonthly - currentMonthlySpend;
|
|
110
|
+
if (monthlyRemaining <= 0) {
|
|
111
|
+
action = 'deny';
|
|
112
|
+
}
|
|
113
|
+
else if (monthlyRemaining < config.costCapMonthly * 0.1 && action !== 'deny') {
|
|
114
|
+
action = 'downgrade';
|
|
115
|
+
}
|
|
116
|
+
else if (monthlyRemaining < config.costCapMonthly * 0.2 && action === 'allow') {
|
|
117
|
+
action = 'warn';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
allowed: action !== 'deny',
|
|
122
|
+
dailyRemaining,
|
|
123
|
+
monthlyRemaining,
|
|
124
|
+
action,
|
|
125
|
+
model: config.model,
|
|
126
|
+
fallbackModel: config.fallbackModel,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=agent-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-config.js","sourceRoot":"","sources":["../src/agent-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-config.test.d.ts","sourceRoot":"","sources":["../src/agent-config.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
// Test the cost cap logic in isolation
|
|
5
|
+
function checkCostCap(config, dailySpend, monthlySpend) {
|
|
6
|
+
if (!config)
|
|
7
|
+
return { allowed: true, action: 'allow' };
|
|
8
|
+
let action = 'allow';
|
|
9
|
+
if (config.costCapDaily !== null) {
|
|
10
|
+
const remaining = config.costCapDaily - dailySpend;
|
|
11
|
+
if (remaining <= 0)
|
|
12
|
+
action = 'deny';
|
|
13
|
+
else if (remaining < config.costCapDaily * 0.1)
|
|
14
|
+
action = 'downgrade';
|
|
15
|
+
else if (remaining < config.costCapDaily * 0.2)
|
|
16
|
+
action = 'warn';
|
|
17
|
+
}
|
|
18
|
+
if (config.costCapMonthly !== null) {
|
|
19
|
+
const remaining = config.costCapMonthly - monthlySpend;
|
|
20
|
+
if (remaining <= 0)
|
|
21
|
+
action = 'deny';
|
|
22
|
+
else if (remaining < config.costCapMonthly * 0.1 && action !== 'deny')
|
|
23
|
+
action = 'downgrade';
|
|
24
|
+
else if (remaining < config.costCapMonthly * 0.2 && action === 'allow')
|
|
25
|
+
action = 'warn';
|
|
26
|
+
}
|
|
27
|
+
return { allowed: action !== 'deny', action };
|
|
28
|
+
}
|
|
29
|
+
describe('agent config cost enforcement', () => {
|
|
30
|
+
it('allows when no config exists', () => {
|
|
31
|
+
const r = checkCostCap(null, 5, 50);
|
|
32
|
+
assert.equal(r.allowed, true);
|
|
33
|
+
assert.equal(r.action, 'allow');
|
|
34
|
+
});
|
|
35
|
+
it('allows when no caps are set', () => {
|
|
36
|
+
const r = checkCostCap({ costCapDaily: null, costCapMonthly: null, model: null, fallbackModel: null }, 5, 50);
|
|
37
|
+
assert.equal(r.allowed, true);
|
|
38
|
+
assert.equal(r.action, 'allow');
|
|
39
|
+
});
|
|
40
|
+
it('allows when well under daily cap', () => {
|
|
41
|
+
const r = checkCostCap({ costCapDaily: 10, costCapMonthly: null, model: 'opus', fallbackModel: 'sonnet' }, 3, 0);
|
|
42
|
+
assert.equal(r.allowed, true);
|
|
43
|
+
assert.equal(r.action, 'allow');
|
|
44
|
+
});
|
|
45
|
+
it('warns at 80% daily spend', () => {
|
|
46
|
+
const r = checkCostCap({ costCapDaily: 10, costCapMonthly: null, model: 'opus', fallbackModel: 'sonnet' }, 8.5, 0);
|
|
47
|
+
assert.equal(r.allowed, true);
|
|
48
|
+
assert.equal(r.action, 'warn');
|
|
49
|
+
});
|
|
50
|
+
it('downgrades at 90% daily spend', () => {
|
|
51
|
+
const r = checkCostCap({ costCapDaily: 10, costCapMonthly: null, model: 'opus', fallbackModel: 'sonnet' }, 9.5, 0);
|
|
52
|
+
assert.equal(r.allowed, true);
|
|
53
|
+
assert.equal(r.action, 'downgrade');
|
|
54
|
+
});
|
|
55
|
+
it('denies at 100% daily spend', () => {
|
|
56
|
+
const r = checkCostCap({ costCapDaily: 10, costCapMonthly: null, model: 'opus', fallbackModel: 'sonnet' }, 10, 0);
|
|
57
|
+
assert.equal(r.allowed, false);
|
|
58
|
+
assert.equal(r.action, 'deny');
|
|
59
|
+
});
|
|
60
|
+
it('denies when over daily cap', () => {
|
|
61
|
+
const r = checkCostCap({ costCapDaily: 10, costCapMonthly: null, model: 'opus', fallbackModel: 'sonnet' }, 12, 0);
|
|
62
|
+
assert.equal(r.allowed, false);
|
|
63
|
+
assert.equal(r.action, 'deny');
|
|
64
|
+
});
|
|
65
|
+
it('monthly cap denies overriding daily allow', () => {
|
|
66
|
+
const r = checkCostCap({ costCapDaily: 10, costCapMonthly: 100, model: null, fallbackModel: null }, 3, 100);
|
|
67
|
+
assert.equal(r.allowed, false);
|
|
68
|
+
assert.equal(r.action, 'deny');
|
|
69
|
+
});
|
|
70
|
+
it('monthly warn when daily is fine', () => {
|
|
71
|
+
const r = checkCostCap({ costCapDaily: null, costCapMonthly: 100, model: null, fallbackModel: null }, 0, 85);
|
|
72
|
+
assert.equal(r.allowed, true);
|
|
73
|
+
assert.equal(r.action, 'warn');
|
|
74
|
+
});
|
|
75
|
+
it('monthly downgrade at 90%', () => {
|
|
76
|
+
const r = checkCostCap({ costCapDaily: null, costCapMonthly: 100, model: null, fallbackModel: null }, 0, 95);
|
|
77
|
+
assert.equal(r.allowed, true);
|
|
78
|
+
assert.equal(r.action, 'downgrade');
|
|
79
|
+
});
|
|
80
|
+
it('both caps — tighter one wins', () => {
|
|
81
|
+
// Daily is at 95% (downgrade), monthly is fine
|
|
82
|
+
const r = checkCostCap({ costCapDaily: 10, costCapMonthly: 1000, model: 'opus', fallbackModel: 'sonnet' }, 9.5, 50);
|
|
83
|
+
assert.equal(r.action, 'downgrade');
|
|
84
|
+
});
|
|
85
|
+
it('zero cap always denies', () => {
|
|
86
|
+
const r = checkCostCap({ costCapDaily: 0, costCapMonthly: null, model: null, fallbackModel: null }, 0, 0);
|
|
87
|
+
assert.equal(r.allowed, false);
|
|
88
|
+
assert.equal(r.action, 'deny');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
//# sourceMappingURL=agent-config.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-config.test.js","sourceRoot":"","sources":["../src/agent-config.test.ts"],"names":[],"mappings":"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"}
|