jinn-cli 0.7.8 → 0.8.0

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 (122) hide show
  1. package/dist/bin/jimmy.js +2 -1
  2. package/dist/bin/jimmy.js.map +1 -1
  3. package/dist/package.json +54 -0
  4. package/dist/src/cli/__tests__/migrate.test.d.ts +2 -0
  5. package/dist/src/cli/__tests__/migrate.test.d.ts.map +1 -0
  6. package/dist/src/cli/__tests__/migrate.test.js +79 -0
  7. package/dist/src/cli/__tests__/migrate.test.js.map +1 -0
  8. package/dist/src/cli/migrate.d.ts.map +1 -1
  9. package/dist/src/cli/migrate.js +3 -2
  10. package/dist/src/cli/migrate.js.map +1 -1
  11. package/dist/src/connectors/telegram/__tests__/connector.test.d.ts +2 -0
  12. package/dist/src/connectors/telegram/__tests__/connector.test.d.ts.map +1 -0
  13. package/dist/src/connectors/telegram/__tests__/connector.test.js +257 -0
  14. package/dist/src/connectors/telegram/__tests__/connector.test.js.map +1 -0
  15. package/dist/src/connectors/telegram/__tests__/format.test.d.ts +2 -0
  16. package/dist/src/connectors/telegram/__tests__/format.test.d.ts.map +1 -0
  17. package/dist/src/connectors/telegram/__tests__/format.test.js +79 -0
  18. package/dist/src/connectors/telegram/__tests__/format.test.js.map +1 -0
  19. package/dist/src/connectors/telegram/__tests__/threads.test.d.ts +2 -0
  20. package/dist/src/connectors/telegram/__tests__/threads.test.d.ts.map +1 -0
  21. package/dist/src/connectors/telegram/__tests__/threads.test.js +51 -0
  22. package/dist/src/connectors/telegram/__tests__/threads.test.js.map +1 -0
  23. package/dist/src/connectors/telegram/format.d.ts +12 -0
  24. package/dist/src/connectors/telegram/format.d.ts.map +1 -0
  25. package/dist/src/connectors/telegram/format.js +61 -0
  26. package/dist/src/connectors/telegram/format.js.map +1 -0
  27. package/dist/src/connectors/telegram/index.d.ts +26 -0
  28. package/dist/src/connectors/telegram/index.d.ts.map +1 -0
  29. package/dist/src/connectors/telegram/index.js +185 -0
  30. package/dist/src/connectors/telegram/index.js.map +1 -0
  31. package/dist/src/connectors/telegram/threads.d.ts +29 -0
  32. package/dist/src/connectors/telegram/threads.d.ts.map +1 -0
  33. package/dist/src/connectors/telegram/threads.js +26 -0
  34. package/dist/src/connectors/telegram/threads.js.map +1 -0
  35. package/dist/src/cron/runner.js.map +1 -1
  36. package/dist/src/engines/__tests__/gemini.test.d.ts +2 -0
  37. package/dist/src/engines/__tests__/gemini.test.d.ts.map +1 -0
  38. package/dist/src/engines/__tests__/gemini.test.js +404 -0
  39. package/dist/src/engines/__tests__/gemini.test.js.map +1 -0
  40. package/dist/src/engines/gemini.d.ts +32 -0
  41. package/dist/src/engines/gemini.d.ts.map +1 -0
  42. package/dist/src/engines/gemini.js +328 -0
  43. package/dist/src/engines/gemini.js.map +1 -0
  44. package/dist/src/gateway/__tests__/org-update.test.d.ts +2 -0
  45. package/dist/src/gateway/__tests__/org-update.test.d.ts.map +1 -0
  46. package/dist/src/gateway/__tests__/org-update.test.js +99 -0
  47. package/dist/src/gateway/__tests__/org-update.test.js.map +1 -0
  48. package/dist/src/gateway/__tests__/org.test.d.ts +2 -0
  49. package/dist/src/gateway/__tests__/org.test.d.ts.map +1 -0
  50. package/dist/src/gateway/__tests__/org.test.js +77 -0
  51. package/dist/src/gateway/__tests__/org.test.js.map +1 -0
  52. package/dist/src/gateway/__tests__/services.test.d.ts +2 -0
  53. package/dist/src/gateway/__tests__/services.test.d.ts.map +1 -0
  54. package/dist/src/gateway/__tests__/services.test.js +165 -0
  55. package/dist/src/gateway/__tests__/services.test.js.map +1 -0
  56. package/dist/src/gateway/api.d.ts.map +1 -1
  57. package/dist/src/gateway/api.js +61 -14
  58. package/dist/src/gateway/api.js.map +1 -1
  59. package/dist/src/gateway/org.d.ts +7 -0
  60. package/dist/src/gateway/org.d.ts.map +1 -1
  61. package/dist/src/gateway/org.js +58 -0
  62. package/dist/src/gateway/org.js.map +1 -1
  63. package/dist/src/gateway/server.d.ts.map +1 -1
  64. package/dist/src/gateway/server.js +27 -0
  65. package/dist/src/gateway/server.js.map +1 -1
  66. package/dist/src/gateway/services.d.ts +17 -0
  67. package/dist/src/gateway/services.d.ts.map +1 -0
  68. package/dist/src/gateway/services.js +73 -0
  69. package/dist/src/gateway/services.js.map +1 -0
  70. package/dist/src/sessions/__tests__/callbacks.test.js +36 -0
  71. package/dist/src/sessions/__tests__/callbacks.test.js.map +1 -1
  72. package/dist/src/sessions/callbacks.d.ts +2 -0
  73. package/dist/src/sessions/callbacks.d.ts.map +1 -1
  74. package/dist/src/sessions/callbacks.js +3 -1
  75. package/dist/src/sessions/callbacks.js.map +1 -1
  76. package/dist/src/sessions/context.js +8 -1
  77. package/dist/src/sessions/context.js.map +1 -1
  78. package/dist/src/sessions/manager.d.ts.map +1 -1
  79. package/dist/src/sessions/manager.js +8 -5
  80. package/dist/src/sessions/manager.js.map +1 -1
  81. package/dist/src/sessions/registry.d.ts +1 -0
  82. package/dist/src/sessions/registry.d.ts.map +1 -1
  83. package/dist/src/sessions/registry.js +4 -0
  84. package/dist/src/sessions/registry.js.map +1 -1
  85. package/dist/src/shared/types.d.ts +15 -1
  86. package/dist/src/shared/types.d.ts.map +1 -1
  87. package/dist/web/404.html +1 -1
  88. package/dist/web/_next/static/chunks/155-d60b5aa6e01f7738.js +1 -0
  89. package/dist/web/_next/static/chunks/192-8281220a22c7a155.js +1 -0
  90. package/dist/web/_next/static/chunks/379-11f5e4203461fd6a.js +1 -0
  91. package/dist/web/_next/static/chunks/app/chat/page-3a532ea2d0f8b961.js +1 -0
  92. package/dist/web/_next/static/chunks/app/{layout-497d1e93737edeae.js → layout-f5c5165308a903e2.js} +1 -1
  93. package/dist/web/_next/static/chunks/app/org/page-99d1b67b8f17e4d5.js +1 -0
  94. package/dist/web/_next/static/css/214f7107c416b9a3.css +1 -0
  95. package/dist/web/chat.html +1 -1
  96. package/dist/web/chat.txt +5 -5
  97. package/dist/web/cron.html +1 -1
  98. package/dist/web/cron.txt +5 -5
  99. package/dist/web/index.html +1 -1
  100. package/dist/web/index.txt +5 -5
  101. package/dist/web/kanban.html +1 -1
  102. package/dist/web/kanban.txt +5 -5
  103. package/dist/web/logs.html +2 -2
  104. package/dist/web/logs.txt +5 -5
  105. package/dist/web/org.html +1 -1
  106. package/dist/web/org.txt +5 -5
  107. package/dist/web/sessions.html +1 -1
  108. package/dist/web/sessions.txt +4 -4
  109. package/dist/web/settings.html +1 -1
  110. package/dist/web/settings.txt +5 -5
  111. package/dist/web/skills.html +1 -1
  112. package/dist/web/skills.txt +5 -5
  113. package/package.json +5 -3
  114. package/template/migrations/0.8.0/MIGRATION.md +73 -0
  115. package/dist/web/_next/static/chunks/155-5843f8840f40f6f8.js +0 -1
  116. package/dist/web/_next/static/chunks/192-f566317c5713c743.js +0 -1
  117. package/dist/web/_next/static/chunks/660-7b281827cf68988a.js +0 -1
  118. package/dist/web/_next/static/chunks/app/chat/page-01d396112fbc8623.js +0 -1
  119. package/dist/web/_next/static/chunks/app/org/page-b14614ed22c7a80d.js +0 -1
  120. package/dist/web/_next/static/css/29fd6f6f1915cce0.css +0 -1
  121. /package/dist/web/_next/static/{73aF2gsMYJ-t64sWQw1Av → yhgZ2UX_j_Aier68GaRfB}/_buildManifest.js +0 -0
  122. /package/dist/web/_next/static/{73aF2gsMYJ-t64sWQw1Av → yhgZ2UX_j_Aier68GaRfB}/_ssgManifest.js +0 -0
