gibi-bot 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.context.json +47 -3
  2. package/.github/workflows/npm-publish.yml +33 -0
  3. package/.github/workflows/release.yml +45 -0
  4. package/.husky/commit-msg +1 -0
  5. package/.husky/pre-commit +2 -0
  6. package/.prettierignore +3 -0
  7. package/.prettierrc +7 -0
  8. package/CHANGELOG.md +45 -0
  9. package/DISTRIBUTION.md +9 -1
  10. package/GEMINI.md +28 -9
  11. package/README.md +55 -28
  12. package/commitlint.config.js +3 -0
  13. package/conductor/code_styleguides/general.md +6 -1
  14. package/conductor/code_styleguides/ts.md +42 -35
  15. package/conductor/product-guidelines.md +16 -12
  16. package/conductor/product.md +12 -7
  17. package/conductor/setup_state.json +1 -1
  18. package/conductor/tech-stack.md +4 -1
  19. package/conductor/tracks/slack_bot_20260107/metadata.json +1 -1
  20. package/conductor/tracks/slack_bot_20260107/plan.md +6 -1
  21. package/conductor/tracks/slack_bot_20260107/spec.md +9 -6
  22. package/conductor/tracks.md +2 -1
  23. package/conductor/workflow.md +74 -53
  24. package/dist/agents.js +7 -10
  25. package/dist/agents.test.js +17 -12
  26. package/dist/app.js +212 -135
  27. package/dist/config.js +5 -5
  28. package/dist/context.js +4 -3
  29. package/dist/context.test.js +2 -4
  30. package/eslint.config.mjs +17 -0
  31. package/jest.config.js +4 -3
  32. package/nodemon.json +5 -9
  33. package/package.json +34 -4
  34. package/release.config.js +22 -0
  35. package/src/agents.test.ts +62 -57
  36. package/src/agents.ts +94 -82
  37. package/src/app.d.ts +1 -1
  38. package/src/app.ts +298 -178
  39. package/src/config.ts +48 -48
  40. package/src/context.test.ts +54 -56
  41. package/src/context.ts +123 -114
  42. package/test_gemini.js +13 -9
  43. package/test_gemini_approval.js +13 -9
  44. package/test_gemini_write.js +19 -9
  45. package/tests/context.test.ts +145 -0
  46. package/tsconfig.json +1 -1
  47. package/src/app.js +0 -55
  48. package/src/app.js.map +0 -1
