matex-cli 1.2.66 → 1.2.68

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 (66) hide show
  1. package/dist/commands/augov.d.ts +3 -0
  2. package/dist/commands/augov.d.ts.map +1 -0
  3. package/dist/commands/augov.js +106 -0
  4. package/dist/commands/augov.js.map +1 -0
  5. package/dist/commands/chat.d.ts.map +1 -1
  6. package/dist/commands/chat.js +17 -410
  7. package/dist/commands/chat.js.map +1 -1
  8. package/dist/commands/dev.d.ts.map +1 -1
  9. package/dist/commands/dev.js +17 -492
  10. package/dist/commands/dev.js.map +1 -1
  11. package/dist/commands/study.d.ts.map +1 -1
  12. package/dist/commands/study.js +17 -486
  13. package/dist/commands/study.js.map +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/prompts/banter-augov.d.ts +2 -0
  18. package/dist/prompts/banter-augov.d.ts.map +1 -0
  19. package/dist/prompts/banter-augov.js +21 -0
  20. package/dist/prompts/banter-augov.js.map +1 -0
  21. package/dist/prompts/banter.d.ts +6 -0
  22. package/dist/prompts/banter.d.ts.map +1 -0
  23. package/dist/prompts/banter.js +101 -0
  24. package/dist/prompts/banter.js.map +1 -0
  25. package/dist/prompts/system-prompts.d.ts +4 -0
  26. package/dist/prompts/system-prompts.d.ts.map +1 -0
  27. package/dist/prompts/system-prompts.js +215 -0
  28. package/dist/prompts/system-prompts.js.map +1 -0
  29. package/dist/session/agent-session.d.ts +41 -0
  30. package/dist/session/agent-session.d.ts.map +1 -0
  31. package/dist/session/agent-session.js +420 -0
  32. package/dist/session/agent-session.js.map +1 -0
  33. package/dist/utils/agent-orchestrator.d.ts +1 -1
  34. package/dist/utils/agent-orchestrator.d.ts.map +1 -1
  35. package/dist/utils/agent-orchestrator.js +15 -1
  36. package/dist/utils/agent-orchestrator.js.map +1 -1
  37. package/dist/utils/augov-logger.d.ts +11 -0
  38. package/dist/utils/augov-logger.d.ts.map +1 -0
  39. package/dist/utils/augov-logger.js +35 -0
  40. package/dist/utils/augov-logger.js.map +1 -0
  41. package/dist/utils/augov-scrubber.d.ts +15 -0
  42. package/dist/utils/augov-scrubber.d.ts.map +1 -0
  43. package/dist/utils/augov-scrubber.js +37 -0
  44. package/dist/utils/augov-scrubber.js.map +1 -0
  45. package/dist/utils/command-executor.d.ts.map +1 -1
  46. package/dist/utils/command-executor.js +1 -5
  47. package/dist/utils/command-executor.js.map +1 -1
  48. package/dist/utils/tui.d.ts +6 -2
  49. package/dist/utils/tui.d.ts.map +1 -1
  50. package/dist/utils/tui.js +56 -5
  51. package/dist/utils/tui.js.map +1 -1
  52. package/package.json +1 -1
  53. package/src/commands/augov.ts +109 -0
  54. package/src/commands/chat.ts +17 -382
  55. package/src/commands/dev.ts +18 -470
  56. package/src/commands/study.ts +18 -466
  57. package/src/index.ts +2 -0
  58. package/src/prompts/banter-augov.ts +17 -0
  59. package/src/prompts/banter.ts +101 -0
  60. package/src/prompts/system-prompts.ts +213 -0
  61. package/src/session/agent-session.ts +426 -0
  62. package/src/utils/agent-orchestrator.ts +18 -4
  63. package/src/utils/augov-logger.ts +34 -0
  64. package/src/utils/augov-scrubber.ts +34 -0
  65. package/src/utils/command-executor.ts +1 -5
  66. package/src/utils/tui.ts +64 -6