@@ -0,0 +1,165 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { findCommonAncestor, buildRoutePath, resolveManagerChain, } from '../services.js';
3
+ // ---------------------------------------------------------------------------
4
+ // Helpers — build a small org tree for testing
5
+ // ---------------------------------------------------------------------------
6
+ /**
7
+ * Org tree:
8
+ *
9
+ * company
10
+ * / \
11
+ * engineering design
12
+ * / \
13
+ * backend frontend
14
+ */
15
+ function makeDepartments() {
16
+ const depts = [
17
+ { name: 'company', displayName: 'Company', path: 'company', manager: 'ceo', children: ['engineering', 'design'], employees: ['ceo'] },
18
+ { name: 'engineering', displayName: 'Engineering', path: 'engineering', parent: 'company', manager: 'eng-lead', children: ['backend', 'frontend'], employees: ['eng-lead'] },
19
+ { name: 'design', displayName: 'Design', path: 'design', parent: 'company', manager: 'design-lead', children: [], employees: ['design-lead', 'designer-carol'] },
20
+ { name: 'backend', displayName: 'Backend', path: 'backend', parent: 'engineering', manager: 'backend-lead', children: [], employees: ['backend-lead', 'dev-alice'] },
21
+ { name: 'frontend', displayName: 'Frontend', path: 'frontend', parent: 'engineering', manager: 'frontend-lead', children: [], employees: ['frontend-lead', 'dev-bob'] },
22
+ ];
23
+ const map = new Map();
24
+ for (const d of depts)
25
+ map.set(d.path, d);
26
+ return map;
27
+ }
28
+ function makeEmployees() {
29
+ const base = { engine: 'claude', model: 'sonnet', persona: 'test' };
30
+ const emps = [
31
+ { name: 'ceo', displayName: 'CEO', department: 'company', rank: 'executive', ...base },
32
+ { name: 'eng-lead', displayName: 'Eng Lead', department: 'engineering', rank: 'manager', ...base },
33
+ { name: 'design-lead', displayName: 'Design Lead', department: 'design', rank: 'manager', ...base },
34
+ { name: 'backend-lead', displayName: 'Backend Lead', department: 'backend', rank: 'senior', ...base },
35
+ { name: 'frontend-lead', displayName: 'Frontend Lead', department: 'frontend', rank: 'senior', ...base },
36
+ { name: 'dev-alice', displayName: 'Alice', department: 'backend', rank: 'employee', ...base },
37
+ { name: 'dev-bob', displayName: 'Bob', department: 'frontend', rank: 'employee', ...base },
38
+ { name: 'designer-carol', displayName: 'Carol', department: 'design', rank: 'employee', ...base },
39
+ ];
40
+ const map = new Map();
41
+ for (const e of emps)
42
+ map.set(e.name, e);
43
+ return map;
44
+ }
45
+ // ---------------------------------------------------------------------------
46
+ // Tests
47
+ // ---------------------------------------------------------------------------
48
+ describe('findCommonAncestor', () => {
49
+ const depts = makeDepartments();
50
+ it('finds LCA between two sibling departments', () => {
51
+ // backend and frontend are both children of engineering
52
+ expect(findCommonAncestor('backend', 'frontend', depts)).toBe('engineering');
53
+ });
54
+ it('finds LCA between cousin departments', () => {
55
+ // backend (under engineering) and design are both under company
56
+ expect(findCommonAncestor('backend', 'design', depts)).toBe('company');
57
+ });
58
+ it('finds LCA when one department is ancestor of the other', () => {
59
+ // engineering is the parent of backend
60
+ expect(findCommonAncestor('backend', 'engineering', depts)).toBe('engineering');
61
+ });
62
+ it('returns the department itself when both are the same', () => {
63
+ expect(findCommonAncestor('backend', 'backend', depts)).toBe('backend');
64
+ });
65
+ it('returns undefined for two root-level departments with no common ancestor', () => {
66
+ // Create isolated departments with no parent
67
+ const isolated = new Map();
68
+ isolated.set('alpha', { name: 'alpha', displayName: 'Alpha', path: 'alpha', children: [], employees: [] });
69
+ isolated.set('beta', { name: 'beta', displayName: 'Beta', path: 'beta', children: [], employees: [] });
70
+ expect(findCommonAncestor('alpha', 'beta', isolated)).toBeUndefined();
71
+ });
72
+ it('returns undefined when department is unknown', () => {
73
+ expect(findCommonAncestor('nonexistent', 'backend', depts)).toBeUndefined();
74
+ });
75
+ });
76
+ describe('buildRoutePath', () => {
77
+ const depts = makeDepartments();
78
+ it('returns single element when source equals target', () => {
79
+ expect(buildRoutePath('backend', 'backend', depts)).toEqual(['backend']);
80
+ });
81
+ it('builds route between sibling departments', () => {
82
+ const route = buildRoutePath('backend', 'frontend', depts);
83
+ // backend -> engineering (LCA) -> frontend
84
+ expect(route).toEqual(['backend', 'engineering', 'frontend']);
85
+ });
86
+ it('builds route between cousin departments', () => {
87
+ const route = buildRoutePath('backend', 'design', depts);
88
+ // backend -> engineering -> company (LCA) -> design
89
+ expect(route).toEqual(['backend', 'engineering', 'company', 'design']);
90
+ });
91
+ it('builds route when target is ancestor of source', () => {
92
+ const route = buildRoutePath('backend', 'engineering', depts);
93
+ // backend -> engineering (LCA = engineering, so just up-path)
94
+ expect(route).toEqual(['backend', 'engineering']);
95
+ });
96
+ it('builds route when source is ancestor of target', () => {
97
+ const route = buildRoutePath('engineering', 'backend', depts);
98
+ // engineering (LCA = engineering) -> backend
99
+ expect(route).toEqual(['engineering', 'backend']);
100
+ });
101
+ it('handles unknown department gracefully', () => {
102
+ const route = buildRoutePath('nonexistent', 'backend', depts);
103
+ // nonexistent has no parent, no common ancestor found
104
+ // upPath = ['nonexistent'], no ancestor, downPath walks back from backend
105
+ expect(route).toContain('nonexistent');
106
+ });
107
+ });
108
+ describe('resolveManagerChain', () => {
109
+ const depts = makeDepartments();
110
+ const emps = makeEmployees();
111
+ it('resolves managers along a route between siblings', () => {
112
+ const route = buildRoutePath('backend', 'frontend', depts);
113
+ const chain = resolveManagerChain(route, depts, emps);
114
+ const names = chain.map((e) => e.name);
115
+ expect(names).toContain('backend-lead');
116
+ expect(names).toContain('eng-lead');
117
+ expect(names).toContain('frontend-lead');
118
+ });
119
+ it('resolves managers along a cousin route', () => {
120
+ const route = buildRoutePath('backend', 'design', depts);
121
+ const chain = resolveManagerChain(route, depts, emps);
122
+ const names = chain.map((e) => e.name);
123
+ expect(names).toContain('backend-lead');
124
+ expect(names).toContain('eng-lead');
125
+ expect(names).toContain('ceo');
126
+ expect(names).toContain('design-lead');
127
+ });
128
+ it('deduplicates managers when route passes through same dept twice', () => {
129
+ // same dept = single element route
130
+ const route = ['engineering', 'engineering'];
131
+ const chain = resolveManagerChain(route, depts, emps);
132
+ // eng-lead should appear only once
133
+ expect(chain.filter((e) => e.name === 'eng-lead')).toHaveLength(1);
134
+ });
135
+ it('returns empty chain for unknown departments', () => {
136
+ const chain = resolveManagerChain(['nonexistent'], depts, emps);
137
+ expect(chain).toEqual([]);
138
+ });
139
+ it('skips departments with no manager', () => {
140
+ const customDepts = new Map(depts);
141
+ customDepts.set('orphan', { name: 'orphan', displayName: 'Orphan', path: 'orphan', children: [], employees: [] });
142
+ const chain = resolveManagerChain(['orphan', 'backend'], customDepts, emps);
143
+ // orphan has no manager, so only backend-lead
144
+ const names = chain.map((e) => e.name);
145
+ expect(names).not.toContain(undefined);
146
+ expect(names).toContain('backend-lead');
147
+ });
148
+ it('skips managers not found in employee registry', () => {
149
+ const customDepts = new Map(depts);
150
+ customDepts.set('ghost-dept', {
151
+ name: 'ghost-dept',
152
+ displayName: 'Ghost',
153
+ path: 'ghost-dept',
154
+ manager: 'ghost-manager',
155
+ children: [],
156
+ employees: [],
157
+ });
158
+ const chain = resolveManagerChain(['ghost-dept', 'backend'], customDepts, emps);
159
+ // ghost-manager doesn't exist in emps, so only backend-lead
160
+ const names = chain.map((e) => e.name);
161
+ expect(names).not.toContain('ghost-manager');
162
+ expect(names).toContain('backend-lead');
163
+ });
164
+ });
165
+ //# sourceMappingURL=services.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.test.js","sourceRoot":"","sources":["../../../../src/gateway/__tests__/services.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAEvB,8EAA8E;AAC9E,+CAA+C;AAC/C,8EAA8E;AAE9E;;;;;;;;GAQG;AAEH,SAAS,eAAe;IACtB,MAAM,KAAK,GAAiB;QAC1B,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,aAAa,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE;QACrI,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC,UAAU,CAAC,EAAE;QAC5K,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,aAAa,EAAE,gBAAgB,CAAC,EAAE;QAChK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,cAAc,EAAE,WAAW,CAAC,EAAE;QACpK,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,eAAe,EAAE,SAAS,CAAC,EAAE;KACxK,CAAA;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsB,CAAA;IACzC,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IACzC,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,aAAa;IACpB,MAAM,IAAI,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAW,CAAA;IAC5E,MAAM,IAAI,GAAe;QACvB,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE;QACtF,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE;QAClG,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE;QACnG,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE;QACrG,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE;QACxG,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE;QAC7F,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE;QAC1F,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE;KAClG,CAAA;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAA;IACvC,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IACxC,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,MAAM,KAAK,GAAG,eAAe,EAAE,CAAA;IAE/B,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,wDAAwD;QACxD,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;IAC9E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,gEAAgE;QAChE,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,uCAAuC;QACvC,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;IACjF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,6CAA6C;QAC7C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAA;QAC9C,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAA;QAC1G,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAA;QACtG,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;IACvE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,kBAAkB,CAAC,aAAa,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;IAC7E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,MAAM,KAAK,GAAG,eAAe,EAAE,CAAA;IAE/B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,CAAC,CAAA;QAC1D,2CAA2C;QAC3C,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC,CAAA;IAC/D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;QACxD,oDAAoD;QACpD,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,CAAC,CAAA;QAC7D,8DAA8D;QAC9D,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,KAAK,GAAG,cAAc,CAAC,aAAa,EAAE,SAAS,EAAE,KAAK,CAAC,CAAA;QAC7D,6CAA6C;QAC7C,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,KAAK,GAAG,cAAc,CAAC,aAAa,EAAE,SAAS,EAAE,KAAK,CAAC,CAAA;QAC7D,sDAAsD;QACtD,0EAA0E;QAC1E,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,MAAM,KAAK,GAAG,eAAe,EAAE,CAAA;IAC/B,MAAM,IAAI,GAAG,aAAa,EAAE,CAAA;IAE5B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,EAAE,UAAU,EAAE,KAAK,CAAC,CAAA;QAC1D,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;QACrD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;QACvC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;QACnC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;QACxD,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;QACrD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;QACvC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;QACnC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;QAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,mCAAmC;QACnC,MAAM,KAAK,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;QAC5C,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;QACrD,mCAAmC;QACnC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,KAAK,GAAG,mBAAmB,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;QAC/D,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC3B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAClC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAA;QACjH,MAAM,KAAK,GAAG,mBAAmB,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;QAC3E,8CAA8C;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;QACtC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAClC,WAAW,CAAC,GAAG,CAAC,YAAY,EAAE;YAC5B,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,OAAO;YACpB,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,eAAe;YACxB,QAAQ,EAAE,EAAE;YACZ,SAAS,EAAE,EAAE;SACd,CAAC,CAAA;QACF,MAAM,KAAK,GAAG,mBAAmB,CAAC,CAAC,YAAY,EAAE,SAAS,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;QAC/E,4DAA4D;QAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,eAAe,CAAC,CAAA;QAC5C,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/gateway/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,IAAI,WAAW,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAMhF,OAAO,KAAK,EAAoC,UAAU,EAAmB,MAAM,oBAAoB,CAAC;AAExG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AA4C7D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,UAAU,CAAC;IAC5B,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,oBAAoB,EAAE,SAAS,CAAC,CAAC;CACjE;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAgCpE;AAgND,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CAwxCf"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/gateway/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,IAAI,WAAW,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAMhF,OAAO,KAAK,EAAoC,UAAU,EAAmB,MAAM,oBAAoB,CAAC;AAExG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AA6C7D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,UAAU,CAAC;IAC5B,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,oBAAoB,EAAE,SAAS,CAAC,CAAC;CACjE;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAgCpE;AAgND,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CA+zCf"}
@@ -255,6 +255,7 @@ export async function handleApiRequest(req, res, context) {
255
255
  default: config.engines.default,
256
256
  claude: { model: config.engines.claude.model, available: true },
257
257
  codex: { model: config.engines.codex.model, available: true },
258
+ ...(config.engines.gemini ? { gemini: { model: config.engines.gemini.model, available: true } } : {}),
258
259
  },
