codeep 1.0.123 → 1.0.124

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.js CHANGED
@@ -21,7 +21,7 @@ import { MessageList } from './components/MessageList.js';
21
21
  import { chat } from './api/index.js';
22
22
  import { config, loadApiKey, loadAllApiKeys, PROTOCOLS, LANGUAGES, autoSaveSession, startNewSession, getCurrentSessionId, renameSession, deleteSession, hasReadPermission, hasWritePermission, setProjectPermission, setProvider, getCurrentProvider, getModelsForCurrentProvider, PROVIDERS } from './config/index.js';
23
23
  import { getProviderList } from './config/providers.js';
24
- import { isProjectDirectory, getProjectContext, detectFilePaths, readProjectFile, parseFileChanges, writeProjectFile, deleteProjectFile } from './utils/project.js';
24
+ import { isProjectDirectory, getProjectContext, detectFilePaths, readProjectFile, parseFileChanges, writeProjectFile, deleteProjectFile, getProjectTip } from './utils/project.js';
25
25
  import { logStartup, setLogProjectPath } from './utils/logger.js';
26
26
  import { searchMessages } from './utils/search.js';
27
27
  import { exportMessages, saveExport } from './utils/export.js';
@@ -1264,14 +1264,14 @@ export const App = () => {
1264
1264
  if (permanent) {
1265
1265
  // Save permission to local .codeep/config.json
1266
1266
  setProjectPermission(projectPath, true, writeGranted);
1267
- notify(writeGranted
1268
- ? 'Project access granted (read + write, permanent)'
1269
- : 'Project access granted (read-only, permanent)');
1267
+ }
1268
+ // Show project tip with type and suggested commands
1269
+ const tip = getProjectTip(projectPath);
1270
+ if (tip) {
1271
+ notify(tip, 5000);
1270
1272
  }
1271
1273
  else {
1272
- notify(writeGranted
1273
- ? 'Project access granted (read + write, this session)'
1274
- : 'Project access granted (read-only, this session)');
1274
+ notify(writeGranted ? 'Project access granted (read + write)' : 'Project access granted (read-only)');
1275
1275
  }
1276
1276
  // Warn user if Agent Mode is ON but write access was not granted
1277
1277
  const agentMode = config.get('agentMode');
@@ -1323,7 +1323,7 @@ export const App = () => {
1323
1323
  const actionColor = change.action === 'delete' ? 'red' : change.action === 'edit' ? 'yellow' : 'green';
1324
1324
  const actionLabel = change.action === 'delete' ? 'DELETE' : change.action === 'edit' ? 'EDIT' : 'CREATE';
1325
1325
  return (_jsxs(Text, { children: ["\u2022 ", _jsxs(Text, { color: actionColor, children: ["[", actionLabel, "]"] }), " ", change.path, change.action !== 'delete' && change.content.includes('\n') && ` (${change.content.split('\n').length} lines)`] }, i));
1326
- }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["Apply changes? ", _jsx(Text, { color: "#f02a30", bold: true, children: "[Y/n]" })] }), _jsx(Text, { color: "cyan", children: "Press Y to apply, N or Esc to reject" })] })), notification && (_jsx(Box, { justifyContent: "center", children: _jsx(Text, { color: "cyan", children: notification }) })), !isInlineMenu && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "#f02a30", children: '─'.repeat(Math.max(20, stdout?.columns || 80)) }), _jsx(Box, { paddingX: 1, children: _jsx(ChatInput, { onSubmit: handleSubmit, disabled: isLoading || isAgentRunning || pendingFileChanges.length > 0, history: inputHistory, clearTrigger: clearInputTrigger }) }), _jsx(Text, { color: "#f02a30", children: '─'.repeat(Math.max(20, stdout?.columns || 80)) })] })), isInlineMenu && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "#f02a30", children: '─'.repeat(stdout?.columns || 80) }), screen === 'help' && _jsx(Help, {}), screen === 'status' && _jsx(Status, {}), screen === 'settings' && (_jsx(Settings, { onClose: () => setScreen('chat'), notify: notify, hasWriteAccess: hasWriteAccess, hasProjectContext: !!projectContext })), screen === 'sessions' && (_jsx(Sessions, { history: messages, onLoad: handleSessionLoad, onClose: () => setScreen('chat'), projectPath: projectPath })), screen === 'sessions-delete' && (_jsx(Sessions, { history: messages, onLoad: handleSessionLoad, onClose: () => setScreen('chat'), onDelete: (name) => {
1326
+ }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["Apply changes? ", _jsx(Text, { color: "#f02a30", bold: true, children: "[Y/n]" })] }), _jsx(Text, { color: "cyan", children: "Press Y to apply, N or Esc to reject" })] })), notification && (_jsx(Box, { justifyContent: "center", children: _jsx(Text, { color: "cyan", children: notification }) })), !isInlineMenu && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "#f02a30", children: '─'.repeat(Math.max(20, stdout?.columns || 80)) }), _jsx(Box, { paddingX: 1, children: _jsx(ChatInput, { onSubmit: handleSubmit, disabled: isLoading || isAgentRunning || pendingFileChanges.length > 0, history: inputHistory, clearTrigger: clearInputTrigger }) }), _jsx(Text, { color: "#f02a30", children: '─'.repeat(Math.max(20, stdout?.columns || 80)) })] })), isInlineMenu && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "#f02a30", children: '─'.repeat(stdout?.columns || 80) }), screen === 'help' && _jsx(Help, { projectPath: projectPath }), screen === 'status' && _jsx(Status, {}), screen === 'settings' && (_jsx(Settings, { onClose: () => setScreen('chat'), notify: notify, hasWriteAccess: hasWriteAccess, hasProjectContext: !!projectContext })), screen === 'sessions' && (_jsx(Sessions, { history: messages, onLoad: handleSessionLoad, onClose: () => setScreen('chat'), projectPath: projectPath })), screen === 'sessions-delete' && (_jsx(Sessions, { history: messages, onLoad: handleSessionLoad, onClose: () => setScreen('chat'), onDelete: (name) => {
1327
1327
  notify(`Deleted: ${name}`);
1328
1328
  setScreen('chat');
1329
1329
  }, deleteMode: true, projectPath: projectPath })), screen === 'logout' && (_jsx(LogoutPicker, { onLogout: (providerId) => {
@@ -1,2 +1,6 @@
1
1
  import React from 'react';
2
- export declare const Help: React.FC;
2
+ interface HelpProps {
3
+ projectPath?: string;
4
+ }
5
+ export declare const Help: React.FC<HelpProps>;
6
+ export {};
@@ -1,5 +1,7 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Text, Box } from 'ink';
3
- export const Help = () => {
4
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "#f02a30", bold: true, children: "Available Commands" }), _jsx(Text, { children: " " }), _jsxs(Box, { flexDirection: "row", gap: 2, children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/help" }), " - Show this help"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/status" }), " - Current status"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/settings" }), " - Adjust settings"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/sessions" }), " - Manage sessions"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/grant" }), " - Grant permissions"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/agent" }), " ", '<task>', " - Run agent"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/clear" }), " - Clear chat"] })] }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/model" }), " - Switch model"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/provider" }), " - Switch provider"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/diff" }), " - Review git changes"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/commit" }), " - Generate commit msg"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/export" }), " - Export chat"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/copy" }), " [n] - Copy code block"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/exit" }), " - Quit"] })] })] }), _jsx(Text, { children: " " }), _jsx(Text, { color: "cyan", children: "Type / to see autocomplete. Docs: github.com/VladoIvankovic/Codeep" })] }));
3
+ import { detectProjectFeatures } from '../utils/project.js';
4
+ export const Help = ({ projectPath }) => {
5
+ const features = projectPath ? detectProjectFeatures(projectPath) : null;
6
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "#f02a30", bold: true, children: "Available Commands" }), _jsx(Text, { children: " " }), _jsxs(Box, { flexDirection: "row", gap: 2, children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/help" }), " - Show this help"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/status" }), " - Current status"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/settings" }), " - Adjust settings"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/sessions" }), " - Manage sessions"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/grant" }), " - Grant permissions"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/agent" }), " ", '<task>', " - Run agent"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/clear" }), " - Clear chat"] })] }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/model" }), " - Switch model"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/provider" }), " - Switch provider"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/diff" }), " - Review git changes"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/commit" }), " - Generate commit msg"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/export" }), " - Export chat"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/copy" }), " [n] - Copy code block"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/exit" }), " - Quit"] })] })] }), features && (features.hasGit || features.hasPackageJson || features.hasPython || features.hasCargo || features.hasGoMod) && (_jsxs(_Fragment, { children: [_jsx(Text, { children: " " }), _jsx(Text, { color: "green", bold: true, children: "Suggested for this project:" }), _jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [features.hasGit && (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "/diff" }), " - Review your uncommitted changes"] })), features.hasGit && (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "/commit" }), " - AI-generated commit message"] })), features.hasPackageJson && (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "/agent npm run build" }), " - Build Node.js project"] })), features.hasPython && (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "/agent pytest" }), " - Run Python tests"] })), features.hasCargo && (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "/agent cargo build" }), " - Build Rust project"] })), features.hasGoMod && (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: "/agent go build" }), " - Build Go project"] }))] })] })), _jsx(Text, { children: " " }), _jsx(Text, { color: "cyan", children: "Type / to see autocomplete. Docs: github.com/VladoIvankovic/Codeep" })] }));
5
7
  };