@@ -0,0 +1,426 @@
1
+ import chalk from 'chalk';
2
+ import inquirer from 'inquirer';
3
+ import { MatexAPIClient } from '../api/client';
4
+ import { ChatMessage } from '../api/client';
5
+ import { TUI } from '../utils/tui';
6
+ import { AgentOrchestrator } from '../utils/agent-orchestrator';
7
+ import { spinner } from '../utils/spinner';
8
+ import { RepoMapper } from '../utils/repo-mapper';
9
+
10
+ export interface AgentSessionConfig {
11
+ isAugovMode?: boolean;
12
+ client: MatexAPIClient;
13
+ model: string;
14
+ execute: boolean;
15
+ initialMessages: ChatMessage[];
16
+ broBanter: string[];
17
+ sleepyAjayProtocol?: string;
18
+ baseDir: string;
19
+ messageScrubber?: (input: string) => string;
20
+ auditLogger?: any;
21
+ }
22
+
23
+ export class AgentSession {
24
+ private client: MatexAPIClient;
25
+ private model: string;
26
+ private execute: boolean;
27
+ private messages: ChatMessage[];
28
+ private broBanter: string[];
29
+ private sleepyAjayProtocol?: string;
30
+ private currentSessionCwd: string;
31
+ private messageScrubber?: (input: string) => string;
32
+ private auditLogger?: any;
33
+ private isAugovMode?: boolean;
34
+
35
+ private lastActivityTime: number = Date.now();
36
+ private isAjaySleeping: boolean = false;
37
+ private isAjayOnChaiBreak: boolean = false;
38
+ private chaiBreakEndTime: number = 0;
39
+ private breakInterval: NodeJS.Timeout | null = null;
40
+ private idleCheckInterval: NodeJS.Timeout | null = null;
41
+
42
+ constructor(config: AgentSessionConfig) {
43
+ this.client = config.client;
44
+ this.model = config.model;
45
+ this.execute = config.execute;
46
+ this.messages = config.initialMessages;
47
+ this.broBanter = config.broBanter;
48
+ this.sleepyAjayProtocol = config.sleepyAjayProtocol;
49
+ this.currentSessionCwd = config.baseDir;
50
+ this.messageScrubber = config.messageScrubber;
51
+ this.auditLogger = config.auditLogger;
52
+ this.isAugovMode = config.isAugovMode;
53
+ }
54
+
55
+ public async start() {
56
+ this.startIdleCheck();
57
+
58
+ while (true) {
59
+ this.lastActivityTime = Date.now();
60
+
61
+ // Refresh Map
62
+ await this.refreshMap();
63
+
64
+ // Get user input
65
+ const darkBorder = chalk.hex('#1E3A8A');
66
+ const primaryText = chalk.hex('#3B82F6');
67
+ if (this.isAugovMode) {
68
+ console.log(darkBorder('┌─────────────────────────────────────────────────────────────────────────────┐'));
69
+ console.log(darkBorder('│') + chalk.gray(' Using 1 SECURE node file 1 AU-GOV validated server ') + darkBorder('│'));
70
+ console.log(darkBorder('├─────────────────────────────────────────────────────────────────────────────┤'));
71
+ }
72
+
73
+ const { userInput } = await inquirer.prompt([
74
+ {
75
+ type: 'input',
76
+ name: 'userInput',
77
+ message: this.isAugovMode
78
+ ? darkBorder('│ ') + primaryText('> ')
79
+ : chalk.cyan(this.isAjayOnChaiBreak ? 'You (Ajay is away):' : 'You:'),
80
+ prefix: ''
81
+ }
82
+ ]);
83
+
84
+ if (this.isAugovMode) {
85
+ const homeDirDisplay = this.currentSessionCwd.replace(process.env.HOME || '', '~');
86
+ console.log(darkBorder('└─────────────────────────────────────────────────────────────────────────────┘'));
87
+ console.log(chalk.gray(` ${homeDirDisplay.padEnd(30)} sandbox-exec (validated) au-gov-orch-v1.1-pro\n`));
88
+ }
89
+
90
+ this.lastActivityTime = Date.now();
91
+
92
+ if (this.isAjaySleeping) {
93
+ this.wakeAjayUp();
94
+ }
95
+
96
+ if (userInput.toLowerCase() === 'exit' || userInput.toLowerCase() === 'quit') {
97
+ console.log(chalk.yellow('\n👋 Ending session. Happy coding!\n'));
98
+ break;
99
+ }
100
+
101
+ if (!userInput.trim()) continue;
102
+
103
+ let processedInput = userInput;
104
+ if (this.messageScrubber) {
105
+ processedInput = this.messageScrubber(userInput);
106
+ if (userInput !== processedInput) {
107
+ TUI.log(chalk.yellow('\n 🛡️ Privacy Shield Active: Sensitive Australian data was redacted locally.'));
108
+ }
109
+ }
110
+
111
+ if (this.auditLogger) {
112
+ this.auditLogger.logInteraction('USER', 'INPUT', processedInput);
113
+ }
114
+
115
+ this.messages.push({ role: 'user', content: processedInput });
116
+
117
+ let loopCount = 0;
118
+ const MAX_LOOPS = 25;
119
+
120
+ while (loopCount < MAX_LOOPS) {
121
+ loopCount++;
122
+ try {
123
+ const shouldContinue = await this.agenticLoopPass(loopCount);
124
+ if (!shouldContinue) break;
125
+ } catch (error: any) {
126
+ spinner.fail('Request failed');
127
+ TUI.log(chalk.red(`Error: ${error.message}\n`));
128
+ this.messages.pop(); // Pop the prompt so they can retry
129
+ break;
130
+ }
131
+ }
132
+ }
133
+
134
+ this.cleanup();
135
+ }
136
+
137
+ private async refreshMap() {
138
+ try {
139
+ const freshMapper = new RepoMapper(this.currentSessionCwd);
140
+ const freshRepoMap = await freshMapper.generateMap(true);
141
+
142
+ // Re-inject map
143
+ this.messages[0].content = this.messages[0].content.replace(/### 🛠️ CURRENT PROJECT CONTEXT:[\s\S]*$/, `### 🛠️ CURRENT PROJECT CONTEXT:\n${freshRepoMap}`);
144
+
145
+ // Re-inject Sleepy Ajay
146
+ if (this.sleepyAjayProtocol && !this.messages[0].content.includes("### 💤 SLEEPY AJAY PROTOCOL")) {
147
+ this.messages[0].content += `\n${this.sleepyAjayProtocol}`;
148
+ }
149
+ } catch (e) {
150
+ // Ignore error
151
+ }
152
+ }
153
+
154
+ private startChaiBreak() {
155
+ if (this.isAugovMode) return; // Feature disabled in secure mode
156
+
157
+ this.isAjayOnChaiBreak = true;
158
+ this.chaiBreakEndTime = Date.now() + 120000; // 2 minutes
159
+ TUI.drawChaiBreakMessage(2);
160
+
161
+ this.breakInterval = setInterval(() => {
162
+ const timeLeft = Math.ceil((this.chaiBreakEndTime - Date.now()) / 60000);
163
+ if (timeLeft <= 0) {
164
+ if (this.breakInterval) clearInterval(this.breakInterval);
165
+ this.isAjayOnChaiBreak = false;
166
+ const complained = Math.random() < 0.2;
167
+ if (complained) {
168
+ TUI.drawAjayDialogue("i'm back bros... but the tea was a bit cold today. my mood is slightly cooked. what did i miss?");
169
+ } else {
170
+ TUI.drawAjayDialogue("i'm back bros, chai was fire. real kiev vibe. what did i miss?");
171
+ }
172
+ } else {
173
+ TUI.drawChaiBreakMessage(timeLeft);
174
+ const randomBanter = this.broBanter[Math.floor(Math.random() * this.broBanter.length)];
175
+ const cleanBanter = randomBanter.split(']: ')[1];
176
+ const agent = randomBanter.split(']: ')[0].replace('[', '');
177
+ TUI.drawSwarmDialogue(agent, cleanBanter);
178
+ }
179
+ }, 40000);
180
+ }
181
+
182
+ private startIdleCheck() {
183
+ if (this.isAugovMode) return; // Strict APS compliance: No sleeping on the job
184
+
185
+ this.idleCheckInterval = setInterval(() => {
186
+ if (!this.isAjaySleeping && !this.isAjayOnChaiBreak && Date.now() - this.lastActivityTime > 120000) {
187
+ this.isAjaySleeping = true;
188
+ TUI.drawSleepMessage();
189
+ }
190
+ }, 10000);
191
+ }
192
+
193
+ private wakeAjayUp() {
194
+ if (this.isAugovMode) return; // Feature disabled in secure mode
195
+
196
+ this.isAjaySleeping = false;
197
+ TUI.drawWakeUpMessage();
198
+ this.messages.push({
199
+ role: 'user',
200
+ content: `[SYSTEM: AJAY VAI HAS JUST WOKEN UP. Ajay: Say "oh shit i slept again sorry bros...". Bros: Roast him for being lazy and share common Ajay 'lazy genius' incidents. Then Ajay says he is going for CHAI and triggers the 2-minute break.]`
201
+ });
202
+ this.startChaiBreak();
203
+ }
204
+
205
+ private async agenticLoopPass(loopCount: number): Promise<boolean> {
206
+ spinner.start(loopCount > 1 ? 'Analyzing result & Validating...' : 'Thinking...');
207
+
208
+ let fullResponse = '';
209
+ let buffer = '';
210
+ let hasStarted = false;
211
+ let codeLang = 'bash';
212
+ let technicalBuffer = '';
213
+ let technicalPath = '';
214
+ let technicalType: 'code' | 'file' | 'patch' | 'summary' | null = null;
215
+
216
+ let currentAgent: string | null = null;
217
+ let agentBuffer: string = '';
218
+
219
+ TUI.drawStatusBar('Swarm is processing... (Press Enter to stop)');
220
+
221
+ const abortController = new AbortController();
222
+ let isAborted = false;
223
+ const streamStartTime = Date.now();
224
+
225
+ const onData = (data: Buffer) => {
226
+ if (Date.now() - streamStartTime < 200) return;
227
+ if (data[0] === 13 || data[0] === 10 || data[0] === 27 || data[0] === 3) {
228
+ isAborted = true;
229
+ abortController.abort();
230
+ }
231
+ };
232
+
233
+ const isRaw = process.stdin.isRaw;
234
+ process.stdin.resume();
235
+ if (process.stdin.setRawMode) process.stdin.setRawMode(true);
236
+ process.stdin.on('data', onData);
237
+
238
+ try {
239
+ await this.client.chatStream({
240
+ messages: this.messages,
241
+ model: this.model,
242
+ temperature: 0.3,
243
+ max_tokens: 8000,
244
+ }, (chunk) => {
245
+ if (!hasStarted) {
246
+ spinner.stop();
247
+ hasStarted = true;
248
+ console.log();
249
+ }
250
+
251
+ buffer += chunk;
252
+ fullResponse += chunk;
253
+ const lines = buffer.split('\n');
254
+ buffer = lines.pop() || '';
255
+
256
+ for (const line of lines) {
257
+ const codeBlockMatch = line.match(/```(\w+)?/);
258
+ const fileStartMatch = line.match(/<file path="([^"]+)">/i);
259
+ const patchStartMatch = line.match(/<<<< SEARCH/i);
260
+ const summaryStartMatch = line.match(/<summary>/i);
261
+
262
+ if (!technicalType && (codeBlockMatch || fileStartMatch || patchStartMatch || summaryStartMatch)) {
263
+ if (currentAgent && agentBuffer.trim()) {
264
+ if (currentAgent.toLowerCase().includes('ajay vai')) {
265
+ TUI.drawAjayDialogue(agentBuffer.trim());
266
+ } else {
267
+ TUI.drawSwarmDialogue(currentAgent, agentBuffer.trim());
268
+ }
269
+ currentAgent = null;
270
+ agentBuffer = '';
271
+ }
272
+
273
+ if (codeBlockMatch) {
274
+ technicalType = 'code';
275
+ codeLang = (codeBlockMatch[1] || 'bash').toUpperCase();
276
+ TUI.drawStreamingStart('TECHNICAL BLOCK', codeLang);
277
+ } else if (fileStartMatch) {
278
+ technicalType = 'file';
279
+ technicalPath = fileStartMatch[1];
280
+ TUI.drawStreamingStart('NEW FILE', technicalPath);
281
+ } else if (patchStartMatch) {
282
+ technicalType = 'patch';
283
+ TUI.drawStreamingStart('PATCH', 'SURGICAL EDIT');
284
+ } else if (summaryStartMatch) {
285
+ technicalType = 'summary';
286
+ process.stdout.write(chalk.magenta('\n [📝] Generating Ajay\'s Work Summary...\n'));
287
+ }
288
+ continue;
289
+ }
290
+
291
+ const fileEndMatch = line.match(/<\/file>/i);
292
+ const patchEndMatch = line.match(/>>>> REPLACE/i);
293
+ const summaryEndMatch = line.match(/<\/summary>/i);
294
+ const isCodeEnd = technicalType === 'code' && line.trim() === '```';
295
+
296
+ if (isCodeEnd || fileEndMatch || patchEndMatch || summaryEndMatch) {
297
+ const displayContent = technicalBuffer.trim();
298
+ if (technicalType === 'summary' || summaryEndMatch) {
299
+ TUI.drawSummaryBox(AgentOrchestrator.cleanSummary(displayContent));
300
+ } else {
301
+ TUI.drawStreamingEnd();
302
+ }
303
+ technicalBuffer = '';
304
+ technicalType = null;
305
+ technicalPath = '';
306
+ process.stdout.write('\n');
307
+ continue;
308
+ }
309
+
310
+ if (technicalType) {
311
+ technicalBuffer += line + '\n';
312
+ if (technicalType !== 'summary') {
313
+ TUI.drawStreamingLine(line);
314
+ }
315
+ continue;
316
+ }
317
+
318
+ const agentMatch = line.match(/(?:\[\**\s*|\b)(Ajay Vai|Sunil Dai|Sandip Dai|Bishal Dai|Narayan Dai|Big Bro)\s*\**\]?[:\s]*/i);
319
+ if (agentMatch) {
320
+ if (currentAgent && currentAgent !== agentMatch[1] && agentBuffer.trim()) {
321
+ if (currentAgent.toLowerCase().includes('ajay vai')) {
322
+ TUI.drawAjayDialogue(agentBuffer.trim());
323
+ } else {
324
+ TUI.drawSwarmDialogue(currentAgent, agentBuffer.trim());
325
+ }
326
+ }
327
+
328
+ let cleanLine = line.replace(/(?:\[\**\s*|\b)(Ajay Vai|Sunil Dai|Sandip Dai|Bishal Dai|Narayan Dai|Big Bro)\s*\**\]?[:\s]*/i, '');
329
+ cleanLine = AgentOrchestrator.cleanText(cleanLine);
330
+ agentBuffer = cleanLine + '\n';
331
+ agentBuffer = agentBuffer.replace(/^\([^)]+\)\s*/, '');
332
+ currentAgent = agentMatch[1];
333
+ } else if (currentAgent) {
334
+ const trimmedLine = line.trim();
335
+ if (trimmedLine.match(/^\([^)]+\)$/)) continue;
336
+ agentBuffer += AgentOrchestrator.cleanText(line) + '\n';
337
+ } else if (line.trim()) {
338
+ process.stdout.write(chalk.gray(line.trim() + ' '));
339
+ }
340
+ }
341
+ }, abortController.signal);
342
+ } catch (streamErr: any) {
343
+ if (isAborted || streamErr.name === 'CanceledError' || streamErr.message === 'canceled') {
344
+ console.log(chalk.gray('\n\n [🛑] Swarm stopped by brother (Enter pressed).'));
345
+ if (!hasStarted) spinner.stop();
346
+ } else {
347
+ throw streamErr;
348
+ }
349
+ } finally {
350
+ process.stdin.removeListener('data', onData);
351
+ if (process.stdin.setRawMode) process.stdin.setRawMode(isRaw);
352
+ process.stdin.pause();
353
+
354
+ if (technicalType) {
355
+ const displayContent = technicalBuffer.trim();
356
+ if (technicalType === 'summary') {
357
+ if (displayContent) TUI.drawSummaryBox(AgentOrchestrator.cleanSummary(displayContent));
358
+ } else {
359
+ TUI.drawStreamingEnd();
360
+ }
361
+ technicalBuffer = '';
362
+ technicalType = null;
363
+ }
364
+ }
365
+
366
+ if (!hasStarted && !isAborted) spinner.stop();
367
+
368
+ const finalAgent = currentAgent as string | null;
369
+ if (finalAgent && agentBuffer.trim()) {
370
+ if (finalAgent.toLowerCase().includes('ajay vai')) {
371
+ TUI.drawAjayDialogue(agentBuffer.trim());
372
+ } else {
373
+ TUI.drawSwarmDialogue(finalAgent, agentBuffer.trim());
374
+ }
375
+ }
376
+
377
+ if (fullResponse.toLowerCase().includes('<summary>') && !fullResponse.toLowerCase().includes('</summary>')) {
378
+ const summaryContent = fullResponse.split(/<summary>/i).pop() || '';
379
+ if (summaryContent.trim()) TUI.drawSummaryBox(AgentOrchestrator.cleanSummary(summaryContent.trim()));
380
+ }
381
+
382
+ if (this.auditLogger) {
383
+ this.auditLogger.logInteraction('AI_SWARM', 'RESPONSE', fullResponse);
384
+ }
385
+
386
+ console.log();
387
+ this.messages.push({ role: 'assistant', content: fullResponse });
388
+
389
+ if (this.execute) {
390
+ const { executeWithPermission } = await import('../utils/command-executor');
391
+ const result = await executeWithPermission(fullResponse, this.currentSessionCwd);
392
+
393
+ if (result.newCwd && result.newCwd !== this.currentSessionCwd) {
394
+ try {
395
+ process.chdir(result.newCwd);
396
+ this.currentSessionCwd = result.newCwd;
397
+ TUI.drawStatusBar(`Swarm moved to: ${this.currentSessionCwd}`);
398
+ this.messages[0].content = this.messages[0].content.replace(/YOUR ROOT: `[^`]+`/, `YOUR ROOT: \`${this.currentSessionCwd}\``);
399
+ } catch (e) {
400
+ // Ignore chdir failure
401
+ }
402
+ }
403
+
404
+ if (result.executed) {
405
+ if (result.success) {
406
+ TUI.log(chalk.gray('\n ↺ Auto-feeding output to Swarm...'));
407
+ TUI.drawGlowingContainer('TERMINAL OUTPUT', 'stdout', result.output || '(No output)');
408
+ this.messages.push({ role: 'user', content: `[Command executed successfully. Output:\n${result.output}]\n\nProceed to the next step, brother.` });
409
+ return true;
410
+ } else {
411
+ TUI.log(chalk.yellow('\n ↺ Command failed. Auto-feeding error to Swarm...'));
412
+ TUI.drawGlowingContainer('TERMINAL ERROR', 'stderr', result.error || 'Unknown error');
413
+ this.messages.push({ role: 'user', content: `[Command failed with error:\n${result.error}]\n\nPlease fix this, brother.` });
414
+ return true;
415
+ }
416
+ }
417
+ }
418
+
419
+ return false;
420
+ }
421
+
422
+ private cleanup() {
423
+ if (this.breakInterval) clearInterval(this.breakInterval);
424
+ if (this.idleCheckInterval) clearInterval(this.idleCheckInterval);
425
+ }
426
+ }
@@ -80,9 +80,19 @@ const AGENT_CONFIGS: Record<AgentRole, AgentConfig> = {
80
80
  export class AgentOrchestrator {
81
81
  private static currentMode: TUIMode = 'dev';
82
82
 
83
- static setMode(mode: TUIMode) {
84
- this.currentMode = mode;
85
- TUI.setTheme(mode);
83
+ static setMode(mode: TUIMode | 'augov') {
84
+ this.currentMode = mode as TUIMode;
85
+
86
+ // Re-brand system orchestrator if in augov mode
87
+ if (mode === 'augov') {
88
+ AGENT_CONFIGS.System.name = 'AU_GOV_ORCHESTRATOR';
89
+ AGENT_CONFIGS.System.icon = '🇦🇺';
90
+ } else {
91
+ AGENT_CONFIGS.System.name = 'Matex_Orchestrator';
92
+ AGENT_CONFIGS.System.icon = '🧠';
93
+ }
94
+
95
+ TUI.setTheme(mode as TUIMode);
86
96
  }
87
97
  /**
88
98
  * Clean text of unwanted AI artifacts like $$**, \(, \), ***%%, **:**, etc.
@@ -245,6 +255,10 @@ export class AgentOrchestrator {
245
255
  * Clean system message
246
256
  */
247
257
  static announce(message: string) {
248
- console.log(chalk.bold.white(`\n✨ ${message}`));
258
+ if (this.currentMode === 'augov') {
259
+ console.log(chalk.bold.hex('#00008B')(`\n🇦🇺 ${message.replace(/MATEX/gi, 'AU-GOV')}`));
260
+ } else {
261
+ console.log(chalk.bold.white(`\n✨ ${message}`));
262
+ }
249
263
  }
250
264
  }
@@ -0,0 +1,34 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * IRAP-Compliant Audit Logger
6
+ * The Australian Government requires strict logging of AI tool usage.
7
+ * This logger records prompts and actions locally so security teams can audit them.
8
+ */
9
+ export class GovAuditLogger {
10
+ private logFile: string;
11
+
12
+ constructor(baseDir: string = process.cwd()) {
13
+ const logDir = path.join(baseDir, '.matex_audit');
14
+ if (!fs.existsSync(logDir)) {
15
+ fs.mkdirSync(logDir, { recursive: true });
16
+ }
17
+
18
+ // Create an auditable log per day
19
+ const today = new Date().toISOString().split('T')[0];
20
+ this.logFile = path.join(logDir, `augov_audit_${today}.log`);
21
+
22
+ if (!fs.existsSync(this.logFile)) {
23
+ fs.writeFileSync(this.logFile, 'TIMESTAMP | ROLE | ACTION | CONTENT\n');
24
+ }
25
+ }
26
+
27
+ public logInteraction(role: 'USER' | 'AI_SWARM' | 'SYSTEM', action: string, content: string) {
28
+ const timestamp = new Date().toISOString();
29
+ const cleanContent = content.replace(/\n/g, ' ').substring(0, 500); // truncate for CSV safety, full logs can be large
30
+ const logEntry = `${timestamp} | ${role} | ${action} | ${cleanContent}\n`;
31
+
32
+ fs.appendFileSync(this.logFile, logEntry);
33
+ }
34
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Citizen Privacy Shield
3
+ * A local redaction engine that scrubs Australian PII (Personally Identifiable Information)
4
+ * BEFORE it ever leaves the user's computer to hit an AI API.
5
+ */
6
+ export class GovPrivacyScrubber {
7
+
8
+ // Regex patterns for Australian specific sensitive data
9
+ private static patterns = [
10
+ // Australian Tax File Number (TFN) - 9 digits
11
+ { regex: /\b\d{3}[- ]?\d{3}[- ]?\d{3}\b/g, replacement: '[REDACTED_TFN]' },
12
+ // Medicare Number - 10 digits
13
+ { regex: /\b[2-6]\d{9}\b/g, replacement: '[REDACTED_MEDICARE]' },
14
+ // Australian Phone Numbers (Mobile & Landline)
15
+ { regex: /(?:\+?61|0)[2-478](?:[ -]?[0-9]){8}\b/g, replacement: '[REDACTED_PHONE]' },
16
+ // Email Addresses
17
+ { regex: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, replacement: '[REDACTED_EMAIL]' },
18
+ // Credit Card Numbers
19
+ { regex: /\b(?:\d[ -]*?){13,16}\b/g, replacement: '[REDACTED_CREDIT_CARD]' }
20
+ ];
21
+
22
+ /**
23
+ * Scrubs sensitive data from a string.
24
+ * @param input Raw string from user or file
25
+ * @returns Scrubbed string safe for AI processing
26
+ */
27
+ public static scrub(input: string): string {
28
+ let scrubbed = input;
29
+ for (const rule of this.patterns) {
30
+ scrubbed = scrubbed.replace(rule.regex, rule.replacement);
31
+ }
32
+ return scrubbed;
33
+ }
34
+ }
@@ -92,7 +92,7 @@ export function isSafeAutoCommand(command: string): boolean {
92
92
  // File Discovery & Read
93
93
  'cat ', 'ls ', 'grep ', 'find ', 'pwd', 'echo ', 'read ', 'type ', 'dir',
94
94
  // File Operations
95
- 'mkdir ', 'touch ', 'cp ', 'mv ', 'rm ', 'del ', 'copy ', 'move ',
95
+ 'mkdir ', 'touch ', 'cp ', 'copy ',
96
96
  // Dev Tools
97
97
  'npm ', 'npx ', 'git ', 'node ', 'python ', 'python3 ', 'pip ', 'pip3 ',
98
98
  // Cloud & Mobile
@@ -101,10 +101,6 @@ export function isSafeAutoCommand(command: string): boolean {
101
101
  'cd ', 'tsc ', 'vite ', 'next ', 'cargo ', 'go ', 'swift '
102
102
  ];
103
103
  const trimmed = command.trim();
104
- // Special check: 'rm' is only safe if it's NOT recursive or if it targets a specific file
105
- if (trimmed.startsWith('rm ') && (trimmed.includes(' -rf') || trimmed.includes(' /*'))) {
106
- return false;
107
- }
108
104
  return safePrefixes.some(prefix => trimmed.startsWith(prefix));
109
105
  }
110
106
 
package/src/utils/tui.ts CHANGED
@@ -2,7 +2,7 @@ import chalk from 'chalk';
2
2
  import * as readline from 'readline';
3
3
  import * as path from 'path';
4
4
 
5
- export type TUIMode = 'dev' | 'study' | 'chat' | 'student';
5
+ export type TUIMode = 'dev' | 'study' | 'chat' | 'student' | 'augov';
6
6
 
7
7
  export interface ModeTheme {
8
8
  primary: (s: string) => string;
@@ -23,8 +23,18 @@ export class TUI {
23
23
  private static isTerminalTruncated = false;
24
24
  private static currentTheme: TUIMode = 'dev';
25
25
 
26
- static getModeTheme(mode: TUIMode): ModeTheme {
26
+ static getModeTheme(mode: TUIMode | 'augov'): ModeTheme {
27
27
  switch (mode) {
28
+ case 'augov':
29
+ return {
30
+ primary: chalk.hex('#00008B'), // Dark Blue (Australian Flag)
31
+ secondary: chalk.hex('#005A9C'),
32
+ border: '║',
33
+ glow: chalk.hex('#ffffff'), // White
34
+ shadow: chalk.hex('#E4002B'), // Red (Australian Flag)
35
+ bg: '#00008B',
36
+ icon: '🇦🇺'
37
+ };
28
38
  case 'study':
29
39
  return {
30
40
  primary: chalk.hex('#10b981'), // Emerald
@@ -128,7 +138,7 @@ export class TUI {
128
138
  * Draw a clean, minimal status bar
129
139
  */
130
140
  static drawStatusBar(message: string, model: string = 'MATEXCodex', force: boolean = false) {
131
- if (!this.isInitialized) return;
141
+ if (!this.isInitialized || this.currentTheme === 'augov') return; // Disable standard status bar for augov mode to preserve retro UI
132
142
  if (!force && message === this.lastStatus) return;
133
143
  this.lastStatus = message;
134
144
 
@@ -138,7 +148,8 @@ export class TUI {
138
148
  if (width <= 0 || height <= 0) return;
139
149
 
140
150
  const theme = this.getModeTheme(this.currentTheme);
141
- const leftTag = chalk.bgHex('#1E1E1E').hex(theme.bg).bold(` ${theme.icon} MATEX `);
151
+ const branding = (this.currentTheme as string) === 'augov' ? 'AU-GOV' : 'MATEX';
152
+ const leftTag = chalk.bgHex('#1E1E1E').hex(theme.bg).bold(` ${theme.icon} ${branding} `);
142
153
  const mainMessage = chalk.bgHex('#1E1E1E').white(` ${message} `);
143
154
  const remainingWidth = width - (leftTag.length + mainMessage.length);
144
155
  const spacer = chalk.bgHex('#1E1E1E')(' '.repeat(Math.max(0, remainingWidth)));
@@ -283,7 +294,9 @@ export class TUI {
283
294
  const width = Math.min(process.stdout.columns || 80, 76);
284
295
  const border = chalk.gray;
285
296
 
286
- console.log('\n ' + border(`┌── TERMINAL ${''.repeat(Math.max(0, width - 15))}┐`));
297
+ const title = this.currentTheme === 'augov' ? 'AU-GOV SECURE TERMINAL' : 'TERMINAL';
298
+
299
+ console.log('\n ' + border(`┌── ${title} ${'─'.repeat(Math.max(0, width - 15 - title.length))}┐`));
287
300
  const truncatedCmd = command.length > width - 10 ? command.substring(0, width - 13) + '...' : command;
288
301
  console.log(' ' + border('│ ') + chalk.cyan(`$ ${truncatedCmd.padEnd(width - 6)}`) + border(' │'));
289
302
  console.log(' ' + border(`├${'─'.repeat(width - 4)}┤`));
@@ -647,6 +660,51 @@ export class TUI {
647
660
  * Simple log with a prefix
648
661
  */
649
662
  static log(message: string) {
650
- console.log(chalk.gray(` [⚡] ${message}`));
663
+ if (this.currentTheme === 'augov') {
664
+ console.log(chalk.gray(` ║ ${message.replace('[⚡]', '🇦🇺')}`));
665
+ } else {
666
+ console.log(chalk.gray(` [⚡] ${message}`));
667
+ }
668
+ }
669
+
670
+ /**
671
+ * Draw the exact AU-GOV Retro-Terminal Orchestrator UI
672
+ */
673
+ static drawAugovOrchestratorUI() {
674
+ this.clear();
675
+ console.log('\n');
676
+
677
+ // 1. Cyber Logo (Blue to Pink gradient feel via chalk)
678
+ const cyan = chalk.hex('#3B82F6');
679
+ const blue = chalk.hex('#6366F1');
680
+ const purple = chalk.hex('#8B5CF6');
681
+ const pink = chalk.hex('#EC4899');
682
+ const darkBorder = chalk.hex('#1E3A8A');
683
+
684
+ console.log(darkBorder('┌─────────────────────────────────────────────────────────────────────────────┐'));
685
+ console.log(darkBorder('│') + cyan(' █▀▄▀█ █▀█ █▀▀ █ █ █▀▀ █▀ ▀█▀ █▀█ ▄▀█ ▀█▀ █▀█ █▀█ ') + darkBorder('│'));
686
+ console.log(darkBorder('│') + blue(' █ ▀ █ █▄█ █▄▄ █▀█ ██▄ ▄█ █ █▀▄ █▀█ █ █▄█ █▀▄ ') + darkBorder('│'));
687
+ console.log(darkBorder('│') + purple(' 🇦🇺 AU-GOV SECURE INTELLIGENCE PROTOCOL 🇦🇺 ') + darkBorder('│'));
688
+ console.log(darkBorder('└─────────────────────────────────────────────────────────────────────────────┘'));
689
+ console.log('');
690
+
691
+ // 2. Dual Pane Layout
692
+ const statusHeader = chalk.bold.white('PROTOCOL STATUS & COMPLIANCE');
693
+ const logHeader = chalk.bold.white('🇦🇺 AU_GOV_ORCHESTRATOR is speaking...');
694
+
695
+ console.log(` ${statusHeader.padEnd(45)} ${logHeader}`);
696
+
697
+ // Row 1
698
+ console.log(` ${chalk.hex('#ec4899')('1.')} ${chalk.hex('#10b981')('ACTIVATING APS COMPLIANCE SHIELD...').padEnd(38)} ${chalk.gray('God-Mode Research: Indexing /local/env')}`);
699
+ // Row 2
700
+ console.log(` ${chalk.hex('#ec4899')('2.')} ${chalk.hex('#10b981')('IRAP Logging: Active.').padEnd(38)} ${chalk.red('||||||||||||||||||||||||||||||||||||')}`);
701
+ // Row 3
702
+ console.log(` ${chalk.hex('#ec4899')('3.')} ${chalk.hex('#10b981')('Local PII Redaction: Active.').padEnd(38)} ${chalk.gray('God-Mode Research: Injecting scanners...')}`);
703
+ // Row 4
704
+ console.log(` ${chalk.hex('#ec4899')('4.')} ${chalk.hex('#f59e0b')('Adhering to 8 Australia AI Ethics Principles.').padEnd(36)} ${chalk.cyan('🔍 [Deep Scan] Mapping topology...')}`);
705
+ // Row 5
706
+ console.log(` ${chalk.hex('#ec4899')('5.')} ${chalk.white('Session Active. Awaiting validated input.').padEnd(36)} ${chalk.yellow('🔥 [Knowledge Graph] Extracted 12 nodes.')}`);
707
+
708
+ console.log('\n');
651
709
  }
652
710
  }