259
260
  sessions: { total: sessions.length, running, active: running },
260
261
  connectors,
@@ -307,6 +308,34 @@ export async function handleApiRequest(req, res, context) {
307
308
  }
308
309
  return json(res, { ...serializeSession(session, context), messages });
309
310
  }
311
+ // PUT /api/sessions/:id
312
+ params = matchRoute("/api/sessions/:id", pathname);
313
+ if (method === "PUT" && params) {
314
+ const session = getSession(params.id);
315
+ if (!session)
316
+ return notFound(res);
317
+ const _parsed = await readJsonBody(req, res);
318
+ if (!_parsed.ok)
319
+ return;
320
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
321
+ const body = _parsed.body;
322
+ const updates = {};
323
+ if (body.title !== undefined) {
324
+ if (typeof body.title !== "string")
325
+ return badRequest(res, "title must be a string");
326
+ const trimmed = body.title.trim();
327
+ if (!trimmed)
328
+ return badRequest(res, "title must not be empty");
329
+ updates.title = trimmed.slice(0, 200);
330
+ }
331
+ if (Object.keys(updates).length === 0)
332
+ return badRequest(res, "no valid fields to update");
333
+ const updated = updateSession(params.id, updates);
334
+ if (!updated)
335
+ return notFound(res);
336
+ context.emit("session:updated", { sessionId: params.id });
337
+ return json(res, serializeSession(updated, context));
338
+ }
310
339
  // DELETE /api/sessions/:id
