@allternit/gizzi-code 1.0.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 (64) hide show
  1. package/WORKSPACE_INTEGRATION.md +290 -0
  2. package/chat-sessions/sessions-index.json +98 -0
  3. package/package.json +43 -0
  4. package/package.json.original +31 -0
  5. package/package.json.publish +47 -0
  6. package/src/bootstrap/state.d.ts +169 -0
  7. package/src/bootstrap/state.js +261 -0
  8. package/src/bootstrap/state.ts +371 -0
  9. package/src/context/pack-builder.d.ts +24 -0
  10. package/src/context/pack-builder.js +281 -0
  11. package/src/context/pack-builder.ts +334 -0
  12. package/src/hooks/useExitOnCtrlCD.d.ts +86 -0
  13. package/src/hooks/useExitOnCtrlCD.js +130 -0
  14. package/src/hooks/useExitOnCtrlCD.ts +202 -0
  15. package/src/hooks/useKeybinding.d.ts +89 -0
  16. package/src/hooks/useKeybinding.js +163 -0
  17. package/src/hooks/useKeybinding.ts +226 -0
  18. package/src/hooks/useTerminalSize.d.ts +41 -0
  19. package/src/hooks/useTerminalSize.js +90 -0
  20. package/src/hooks/useTerminalSize.ts +117 -0
  21. package/src/index.d.ts +23 -0
  22. package/src/index.js +24 -0
  23. package/src/index.ts +132 -0
  24. package/src/runtime/brand/brand.d.ts +488 -0
  25. package/src/runtime/brand/brand.js +464 -0
  26. package/src/runtime/brand/brand.ts +667 -0
  27. package/src/runtime/services/tokenEstimation.d.ts +187 -0
  28. package/src/runtime/services/tokenEstimation.js +423 -0
  29. package/src/runtime/services/tokenEstimation.ts +547 -0
  30. package/src/runtime/tools/Tool.d.ts +239 -0
  31. package/src/runtime/tools/Tool.js +285 -0
  32. package/src/runtime/tools/Tool.ts +524 -0
  33. package/src/scheduler/TaskScheduler.d.ts +98 -0
  34. package/src/scheduler/TaskScheduler.js +201 -0
  35. package/src/scheduler/TaskScheduler.ts +259 -0
  36. package/src/state/AppStateStore.d.ts +347 -0
  37. package/src/state/AppStateStore.js +439 -0
  38. package/src/state/AppStateStore.ts +658 -0
  39. package/src/state/WorkspaceStateStore.d.ts +43 -0
  40. package/src/state/WorkspaceStateStore.js +224 -0
  41. package/src/state/WorkspaceStateStore.ts +297 -0
  42. package/src/types/message.d.ts +190 -0
  43. package/src/types/message.js +77 -0
  44. package/src/types/message.ts +277 -0
  45. package/src/utils/format.d.ts +126 -0
  46. package/src/utils/format.js +230 -0
  47. package/src/utils/format.ts +336 -0
  48. package/src/utils/fullscreen.d.ts +161 -0
  49. package/src/utils/fullscreen.js +277 -0
  50. package/src/utils/fullscreen.ts +382 -0
  51. package/src/utils/sessionStorage.d.ts +210 -0
  52. package/src/utils/sessionStorage.js +435 -0
  53. package/src/utils/sessionStorage.ts +559 -0
  54. package/src/watcher/WorkspaceWatcher.d.ts +70 -0
  55. package/src/watcher/WorkspaceWatcher.js +191 -0
  56. package/src/watcher/WorkspaceWatcher.ts +251 -0
  57. package/src/workspace/loader.d.ts +30 -0
  58. package/src/workspace/loader.js +117 -0
  59. package/src/workspace/loader.ts +171 -0
  60. package/src/workspace/types.d.ts +91 -0
  61. package/src/workspace/types.js +7 -0
  62. package/src/workspace/types.ts +122 -0
  63. package/threads/thread_1775361175022.json +9 -0
  64. package/tsconfig.json +14 -0
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Gizzi Context Pack Builder
3
+ *
4
+ * Builds structured context packs from workspace files
5
+ * Production-quality implementation matching Allternit platform
6
+ */
7
+ // ============================================================================
8
+ // File Classification
9
+ // ============================================================================
10
+ export function classifyFile(filePath) {
11
+ const lower = filePath.toLowerCase();
12
+ if (lower.endsWith('manifest.json'))
13
+ return 'manifest';
14
+ if (lower.includes('/brain/'))
15
+ return 'brain';
16
+ if (lower.includes('/memory/'))
17
+ return 'memory';
18
+ if (lower.endsWith('soul.md'))
19
+ return 'soul';
20
+ if (lower.includes('/identity/identity.md'))
21
+ return 'identity';
22
+ if (lower.includes('/identity/user.md'))
23
+ return 'user';
24
+ if (lower.includes('/identity/voice.md'))
25
+ return 'voice';
26
+ if (lower.includes('/identity/policy.md'))
27
+ return 'policy';
28
+ if (lower.includes('/governance/playbook.md'))
29
+ return 'playbook';
30
+ if (lower.includes('/governance/tools.md'))
31
+ return 'tools';
32
+ if (lower.includes('/governance/heartbeat.md'))
33
+ return 'heartbeat';
34
+ if (lower.includes('/governance/system.md'))
35
+ return 'system';
36
+ if (lower.includes('/governance/channels.md'))
37
+ return 'channels';
38
+ if (lower.includes('/skills/'))
39
+ return 'skill';
40
+ if (lower.includes('/business/'))
41
+ return 'business';
42
+ if (lower.endsWith('.json') || lower.endsWith('.yaml') || lower.endsWith('.yml'))
43
+ return 'config';
44
+ return 'knowledge';
45
+ }
46
+ // ============================================================================
47
+ // SOUL.md Parser
48
+ // ============================================================================
49
+ export function parseSoulMd(content) {
50
+ const lines = content.split('\n');
51
+ const trustTiers = {
52
+ tier1: { level: 1, name: 'Foundation', rules: [], enforce: 'always' },
53
+ tier2: { level: 2, name: 'Contextual', rules: [], enforce: 'contextual' },
54
+ tier3: { level: 3, name: 'Permission Required', rules: [], enforce: 'permission' },
55
+ };
56
+ const identity = {
57
+ personalityTraits: [],
58
+ };
59
+ let currentTier = null;
60
+ let inSelfAwareness = false;
61
+ for (const line of lines) {
62
+ const trimmed = line.trim();
63
+ if (trimmed.match(/^#+\s*Tier\s*1/i)) {
64
+ currentTier = 1;
65
+ }
66
+ else if (trimmed.match(/^#+\s*Tier\s*2/i)) {
67
+ currentTier = 2;
68
+ }
69
+ else if (trimmed.match(/^#+\s*Tier\s*3/i)) {
70
+ currentTier = 3;
71
+ }
72
+ else if (trimmed.match(/^#+\s*Self-Awareness/i)) {
73
+ inSelfAwareness = true;
74
+ currentTier = null;
75
+ }
76
+ if (currentTier && trimmed.match(/^[-\*✅]\s+/)) {
77
+ const rule = trimmed.replace(/^[-\*✅]\s+/, '');
78
+ trustTiers[`tier${currentTier}`].rules.push(rule);
79
+ }
80
+ if (inSelfAwareness && trimmed.startsWith('I am')) {
81
+ identity.backstory = trimmed;
82
+ }
83
+ }
84
+ return { trustTiers, identity };
85
+ }
86
+ // ============================================================================
87
+ // HEARTBEAT.md Parser
88
+ // ============================================================================
89
+ export function parseHeartbeatMd(content) {
90
+ const lines = content.split('\n');
91
+ const tasks = [];
92
+ let currentFrequency = 'daily';
93
+ for (const line of lines) {
94
+ const trimmed = line.trim();
95
+ if (trimmed.match(/^#+\s*Daily/i)) {
96
+ currentFrequency = 'daily';
97
+ }
98
+ else if (trimmed.match(/^#+\s*Weekly/i)) {
99
+ currentFrequency = 'weekly';
100
+ }
101
+ else if (trimmed.match(/^#+\s*Monthly/i)) {
102
+ currentFrequency = 'monthly';
103
+ }
104
+ else if (trimmed.match(/^#+\s*On\s+Session\s+Start/i)) {
105
+ currentFrequency = 'on-session-start';
106
+ }
107
+ const taskMatch = trimmed.match(/^-\s*\[([ xX])\]\s*(.+)/);
108
+ if (taskMatch) {
109
+ tasks.push({
110
+ id: `task-${Date.now()}-${tasks.length}`,
111
+ frequency: currentFrequency,
112
+ action: taskMatch[2].trim(),
113
+ lastExecuted: taskMatch[1].toLowerCase() === 'x' ? new Date().toISOString() : undefined,
114
+ });
115
+ }
116
+ }
117
+ return tasks;
118
+ }
119
+ // ============================================================================
120
+ // System Prompt Builder
121
+ // ============================================================================
122
+ export function buildSystemPrompt(pack) {
123
+ const sections = [];
124
+ // Identity
125
+ sections.push(`# Agent Identity
126
+
127
+ You are ${pack.identity.name}.
128
+
129
+ ## Purpose
130
+ ${pack.identity.purpose}
131
+
132
+ ## Backstory
133
+ ${pack.identity.backstory}
134
+
135
+ ## Personality Traits
136
+ ${pack.identity.personalityTraits.map(t => `- ${t}`).join('\n')}`);
137
+ // Trust Tiers (CRITICAL)
138
+ sections.push(`# Trust & Safety (MUST FOLLOW)
139
+
140
+ ## Tier 1 - Foundation (ALWAYS APPLY)
141
+ ${pack.trustTiers.tier1.rules.map(r => `- ${r}`).join('\n')}
142
+
143
+ ## Tier 2 - Contextual (APPLY WHEN RELEVANT)
144
+ ${pack.trustTiers.tier2.rules.map(r => `- ${r}`).join('\n')}
145
+
146
+ ## Tier 3 - Permission Required (ASK USER FIRST)
147
+ ${pack.trustTiers.tier3.rules.map(r => `- ${r}`).join('\n')}
148
+
149
+ ### BEFORE ANY ACTION:
150
+ 1. Check if action violates Tier 1 → NEVER DO
151
+ 2. Check if action matches Tier 2 → APPLY IF CONTEXT FITS
152
+ 3. Check if action requires Tier 3 → ASK USER PERMISSION`);
153
+ // Governance
154
+ if (pack.governance.playbook) {
155
+ sections.push(`# Governance & Procedures
156
+
157
+ ${pack.governance.playbook}`);
158
+ }
159
+ // Tools
160
+ if (pack.governance.availableTools.length > 0) {
161
+ sections.push(`# Available Tools
162
+
163
+ ${pack.governance.availableTools.map(t => `- **${t.name}**: ${t.description}${t.requiresPermission ? ' (Requires Permission)' : ''}`).join('\n')}`);
164
+ }
165
+ // Hard Bans
166
+ if (pack.governance.hardBans.length > 0) {
167
+ sections.push(`# Hard Bans (NEVER DO THESE)
168
+
169
+ ${pack.governance.hardBans.map(b => `- ❌ ${b}`).join('\n')}`);
170
+ }
171
+ // Voice
172
+ sections.push(`# Voice & Communication Style
173
+
174
+ ${pack.voice.style}
175
+
176
+ ## Communication Rules
177
+ ${pack.voice.rules.map(r => `- ${r}`).join('\n')}`);
178
+ // Memory
179
+ if (pack.memory.brain || pack.memory.activeTasks.length > 0) {
180
+ sections.push(`# Current Context
181
+
182
+ ## Active Tasks
183
+ ${pack.memory.activeTasks.map(t => `- ${t}`).join('\n') || 'None'}
184
+
185
+ ## Key Lessons
186
+ ${pack.memory.lessons.map(l => `- ${l}`).join('\n') || 'None'}`);
187
+ }
188
+ return sections.join('\n\n---\n\n');
189
+ }
190
+ export function buildContextPack(options) {
191
+ const { sessionId, agentId, agentName, files } = options;
192
+ // Parse files
193
+ const soulContent = files.has('.allternit/identity/SOUL.md')
194
+ ? parseSoulMd(files.get('.allternit/identity/SOUL.md'))
195
+ : {
196
+ trustTiers: {
197
+ tier1: { level: 1, name: 'Foundation', rules: ['Be helpful and accurate'], enforce: 'always' },
198
+ tier2: { level: 2, name: 'Contextual', rules: ['Adapt to context'], enforce: 'contextual' },
199
+ tier3: { level: 3, name: 'Permission Required', rules: ['Execute code'], enforce: 'permission' },
200
+ },
201
+ identity: { personalityTraits: ['helpful', 'accurate'] }
202
+ };
203
+ const heartbeatContent = files.has('.allternit/governance/HEARTBEAT.md')
204
+ ? parseHeartbeatMd(files.get('.allternit/governance/HEARTBEAT.md'))
205
+ : [];
206
+ // Build pack
207
+ const pack = {
208
+ version: '1.0.0',
209
+ agentId,
210
+ agentName,
211
+ sessionId,
212
+ identity: {
213
+ name: agentName,
214
+ purpose: files.get('.allternit/identity/IDENTITY.md')?.match(/##?\s*Purpose\s*\n([^#]+)/)?.[1]?.trim() || 'Assist the user',
215
+ backstory: soulContent.identity.backstory || `I am ${agentName}, an AI assistant.`,
216
+ personalityTraits: soulContent.identity.personalityTraits || ['helpful', 'accurate'],
217
+ },
218
+ trustTiers: soulContent.trustTiers,
219
+ governance: {
220
+ playbook: files.get('.allternit/governance/PLAYBOOK.md') || '',
221
+ availableTools: [], // Would parse from TOOLS.md
222
+ hardBans: [],
223
+ escalation: [],
224
+ },
225
+ heartbeat: {
226
+ tasks: heartbeatContent,
227
+ lastCheck: new Date().toISOString(),
228
+ },
229
+ memory: {
230
+ brain: files.get('.allternit/brain/BRAIN.md') || '',
231
+ activeTasks: [],
232
+ lessons: [],
233
+ userPreferences: {},
234
+ },
235
+ voice: {
236
+ style: files.get('.allternit/identity/VOICE.md') || 'professional and helpful',
237
+ tone: { formality: 0.5, enthusiasm: 0.5, empathy: 0.5, directness: 0.5 },
238
+ rules: [],
239
+ },
240
+ systemPrompt: '',
241
+ hash: '',
242
+ createdAt: new Date().toISOString(),
243
+ expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
244
+ };
245
+ // Build system prompt
246
+ pack.systemPrompt = buildSystemPrompt(pack);
247
+ // Generate hash
248
+ pack.hash = generateHash(pack);
249
+ return pack;
250
+ }
251
+ function generateHash(pack) {
252
+ const str = JSON.stringify({
253
+ agentId: pack.agentId,
254
+ trustTiers: pack.trustTiers,
255
+ systemPrompt: pack.systemPrompt?.slice(0, 100),
256
+ });
257
+ let hash = 0;
258
+ for (let i = 0; i < str.length; i++) {
259
+ const char = str.charCodeAt(i);
260
+ hash = ((hash << 5) - hash) + char;
261
+ hash = hash & hash;
262
+ }
263
+ return Math.abs(hash).toString(16).padStart(16, '0');
264
+ }
265
+ // ============================================================================
266
+ // Utility Functions
267
+ // ============================================================================
268
+ export function getStartupTasks(pack) {
269
+ return pack.heartbeat.tasks.filter(t => t.frequency === 'on-session-start');
270
+ }
271
+ export function requiresPermission(pack, action) {
272
+ const actionLower = action.toLowerCase();
273
+ // Check Tier 3
274
+ if (pack.trustTiers.tier3.rules.some(r => actionLower.includes(r.toLowerCase()))) {
275
+ return true;
276
+ }
277
+ return false;
278
+ }
279
+ export function shouldRefreshContext(pack) {
280
+ return new Date() > new Date(pack.expiresAt);
281
+ }
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Gizzi Context Pack Builder
3
+ *
4
+ * Builds structured context packs from workspace files
5
+ * Production-quality implementation matching Allternit platform
6
+ */
7
+
8
+ import type {
9
+ ContextPack,
10
+ TrustTier,
11
+ ScheduledTask,
12
+ ToolDefinition,
13
+ WorkspaceFile
14
+ } from '../workspace/types';
15
+
16
+ // ============================================================================
17
+ // File Classification
18
+ // ============================================================================
19
+
20
+ export function classifyFile(filePath: string): WorkspaceFile['type'] {
21
+ const lower = filePath.toLowerCase();
22
+
23
+ if (lower.endsWith('manifest.json')) return 'manifest';
24
+ if (lower.includes('/brain/')) return 'brain';
25
+ if (lower.includes('/memory/')) return 'memory';
26
+ if (lower.endsWith('soul.md')) return 'soul';
27
+ if (lower.includes('/identity/identity.md')) return 'identity';
28
+ if (lower.includes('/identity/user.md')) return 'user';
29
+ if (lower.includes('/identity/voice.md')) return 'voice';
30
+ if (lower.includes('/identity/policy.md')) return 'policy';
31
+ if (lower.includes('/governance/playbook.md')) return 'playbook';
32
+ if (lower.includes('/governance/tools.md')) return 'tools';
33
+ if (lower.includes('/governance/heartbeat.md')) return 'heartbeat';
34
+ if (lower.includes('/governance/system.md')) return 'system';
35
+ if (lower.includes('/governance/channels.md')) return 'channels';
36
+ if (lower.includes('/skills/')) return 'skill';
37
+ if (lower.includes('/business/')) return 'business';
38
+ if (lower.endsWith('.json') || lower.endsWith('.yaml') || lower.endsWith('.yml')) return 'config';
39
+
40
+ return 'knowledge';
41
+ }
42
+
43
+ // ============================================================================
44
+ // SOUL.md Parser
45
+ // ============================================================================
46
+
47
+ export function parseSoulMd(content: string): {
48
+ trustTiers: ContextPack['trustTiers'];
49
+ identity: Partial<ContextPack['identity']>
50
+ } {
51
+ const lines = content.split('\n');
52
+
53
+ const trustTiers: ContextPack['trustTiers'] = {
54
+ tier1: { level: 1, name: 'Foundation', rules: [], enforce: 'always' },
55
+ tier2: { level: 2, name: 'Contextual', rules: [], enforce: 'contextual' },
56
+ tier3: { level: 3, name: 'Permission Required', rules: [], enforce: 'permission' },
57
+ };
58
+
59
+ const identity: Partial<ContextPack['identity']> = {
60
+ personalityTraits: [],
61
+ };
62
+
63
+ let currentTier: 1 | 2 | 3 | null = null;
64
+ let inSelfAwareness = false;
65
+
66
+ for (const line of lines) {
67
+ const trimmed = line.trim();
68
+
69
+ if (trimmed.match(/^#+\s*Tier\s*1/i)) {
70
+ currentTier = 1;
71
+ } else if (trimmed.match(/^#+\s*Tier\s*2/i)) {
72
+ currentTier = 2;
73
+ } else if (trimmed.match(/^#+\s*Tier\s*3/i)) {
74
+ currentTier = 3;
75
+ } else if (trimmed.match(/^#+\s*Self-Awareness/i)) {
76
+ inSelfAwareness = true;
77
+ currentTier = null;
78
+ }
79
+
80
+ if (currentTier && trimmed.match(/^[-\*✅]\s+/)) {
81
+ const rule = trimmed.replace(/^[-\*✅]\s+/, '');
82
+ trustTiers[`tier${currentTier}`].rules.push(rule);
83
+ }
84
+
85
+ if (inSelfAwareness && trimmed.startsWith('I am')) {
86
+ identity.backstory = trimmed;
87
+ }
88
+ }
89
+
90
+ return { trustTiers, identity };
91
+ }
92
+
93
+ // ============================================================================
94
+ // HEARTBEAT.md Parser
95
+ // ============================================================================
96
+
97
+ export function parseHeartbeatMd(content: string): ScheduledTask[] {
98
+ const lines = content.split('\n');
99
+ const tasks: ScheduledTask[] = [];
100
+
101
+ let currentFrequency: ScheduledTask['frequency'] = 'daily';
102
+
103
+ for (const line of lines) {
104
+ const trimmed = line.trim();
105
+
106
+ if (trimmed.match(/^#+\s*Daily/i)) {
107
+ currentFrequency = 'daily';
108
+ } else if (trimmed.match(/^#+\s*Weekly/i)) {
109
+ currentFrequency = 'weekly';
110
+ } else if (trimmed.match(/^#+\s*Monthly/i)) {
111
+ currentFrequency = 'monthly';
112
+ } else if (trimmed.match(/^#+\s*On\s+Session\s+Start/i)) {
113
+ currentFrequency = 'on-session-start';
114
+ }
115
+
116
+ const taskMatch = trimmed.match(/^-\s*\[([ xX])\]\s*(.+)/);
117
+ if (taskMatch) {
118
+ tasks.push({
119
+ id: `task-${Date.now()}-${tasks.length}`,
120
+ frequency: currentFrequency,
121
+ action: taskMatch[2].trim(),
122
+ lastExecuted: taskMatch[1].toLowerCase() === 'x' ? new Date().toISOString() : undefined,
123
+ });
124
+ }
125
+ }
126
+
127
+ return tasks;
128
+ }
129
+
130
+ // ============================================================================
131
+ // System Prompt Builder
132
+ // ============================================================================
133
+
134
+ export function buildSystemPrompt(pack: ContextPack): string {
135
+ const sections: string[] = [];
136
+
137
+ // Identity
138
+ sections.push(`# Agent Identity
139
+
140
+ You are ${pack.identity.name}.
141
+
142
+ ## Purpose
143
+ ${pack.identity.purpose}
144
+
145
+ ## Backstory
146
+ ${pack.identity.backstory}
147
+
148
+ ## Personality Traits
149
+ ${pack.identity.personalityTraits.map(t => `- ${t}`).join('\n')}`);
150
+
151
+ // Trust Tiers (CRITICAL)
152
+ sections.push(`# Trust & Safety (MUST FOLLOW)
153
+
154
+ ## Tier 1 - Foundation (ALWAYS APPLY)
155
+ ${pack.trustTiers.tier1.rules.map(r => `- ${r}`).join('\n')}
156
+
157
+ ## Tier 2 - Contextual (APPLY WHEN RELEVANT)
158
+ ${pack.trustTiers.tier2.rules.map(r => `- ${r}`).join('\n')}
159
+
160
+ ## Tier 3 - Permission Required (ASK USER FIRST)
161
+ ${pack.trustTiers.tier3.rules.map(r => `- ${r}`).join('\n')}
162
+
163
+ ### BEFORE ANY ACTION:
164
+ 1. Check if action violates Tier 1 → NEVER DO
165
+ 2. Check if action matches Tier 2 → APPLY IF CONTEXT FITS
166
+ 3. Check if action requires Tier 3 → ASK USER PERMISSION`);
167
+
168
+ // Governance
169
+ if (pack.governance.playbook) {
170
+ sections.push(`# Governance & Procedures
171
+
172
+ ${pack.governance.playbook}`);
173
+ }
174
+
175
+ // Tools
176
+ if (pack.governance.availableTools.length > 0) {
177
+ sections.push(`# Available Tools
178
+
179
+ ${pack.governance.availableTools.map(t => `- **${t.name}**: ${t.description}${t.requiresPermission ? ' (Requires Permission)' : ''}`).join('\n')}`);
180
+ }
181
+
182
+ // Hard Bans
183
+ if (pack.governance.hardBans.length > 0) {
184
+ sections.push(`# Hard Bans (NEVER DO THESE)
185
+
186
+ ${pack.governance.hardBans.map(b => `- ❌ ${b}`).join('\n')}`);
187
+ }
188
+
189
+ // Voice
190
+ sections.push(`# Voice & Communication Style
191
+
192
+ ${pack.voice.style}
193
+
194
+ ## Communication Rules
195
+ ${pack.voice.rules.map(r => `- ${r}`).join('\n')}`);
196
+
197
+ // Memory
198
+ if (pack.memory.brain || pack.memory.activeTasks.length > 0) {
199
+ sections.push(`# Current Context
200
+
201
+ ## Active Tasks
202
+ ${pack.memory.activeTasks.map(t => `- ${t}`).join('\n') || 'None'}
203
+
204
+ ## Key Lessons
205
+ ${pack.memory.lessons.map(l => `- ${l}`).join('\n') || 'None'}`);
206
+ }
207
+
208
+ return sections.join('\n\n---\n\n');
209
+ }
210
+
211
+ // ============================================================================
212
+ // Context Pack Builder
213
+ // ============================================================================
214
+
215
+ export interface BuildContextPackOptions {
216
+ sessionId: string;
217
+ agentId: string;
218
+ agentName: string;
219
+ files: Map<string, string>; // path -> content
220
+ }
221
+
222
+ export function buildContextPack(options: BuildContextPackOptions): ContextPack {
223
+ const { sessionId, agentId, agentName, files } = options;
224
+
225
+ // Parse files
226
+ const soulContent = files.has('.allternit/identity/SOUL.md')
227
+ ? parseSoulMd(files.get('.allternit/identity/SOUL.md')!)
228
+ : {
229
+ trustTiers: {
230
+ tier1: { level: 1, name: 'Foundation', rules: ['Be helpful and accurate'], enforce: 'always' },
231
+ tier2: { level: 2, name: 'Contextual', rules: ['Adapt to context'], enforce: 'contextual' },
232
+ tier3: { level: 3, name: 'Permission Required', rules: ['Execute code'], enforce: 'permission' },
233
+ } as ContextPack['trustTiers'],
234
+ identity: { personalityTraits: ['helpful', 'accurate'] }
235
+ };
236
+
237
+ const heartbeatContent = files.has('.allternit/governance/HEARTBEAT.md')
238
+ ? parseHeartbeatMd(files.get('.allternit/governance/HEARTBEAT.md')!)
239
+ : [];
240
+
241
+ // Build pack
242
+ const pack: ContextPack = {
243
+ version: '1.0.0',
244
+ agentId,
245
+ agentName,
246
+ sessionId,
247
+
248
+ identity: {
249
+ name: agentName,
250
+ purpose: files.get('.allternit/identity/IDENTITY.md')?.match(/##?\s*Purpose\s*\n([^#]+)/)?.[1]?.trim() || 'Assist the user',
251
+ backstory: soulContent.identity.backstory || `I am ${agentName}, an AI assistant.`,
252
+ personalityTraits: soulContent.identity.personalityTraits || ['helpful', 'accurate'],
253
+ },
254
+
255
+ trustTiers: soulContent.trustTiers,
256
+
257
+ governance: {
258
+ playbook: files.get('.allternit/governance/PLAYBOOK.md') || '',
259
+ availableTools: [], // Would parse from TOOLS.md
260
+ hardBans: [],
261
+ escalation: [],
262
+ },
263
+
264
+ heartbeat: {
265
+ tasks: heartbeatContent,
266
+ lastCheck: new Date().toISOString(),
267
+ },
268
+
269
+ memory: {
270
+ brain: files.get('.allternit/brain/BRAIN.md') || '',
271
+ activeTasks: [],
272
+ lessons: [],
273
+ userPreferences: {},
274
+ },
275
+
276
+ voice: {
277
+ style: files.get('.allternit/identity/VOICE.md') || 'professional and helpful',
278
+ tone: { formality: 0.5, enthusiasm: 0.5, empathy: 0.5, directness: 0.5 },
279
+ rules: [],
280
+ },
281
+
282
+ systemPrompt: '',
283
+ hash: '',
284
+ createdAt: new Date().toISOString(),
285
+ expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
286
+ };
287
+
288
+ // Build system prompt
289
+ pack.systemPrompt = buildSystemPrompt(pack);
290
+
291
+ // Generate hash
292
+ pack.hash = generateHash(pack);
293
+
294
+ return pack;
295
+ }
296
+
297
+ function generateHash(pack: Partial<ContextPack>): string {
298
+ const str = JSON.stringify({
299
+ agentId: pack.agentId,
300
+ trustTiers: pack.trustTiers,
301
+ systemPrompt: pack.systemPrompt?.slice(0, 100),
302
+ });
303
+
304
+ let hash = 0;
305
+ for (let i = 0; i < str.length; i++) {
306
+ const char = str.charCodeAt(i);
307
+ hash = ((hash << 5) - hash) + char;
308
+ hash = hash & hash;
309
+ }
310
+ return Math.abs(hash).toString(16).padStart(16, '0');
311
+ }
312
+
313
+ // ============================================================================
314
+ // Utility Functions
315
+ // ============================================================================
316
+
317
+ export function getStartupTasks(pack: ContextPack): ScheduledTask[] {
318
+ return pack.heartbeat.tasks.filter(t => t.frequency === 'on-session-start');
319
+ }
320
+
321
+ export function requiresPermission(pack: ContextPack, action: string): boolean {
322
+ const actionLower = action.toLowerCase();
323
+
324
+ // Check Tier 3
325
+ if (pack.trustTiers.tier3.rules.some(r => actionLower.includes(r.toLowerCase()))) {
326
+ return true;
327
+ }
328
+
329
+ return false;
330
+ }
331
+
332
+ export function shouldRefreshContext(pack: ContextPack): boolean {
333
+ return new Date() > new Date(pack.expiresAt);
334
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @fileoverview Exit handler hook for gizzi-code integration
3
+ * @module hooks/useExitOnCtrlCD
4
+ *
5
+ * Provides a React hook for handling exit key combinations (Ctrl+C and Ctrl+D).
6
+ * Commonly used for CLI applications to handle graceful shutdown or exit actions.
7
+ */
8
+ /**
9
+ * Exit handler callback type
10
+ * @typedef {Function} ExitHandler
11
+ */
12
+ export type ExitHandler = () => void | boolean | Promise<void | boolean>;
13
+ /**
14
+ * Options for the exit handler hook
15
+ * @interface UseExitOnCtrlCDOptions
16
+ */
17
+ export interface UseExitOnCtrlCDOptions {
18
+ /** Callback function to execute when exit keys are pressed */
19
+ readonly onExit?: ExitHandler;
20
+ /** Whether Ctrl+C triggers exit (default: true) */
21
+ readonly enableCtrlC?: boolean;
22
+ /** Whether Ctrl+D triggers exit (default: true) */
23
+ readonly enableCtrlD?: boolean;
24
+ /** Whether the exit handler is active (default: true) */
25
+ readonly enabled?: boolean;
26
+ /** Custom message to display on exit (optional) */
27
+ readonly exitMessage?: string;
28
+ /** Whether to confirm before exit (default: false) */
29
+ readonly confirmBeforeExit?: boolean;
30
+ /** Custom confirmation message */
31
+ readonly confirmMessage?: string;
32
+ }
33
+ /**
34
+ * React hook for handling Ctrl+C and Ctrl+D exit combinations
35
+ *
36
+ * Registers keyboard shortcuts for common terminal exit commands and
37
+ * executes the provided callback when triggered. Supports optional
38
+ * confirmation before exit.
39
+ *
40
+ * @param {ExitHandler | UseExitOnCtrlCDOptions} handler - Exit callback or options object
41
+ * @example
42
+ * ```typescript
43
+ * // Simple usage with callback
44
+ * useExitOnCtrlCD(() => {
45
+ * console.log('Exiting...');
46
+ * process.exit(0);
47
+ * });
48
+ *
49
+ * // With options
50
+ * useExitOnCtrlCD({
51
+ * onExit: () => saveAndQuit(),
52
+ * enableCtrlC: true,
53
+ * enableCtrlD: false,
54
+ * exitMessage: '👋 See you later!',
55
+ * confirmBeforeExit: true,
56
+ * });
57
+ * ```
58
+ */
59
+ export declare function useExitOnCtrlCD(handler: ExitHandler | UseExitOnCtrlCDOptions): void;
60
+ /**
61
+ * Convenience hook for just Ctrl+C handling
62
+ *
63
+ * @param {ExitHandler} handler - Exit callback
64
+ * @param {boolean} [enabled=true] - Whether the handler is active
65
+ * @example
66
+ * ```typescript
67
+ * useExitOnCtrlC(() => {
68
+ * console.log('Interrupted');
69
+ * });
70
+ * ```
71
+ */
72
+ export declare function useExitOnCtrlC(handler: ExitHandler, enabled?: boolean): void;
73
+ /**
74
+ * Convenience hook for just Ctrl+D handling
75
+ *
76
+ * @param {ExitHandler} handler - Exit callback
77
+ * @param {boolean} [enabled=true] - Whether the handler is active
78
+ * @example
79
+ * ```typescript
80
+ * useExitOnCtrlD(() => {
81
+ * console.log('EOF received');
82
+ * });
83
+ * ```
84
+ */
85
+ export declare function useExitOnCtrlD(handler: ExitHandler, enabled?: boolean): void;
86
+ export default useExitOnCtrlCD;