@@ -0,0 +1,145 @@
1
+ import { ContextManager } from '../src/context';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+
5
+ // Mock fs to avoid writing to disk
6
+ jest.mock('fs');
7
+
8
+ describe('ContextManager', () => {
9
+ const mockStoragePath = path.join(process.cwd(), '.context.json');
10
+ let contextManager: ContextManager;
11
+
12
+ beforeEach(() => {
13
+ jest.clearAllMocks();
14
+
15
+ // Setup fs mock for constructor load()
16
+ (fs.existsSync as jest.Mock).mockReturnValue(false);
17
+
18
+ contextManager = new ContextManager();
19
+ });
20
+
21
+ describe('constructor', () => {
22
+ it('should load existing contexts from disk', () => {
23
+ const mockData = {
24
+ 'ctx-1': {
25
+ id: 'ctx-1',
26
+ createdAt: new Date('2023-01-01').toISOString(),
27
+ lastActiveAt: new Date('2023-01-02').toISOString(),
28
+ data: { role: 'admin' },
29
+ messages: [],
30
+ },
31
+ };
32
+
33
+ (fs.existsSync as jest.Mock).mockReturnValue(true);
34
+ (fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(mockData));
35
+
36
+ // Re-instantiate to trigger load()
37
+ contextManager = new ContextManager();
38
+
39
+ const ctx = contextManager.getContext('ctx-1');
40
+ expect(ctx).toBeDefined();
41
+ expect(ctx.id).toBe('ctx-1');
42
+ expect(ctx.data).toEqual({ role: 'admin' });
43
+ expect(ctx.createdAt).toBeInstanceOf(Date);
44
+ expect(ctx.lastActiveAt).toBeInstanceOf(Date);
45
+ });
46
+
47
+ it('should handle invalid JSON gracefully', () => {
48
+ (fs.existsSync as jest.Mock).mockReturnValue(true);
49
+ (fs.readFileSync as jest.Mock).mockReturnValue('invalid-json');
50
+
51
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
52
+
53
+ contextManager = new ContextManager();
54
+
55
+ expect(consoleSpy).toHaveBeenCalledWith(
56
+ expect.stringContaining('[ContextManager] Failed to load contexts:'),
57
+ expect.any(Error),
58
+ );
59
+
60
+ consoleSpy.mockRestore();
61
+ });
62
+ });
63
+
64
+ describe('getContext', () => {
65
+ it('should create a new context if it does not exist', () => {
66
+ const ctx = contextManager.getContext('new-ctx');
67
+
68
+ expect(ctx.id).toBe('new-ctx');
69
+ expect(ctx.messages).toEqual([]);
70
+ expect(ctx.createdAt).toBeInstanceOf(Date);
71
+
72
+ // Should save to disk when creating new context
73
+ expect(fs.writeFileSync).toHaveBeenCalled();
74
+ });
75
+
76
+ it('should retrieve an existing context', () => {
77
+ // First create it
78
+ contextManager.getContext('existing-ctx');
79
+
80
+ // Then retrieve it
81
+ const ctx = contextManager.getContext('existing-ctx');
82
+ expect(ctx.id).toBe('existing-ctx');
83
+ });
84
+
85
+ it('should update lastActiveAt on retrieval', () => {
86
+ const ctx1 = contextManager.getContext('active-ctx');
87
+ const firstAccess = ctx1.lastActiveAt;
88
+
89
+ // Advance time slightly (mocking Date would be cleaner but checking for change works)
90
+ const ctx2 = contextManager.getContext('active-ctx');
91
+
92
+ expect(ctx2.lastActiveAt.getTime()).toBeGreaterThanOrEqual(firstAccess.getTime());
93
+ expect(fs.writeFileSync).toHaveBeenCalled();
94
+ });
95
+ });
96
+
97
+ describe('setContextData', () => {
98
+ it('should update context data and save', () => {
99
+ contextManager.setContextData('data-ctx', { key: 'value' });
100
+
101
+ const ctx = contextManager.getContext('data-ctx');
102
+ expect(ctx.data).toEqual({ key: 'value' });
103
+
104
+ expect(fs.writeFileSync).toHaveBeenCalled();
105
+
106
+ // Check partial update
107
+ contextManager.setContextData('data-ctx', { key2: 'value2' });
108
+ const ctx2 = contextManager.getContext('data-ctx');
109
+ expect(ctx2.data).toEqual({ key: 'value', key2: 'value2' });
110
+ });
111
+ });
112
+
113
+ describe('getAllContexts', () => {
114
+ it('should return all contexts', () => {
115
+ contextManager.getContext('ctx-1');
116
+ contextManager.getContext('ctx-2');
117
+
118
+ const all = contextManager.getAllContexts();
119
+ expect(all).toHaveLength(2);
120
+ expect(all.map((c) => c.id)).toContain('ctx-1');
121
+ expect(all.map((c) => c.id)).toContain('ctx-2');
122
+ });
123
+ });
124
+
125
+ describe('clearContext', () => {
126
+ it('should remove context and save', () => {
127
+ contextManager.getContext('ctx-to-delete');
128
+ expect(contextManager.hasContext('ctx-to-delete')).toBe(true);
129
+
130
+ contextManager.clearContext('ctx-to-delete');
131
+ expect(contextManager.hasContext('ctx-to-delete')).toBe(false);
132
+
133
+ expect(fs.writeFileSync).toHaveBeenCalled();
134
+ });
135
+
136
+ it('should do nothing if context does not exist', () => {
137
+ contextManager.clearContext('non-existent');
138
+ // Ideally checking that save wasn't called if we tracked "dirty" state properly,
139
+ // but current implementation might not save.
140
+ // Actually implementation calls save only if delete returns true.
141
+ // We'll check hasContext remains false.
142
+ expect(contextManager.hasContext('non-existent')).toBe(false);
143
+ });
144
+ });
145
+ });
package/tsconfig.json CHANGED
@@ -10,4 +10,4 @@
10
10
  "skipLibCheck": true
11
11
  },
12
12
  "include": ["src/**/*"]
13
- }
13
+ }
package/src/app.js DELETED
@@ -1,55 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- const bolt_1 = require("@slack/bolt");
37
- const dotenv = __importStar(require("dotenv"));
38
- dotenv.config();
39
- const app = new bolt_1.App({
40
- token: process.env.SLACK_BOT_TOKEN,
41
- signingSecret: process.env.SLACK_SIGNING_SECRET,
42
- socketMode: true, // Recommended for local development
43
- appToken: process.env.SLACK_APP_TOKEN
44
- });
45
- // Listens to incoming messages that contain "ping"
46
- app.message('ping', async ({ message, say }) => {
47
- // say() sends a message to the channel where the event was triggered
48
- await say(`pong`);
49
- });
50
- (async () => {
51
- // Start your app
52
- await app.start(process.env.PORT || 3000);
53
- console.log('⚡️ Bolt app is running!');
54
- })();
55
- //# sourceMappingURL=app.js.map
package/src/app.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["app.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,sCAAkC;AAClC,+CAAiC;AAEjC,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,GAAG,GAAG,IAAI,UAAG,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;IAClC,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;IAC/C,UAAU,EAAE,IAAI,EAAE,oCAAoC;IACtD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;CACtC,CAAC,CAAC;AAEH,mDAAmD;AACnD,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE;IAC7C,qEAAqE;IACrE,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC;AAEH,CAAC,KAAK,IAAI,EAAE;IACV,iBAAiB;IACjB,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IAE1C,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;AACzC,CAAC,CAAC,EAAE,CAAC"}