311
340
  params = matchRoute("/api/sessions/:id", pathname);
312
341
  if (method === "DELETE" && params) {
@@ -785,6 +814,22 @@ export async function handleApiRequest(req, res, context) {
785
814
  const content = yaml.load(fs.readFileSync(filePath, "utf-8"));
786
815
  return json(res, content);
787
816
  }
817
+ // PATCH /api/org/employees/:name — update employee fields (currently only alwaysNotify)
818
+ params = matchRoute("/api/org/employees/:name", pathname);
819
+ if (method === "PATCH" && params) {
820
+ const _parsed = await readJsonBody(req, res);
821
+ if (!_parsed.ok)
822
+ return;
823
+ const body = _parsed.body;
824
+ const { updateEmployeeYaml } = await import("./org.js");
825
+ const updated = updateEmployeeYaml(params.name, {
826
+ alwaysNotify: typeof body.alwaysNotify === "boolean" ? body.alwaysNotify : undefined,
827
+ });
828
+ if (!updated)
829
+ return notFound(res);
830
+ context.emit("org:updated", { employee: params.name });
831
+ return json(res, { status: "ok" });
832
+ }
788
833
  // GET /api/org/departments/:name/board
789
834
  params = matchRoute("/api/org/departments/:name/board", pathname);
790
835
  if (method === "GET" && params) {
@@ -1665,15 +1710,15 @@ async function runWebSession(session, prompt, engine, config, context, attachmen
1665
1710
  lastActivity: new Date().toISOString(),
1666
1711
  });
1667
1712
  }