@@ -48,21 +48,55 @@ function isProjectDirectory(path) {
48
48
  ];
49
49
  return projectFiles.some(file => existsSync(join(path, file)));
50
50
  }
51
- export const config = new Conf({
52
- projectName: 'codeep',
53
- defaults: {
51
+ /**
52
+ * Get fallback config directory if standard location is not writable
53
+ * Falls back to .codeep in current working directory
54
+ */
55
+ function getFallbackConfigDir() {
56
+ const cwdConfig = join(process.cwd(), '.codeep');
57
+ try {
58
+ if (!existsSync(cwdConfig)) {
59
+ mkdirSync(cwdConfig, { recursive: true });
60
+ }
61
+ return cwdConfig;
62
+ }
63
+ catch {
64
+ return undefined;
65
+ }
66
+ }
67
+ /**
68
+ * Check if a directory is writable
69
+ */
70
+ function isWritable(dir) {
71
+ try {
72
+ const testFile = join(dir, '.write-test');
73
+ writeFileSync(testFile, 'test');
74
+ unlinkSync(testFile);
75
+ return true;
76
+ }
77
+ catch {
78
+ return false;
79
+ }
80
+ }
81
+ /**
82
+ * Create config with fallback logic
83
+ * 1. Try standard Conf location (~/.config/codeep-nodejs on Linux, etc.)
84
+ * 2. If not writable, use .codeep in current working directory
85
+ */
86
+ function createConfig() {
87
+ const defaults = {
54
88
  apiKey: '',
55
89
  provider: 'z.ai',
56
90
  model: 'glm-4.7',
57
91
  agentMode: 'on',
58
- agentConfirmation: 'dangerous', // Confirm only dangerous actions by default
92
+ agentConfirmation: 'dangerous',
59
93
  agentAutoCommit: false,
60
94
  agentAutoCommitBranch: false,
61
- agentAutoVerify: true, // Auto-verify by default
95
+ agentAutoVerify: true,
62
96
  agentMaxFixAttempts: 3,
63
97
  agentMaxIterations: 100,
64
- agentMaxDuration: 20, // minutes
65
- agentApiTimeout: 180000, // 180 seconds base timeout for agent (dynamically adjusted)
98
+ agentMaxDuration: 20,
99
+ agentApiTimeout: 180000,
66
100
  protocol: 'openai',
67
101
  plan: 'lite',
68
102
  language: 'en',
@@ -71,12 +105,47 @@ export const config = new Conf({
71
105
  temperature: 0.7,
72
106
  maxTokens: 8192,
73
107
  apiTimeout: 60000,
74
- rateLimitApi: 30, // 30 requests per minute
75
- rateLimitCommands: 100, // 100 commands per minute
108
+ rateLimitApi: 30,
109
+ rateLimitCommands: 100,
76
110
  projectPermissions: [],
77
111
  providerApiKeys: [],
78
- },
79
- });
112
+ };
113
+ // First try standard location
114
+ try {
115
+ const standardConfig = new Conf({
116
+ projectName: 'codeep',
117
+ defaults,
118
+ });
119
+ // Test if we can write to the config directory
120
+ const configDir = dirname(standardConfig.path);
121
+ if (isWritable(configDir)) {
122
+ return standardConfig;
123
+ }
124
+ }
125
+ catch {
126
+ // Standard location failed, try fallback
127
+ }
128
+ // Fallback: use .codeep in current working directory
129
+ const fallbackDir = getFallbackConfigDir();
130
+ if (fallbackDir) {
131
+ try {
132
+ return new Conf({
133
+ projectName: 'codeep',
134
+ cwd: fallbackDir,
135
+ defaults,
136
+ });
137
+ }
138
+ catch {
139
+ // Even fallback failed
140
+ }
141
+ }
142
+ // Last resort: use standard config anyway (may fail on write)
143
+ return new Conf({
144
+ projectName: 'codeep',
145
+ defaults,
146
+ });
147
+ }
148
+ export const config = createConfig();
80
149
  // Migrate old 'auto' value to 'on'
81
150
  if (config.get('agentMode') === 'auto') {
82
151
  config.set('agentMode', 'on');
@@ -84,3 +84,38 @@ export declare function getProjectSummary(dir?: string): {
84
84
  fileCount: number;
85
85
  hasReadme: boolean;
86
86
  } | null;
87
+ /**
88
+ * Project feature detection
89
+ */
90
+ export interface ProjectFeatures {
91
+ hasGit: boolean;
92
+ hasPackageJson: boolean;
93
+ hasTypescript: boolean;
94
+ hasPython: boolean;
95
+ hasDocker: boolean;
96
+ hasTests: boolean;
97
+ hasCargo: boolean;
98
+ hasGoMod: boolean;
99
+ projectType: string;
100
+ }
101
+ /**
102
+ * Suggested command based on project features
103
+ */
104
+ export interface ProjectSuggestion {
105
+ command: string;
106
+ description: string;
107
+ reason: string;
108
+ priority: number;
109
+ }
110
+ /**
111
+ * Detect project features
112
+ */
113
+ export declare function detectProjectFeatures(dir?: string): ProjectFeatures;
114
+ /**
115
+ * Get smart suggestions based on project type
116
+ */
117
+ export declare function getProjectSuggestions(dir?: string): ProjectSuggestion[];
118
+ /**
119
+ * Get a brief tip message for the project type
120
+ */
121
+ export declare function getProjectTip(dir?: string): string | null;
@@ -414,3 +414,142 @@ export function getProjectSummary(dir = process.cwd()) {
414
414
  return null;
415
415
  }
416
416
  }
417
+ /**
418
+ * Detect project features
419
+ */
420
+ export function detectProjectFeatures(dir = process.cwd()) {
421
+ return {
422
+ hasGit: existsSync(join(dir, '.git')),
423
+ hasPackageJson: existsSync(join(dir, 'package.json')),
424
+ hasTypescript: existsSync(join(dir, 'tsconfig.json')),
425
+ hasPython: existsSync(join(dir, 'requirements.txt')) || existsSync(join(dir, 'setup.py')) || existsSync(join(dir, 'pyproject.toml')),
426
+ hasDocker: existsSync(join(dir, 'Dockerfile')) || existsSync(join(dir, 'docker-compose.yml')),
427
+ hasTests: existsSync(join(dir, 'jest.config.js')) || existsSync(join(dir, 'jest.config.ts')) ||
428
+ existsSync(join(dir, 'pytest.ini')) || existsSync(join(dir, 'test')) || existsSync(join(dir, 'tests')) ||
429
+ existsSync(join(dir, '__tests__')) || existsSync(join(dir, 'spec')),
430
+ hasCargo: existsSync(join(dir, 'Cargo.toml')),
431
+ hasGoMod: existsSync(join(dir, 'go.mod')),
432
+ projectType: getProjectType(dir),
433
+ };
434
+ }
435
+ /**
436
+ * Get smart suggestions based on project type
437
+ */
438
+ export function getProjectSuggestions(dir = process.cwd()) {
439
+ const features = detectProjectFeatures(dir);
440
+ const suggestions = [];
441
+ // Git suggestions
442
+ if (features.hasGit) {
443
+ suggestions.push({
444
+ command: '/diff',
445
+ description: 'Review uncommitted changes',
446
+ reason: 'Git repository detected',
447
+ priority: 1,
448
+ });
449
+ suggestions.push({
450
+ command: '/commit',
451
+ description: 'Generate commit message',
452
+ reason: 'Git repository detected',
453
+ priority: 2,
454
+ });
455
+ }
456
+ // Node.js/TypeScript suggestions
457
+ if (features.hasPackageJson) {
458
+ suggestions.push({
459
+ command: '/agent npm run build',
460
+ description: 'Build the project',
461
+ reason: 'Node.js project detected',
462
+ priority: 3,
463
+ });
464
+ if (features.hasTests) {
465
+ suggestions.push({
466
+ command: '/agent npm test',
467
+ description: 'Run tests',
468
+ reason: 'Test configuration found',
469
+ priority: 4,
470
+ });
471
+ }
472
+ }
473
+ // Python suggestions
474
+ if (features.hasPython) {
475
+ suggestions.push({
476
+ command: '/agent pip install -r requirements.txt',
477
+ description: 'Install dependencies',
478
+ reason: 'Python project detected',
479
+ priority: 3,
480
+ });
481
+ if (features.hasTests) {
482
+ suggestions.push({
483
+ command: '/agent pytest',
484
+ description: 'Run tests',
485
+ reason: 'Python tests detected',
486
+ priority: 4,
487
+ });
488
+ }
489
+ }
490
+ // Rust suggestions
491
+ if (features.hasCargo) {
492
+ suggestions.push({
493
+ command: '/agent cargo build',
494
+ description: 'Build the project',
495
+ reason: 'Rust project detected',
496
+ priority: 3,
497
+ });
498
+ suggestions.push({
499
+ command: '/agent cargo test',
500
+ description: 'Run tests',
501
+ reason: 'Rust project detected',
502
+ priority: 4,
503
+ });
504
+ }
505
+ // Go suggestions
506
+ if (features.hasGoMod) {
507
+ suggestions.push({
508
+ command: '/agent go build',
509
+ description: 'Build the project',
510
+ reason: 'Go project detected',
511
+ priority: 3,
512
+ });
513
+ suggestions.push({
514
+ command: '/agent go test ./...',
515
+ description: 'Run tests',
516
+ reason: 'Go project detected',
517
+ priority: 4,
518
+ });
519
+ }
520
+ // Docker suggestions
521
+ if (features.hasDocker) {
522
+ suggestions.push({
523
+ command: '/agent docker build',
524
+ description: 'Build Docker image',
525
+ reason: 'Dockerfile detected',
526
+ priority: 5,
527
+ });
528
+ }
529
+ // Always suggest agent for code tasks
530
+ suggestions.push({
531
+ command: '/agent',
532
+ description: 'Run autonomous agent for any task',
533
+ reason: 'Project access granted',
534
+ priority: 10,
535
+ });
536
+ // Sort by priority
537
+ return suggestions.sort((a, b) => a.priority - b.priority);
538
+ }
539
+ /**
540
+ * Get a brief tip message for the project type
541
+ */
542
+ export function getProjectTip(dir = process.cwd()) {
543
+ const features = detectProjectFeatures(dir);
544
+ const tips = [];
545
+ if (features.hasGit) {
546
+ tips.push('/diff, /commit');
547
+ }
548
+ if (features.hasPackageJson || features.hasCargo || features.hasGoMod || features.hasPython) {
549
+ tips.push('/agent for tasks');
550
+ }
551
+ if (tips.length === 0)
552
+ return null;
553
+ const projectName = features.projectType !== 'Unknown' ? features.projectType : 'project';
554
+ return `${projectName} • Try: ${tips.join(' • ')}`;
555
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.0.123",
3
+ "version": "1.0.124",
4
4
  "description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",