1713
+ // If this session has an assigned employee, load their persona
1714
+ let employee;
1715
+ if (currentSession.employee) {
1716
+ const { findEmployee } = await import("./org.js");
1717
+ const { scanOrg } = await import("./org.js");
1718
+ const registry = scanOrg();
1719
+ employee = findEmployee(currentSession.employee, registry);
1720
+ }
1668
1721
  try {
1669
- // If this session has an assigned employee, load their persona
1670
- let employee;
1671
- if (currentSession.employee) {
1672
- const { findEmployee } = await import("./org.js");
1673
- const { scanOrg } = await import("./org.js");
1674
- const registry = scanOrg();
1675
- employee = findEmployee(currentSession.employee, registry);
1676
- }
1677
1722
  const systemPrompt = buildContext({
1678
1723
  source: "web",
1679
1724
  channel: currentSession.sourceRef,
@@ -1685,7 +1730,9 @@ async function runWebSession(session, prompt, engine, config, context, attachmen
1685
1730
  });
1686
1731
  const engineConfig = currentSession.engine === "codex"
1687
1732
  ? config.engines.codex
1688
- : config.engines.claude;
1733
+ : currentSession.engine === "gemini"
1734
+ ? config.engines.gemini ?? config.engines.claude
1735
+ : config.engines.claude;
1689
1736
  const effortLevel = resolveEffort(engineConfig, currentSession, employee);
1690
1737
  let lastHeartbeatAt = 0;
1691
1738
  const runHeartbeat = setInterval(() => {
@@ -1831,7 +1878,7 @@ async function runWebSession(session, prompt, engine, config, context, attachmen
1831
1878
  lastError: fallbackResult.error ?? null,
1832
1879
  });
1833
1880
  if (completedFallback) {
1834
- notifyParentSession(completedFallback, { result: fallbackResult.result, error: fallbackResult.error ?? null, cost: fallbackResult.cost, durationMs: fallbackResult.durationMs });
1881
+ notifyParentSession(completedFallback, { result: fallbackResult.result, error: fallbackResult.error ?? null, cost: fallbackResult.cost, durationMs: fallbackResult.durationMs }, { alwaysNotify: employee?.alwaysNotify });
1835
1882
  }
1836
1883
  context.emit("session:completed", {
1837
1884
  sessionId: currentSession.id,
@@ -1941,7 +1988,7 @@ async function runWebSession(session, prompt, engine, config, context, attachmen
1941
1988
  if (completedAfterRetry) {
1942
1989
  notifyRateLimitResumed(completedAfterRetry);
1943
1990
  notifyDiscordChannel(`✅ Claude usage limit cleared. Session ${currentSession.id}${currentSession.employee ? ` (${currentSession.employee})` : ""} resumed.`);
1944
- notifyParentSession(completedAfterRetry, { result: retryResult.result, error: retryResult.error ?? null, cost: retryResult.cost, durationMs: retryResult.durationMs });
1991
+ notifyParentSession(completedAfterRetry, { result: retryResult.result, error: retryResult.error ?? null, cost: retryResult.cost, durationMs: retryResult.durationMs }, { alwaysNotify: employee?.alwaysNotify });
1945
1992
  }
1946
1993
  context.emit("session:completed", {
1947
1994
  sessionId: currentSession.id,
@@ -1963,7 +2010,7 @@ async function runWebSession(session, prompt, engine, config, context, attachmen
1963
2010
  lastError: "Claude usage limit did not clear in time",
1964
2011
  });
1965
2012
  if (erroredSession) {
1966
- notifyParentSession(erroredSession, { error: "Claude usage limit did not clear in time" });
2013
+ notifyParentSession(erroredSession, { error: "Claude usage limit did not clear in time" }, { alwaysNotify: employee?.alwaysNotify });
1967
2014
  }
1968
2015
  context.emit("session:completed", {
1969
2016
  sessionId: currentSession.id,
@@ -1996,7 +2043,7 @@ async function runWebSession(session, prompt, engine, config, context, attachmen
1996
2043
  }
1997
2044
  }
1998
2045
  if (completedSession) {
1999
- notifyParentSession(completedSession, { result: result.result, error: result.error ?? null, cost: result.cost, durationMs: result.durationMs });
2046
+ notifyParentSession(completedSession, { result: result.result, error: result.error ?? null, cost: result.cost, durationMs: result.durationMs }, { alwaysNotify: employee?.alwaysNotify });
2000
2047
  }
2001
2048
  context.emit("session:completed", {
2002
2049
  sessionId: currentSession.id,
@@ -2023,7 +2070,7 @@ async function runWebSession(session, prompt, engine, config, context, attachmen
2023
2070
  lastError: errMsg,
2024
2071
  });
2025
2072
  if (erroredSession) {
2026
- notifyParentSession(erroredSession, { error: errMsg });
2073
+ notifyParentSession(erroredSession, { error: errMsg }, { alwaysNotify: employee?.alwaysNotify });
2027
2074
  }
2028
2075
  context.emit("session:completed", {
2029
2076
  sessionId: currentSession.id,