@staticpayload/zai-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.
- package/LICENSE +678 -0
- package/README.md +115 -0
- package/bin/zcode +3 -0
- package/dist/apply.d.ts +44 -0
- package/dist/apply.d.ts.map +1 -0
- package/dist/apply.js +307 -0
- package/dist/apply.js.map +1 -0
- package/dist/auth.d.ts +9 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +170 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +179 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +15 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +560 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +97 -0
- package/dist/config.js.map +1 -0
- package/dist/context/context_builder.d.ts +29 -0
- package/dist/context/context_builder.d.ts.map +1 -0
- package/dist/context/context_builder.js +307 -0
- package/dist/context/context_builder.js.map +1 -0
- package/dist/context/project_memory.d.ts +14 -0
- package/dist/context/project_memory.d.ts.map +1 -0
- package/dist/context/project_memory.js +142 -0
- package/dist/context/project_memory.js.map +1 -0
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +3 -0
- package/dist/doctor.js.map +1 -0
- package/dist/git.d.ts +10 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +90 -0
- package/dist/git.js.map +1 -0
- package/dist/history.d.ts +14 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +103 -0
- package/dist/history.js.map +1 -0
- package/dist/interactive.d.ts +6 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +83 -0
- package/dist/interactive.js.map +1 -0
- package/dist/orchestrator.d.ts +11 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +135 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/planner.d.ts +22 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +259 -0
- package/dist/planner.js.map +1 -0
- package/dist/profiles.d.ts +16 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +80 -0
- package/dist/profiles.js.map +1 -0
- package/dist/rollback.d.ts +27 -0
- package/dist/rollback.d.ts.map +1 -0
- package/dist/rollback.js +154 -0
- package/dist/rollback.js.map +1 -0
- package/dist/runtime.d.ts +131 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +374 -0
- package/dist/runtime.js.map +1 -0
- package/dist/session.d.ts +95 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +174 -0
- package/dist/session.js.map +1 -0
- package/dist/settings.d.ts +41 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +225 -0
- package/dist/settings.js.map +1 -0
- package/dist/settings_menu.d.ts +2 -0
- package/dist/settings_menu.d.ts.map +1 -0
- package/dist/settings_menu.js +265 -0
- package/dist/settings_menu.js.map +1 -0
- package/dist/shell.d.ts +18 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +128 -0
- package/dist/shell.js.map +1 -0
- package/dist/task_runner.d.ts +22 -0
- package/dist/task_runner.d.ts.map +1 -0
- package/dist/task_runner.js +230 -0
- package/dist/task_runner.js.map +1 -0
- package/dist/ui.d.ts +15 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +160 -0
- package/dist/ui.js.map +1 -0
- package/dist/workspace.d.ts +17 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +134 -0
- package/dist/workspace.js.map +1 -0
- package/dist/workspace_model.d.ts +45 -0
- package/dist/workspace_model.d.ts.map +1 -0
- package/dist/workspace_model.js +253 -0
- package/dist/workspace_model.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Z.ai Code
|
|
2
|
+
|
|
3
|
+
A Z.ai-native AI code editor — CLI-first, interactive editor shell.
|
|
4
|
+
|
|
5
|
+
**This tool uses Z.ai API exclusively.** No other AI providers.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Interactive editor shell** — not a chatbot, a code editor
|
|
10
|
+
- **Plan → Diff → Apply workflow** — no auto-execution
|
|
11
|
+
- **Keyboard-driven settings menu** — BIOS-style configuration
|
|
12
|
+
- **Model switching** — select from available Z.ai models
|
|
13
|
+
- **Execution profiles** — safe, balanced, fast presets
|
|
14
|
+
- **Git awareness** — branch, dirty state, warnings
|
|
15
|
+
- **Dry-run mode** — preview without applying
|
|
16
|
+
- **Undo/rollback** — revert last operation
|
|
17
|
+
- **Task history** — audit log of all operations
|
|
18
|
+
- **Safe file operations** — binary blocked, large files warned
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- Node.js 18 or higher
|
|
23
|
+
- Z.ai API key
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g @staticpayload/zai-code
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or run directly:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx @staticpayload/zai-code
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
zcode
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This opens the interactive editor shell. The prompt shows current state:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
[edit][clean]>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Commands
|
|
50
|
+
|
|
51
|
+
**Navigation:**
|
|
52
|
+
- `/help` — show commands
|
|
53
|
+
- `/context` — show current context
|
|
54
|
+
- `/files` — list open files
|
|
55
|
+
- `/open <path>` — add file to context
|
|
56
|
+
|
|
57
|
+
**Execution:**
|
|
58
|
+
- `/plan` — generate execution plan
|
|
59
|
+
- `/generate` — create file changes
|
|
60
|
+
- `/diff` — review pending changes
|
|
61
|
+
- `/apply` — apply changes
|
|
62
|
+
- `/undo` — rollback last operation
|
|
63
|
+
|
|
64
|
+
**Modes:**
|
|
65
|
+
- `/mode <edit|explain|review|debug>` — set mode
|
|
66
|
+
- `/dry-run on|off` — toggle dry-run
|
|
67
|
+
- `/profile list|set <name>` — manage profiles
|
|
68
|
+
|
|
69
|
+
**Tasks:**
|
|
70
|
+
- `/decompose` — break task into steps
|
|
71
|
+
- `/step` — plan current step
|
|
72
|
+
- `/next` — complete step and advance
|
|
73
|
+
|
|
74
|
+
**System:**
|
|
75
|
+
- `/settings` — open interactive settings menu
|
|
76
|
+
- `/git` — show repository status
|
|
77
|
+
- `/exec <cmd>` — run allowed shell command
|
|
78
|
+
- `/history` — view task history
|
|
79
|
+
- `/doctor` — system health check
|
|
80
|
+
|
|
81
|
+
### Workflow
|
|
82
|
+
|
|
83
|
+
1. Enter a task: `add error handling to auth.ts`
|
|
84
|
+
2. System detects intent: `Intent: CODE_EDIT`
|
|
85
|
+
3. Run `/plan` to generate a plan
|
|
86
|
+
4. Run `/generate` to create changes
|
|
87
|
+
5. Run `/diff` to review
|
|
88
|
+
6. Run `/apply` to execute
|
|
89
|
+
|
|
90
|
+
No changes are made without explicit `/apply`.
|
|
91
|
+
|
|
92
|
+
## Settings
|
|
93
|
+
|
|
94
|
+
Run `/settings` to open the interactive menu:
|
|
95
|
+
|
|
96
|
+
- **Model** — select AI model
|
|
97
|
+
- **UI** — ASCII logo, colors, prompt style
|
|
98
|
+
- **Execution** — confirmation mode, iteration limits
|
|
99
|
+
- **Context** — file scope, token limits
|
|
100
|
+
- **Debug** — logging options
|
|
101
|
+
|
|
102
|
+
Navigate with arrow keys, Tab between sections, Esc to exit.
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
Global settings: `~/.zai/settings.json`
|
|
107
|
+
Project settings: `.zai/settings.json` (overrides global)
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
GPL-3.0
|
|
112
|
+
|
|
113
|
+
## Author
|
|
114
|
+
|
|
115
|
+
StaticPayload <chaitanyamishra.ai@gmail.com>
|
package/bin/zcode
ADDED
package/dist/apply.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ResponseSchema } from './runtime';
|
|
2
|
+
export interface ApplyResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
applied: string[];
|
|
5
|
+
failed: Array<{
|
|
6
|
+
path: string;
|
|
7
|
+
error: string;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export interface ApplyOptions {
|
|
11
|
+
dryRun?: boolean;
|
|
12
|
+
basePath?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PathValidationResult {
|
|
15
|
+
valid: boolean;
|
|
16
|
+
resolved: string;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface FileOperationResult {
|
|
20
|
+
success: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface DiffHunk {
|
|
24
|
+
start: number;
|
|
25
|
+
end: number;
|
|
26
|
+
content: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validate a file path is safe (no path traversal, absolute or within basePath)
|
|
30
|
+
*/
|
|
31
|
+
export declare function validatePath(filePath: string, basePath?: string): PathValidationResult;
|
|
32
|
+
/**
|
|
33
|
+
* Apply a single file operation atomically
|
|
34
|
+
*/
|
|
35
|
+
export declare function applyFileOperation(operation: 'create' | 'modify' | 'delete', filePath: string, content?: string, options?: ApplyOptions): FileOperationResult;
|
|
36
|
+
/**
|
|
37
|
+
* Apply diff hunks to a file
|
|
38
|
+
*/
|
|
39
|
+
export declare function applyDiff(filePath: string, hunks: DiffHunk[], options?: ApplyOptions): FileOperationResult;
|
|
40
|
+
/**
|
|
41
|
+
* Main entry: apply all changes from a ResponseSchema
|
|
42
|
+
*/
|
|
43
|
+
export declare function applyResponse(response: ResponseSchema, options?: ApplyOptions): ApplyResult;
|
|
44
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../src/apply.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,oBAAoB,CA+CtB;AAkCD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,YAAY,GACrB,mBAAmB,CAqFrB;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,EAAE,EACjB,OAAO,CAAC,EAAE,YAAY,GACrB,mBAAmB,CAqErB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,YAAY,GACrB,WAAW,CAqDb"}
|
package/dist/apply.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
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
|
+
exports.validatePath = validatePath;
|
|
37
|
+
exports.applyFileOperation = applyFileOperation;
|
|
38
|
+
exports.applyDiff = applyDiff;
|
|
39
|
+
exports.applyResponse = applyResponse;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const rollback_1 = require("./rollback");
|
|
43
|
+
/**
|
|
44
|
+
* Validate a file path is safe (no path traversal, absolute or within basePath)
|
|
45
|
+
*/
|
|
46
|
+
function validatePath(filePath, basePath) {
|
|
47
|
+
try {
|
|
48
|
+
let resolvedPath = path.resolve(filePath);
|
|
49
|
+
// Normalize the path to remove any redundant components
|
|
50
|
+
resolvedPath = path.normalize(resolvedPath);
|
|
51
|
+
// If basePath is provided, ensure the resolved path is within it
|
|
52
|
+
if (basePath) {
|
|
53
|
+
const resolvedBase = path.resolve(basePath);
|
|
54
|
+
const resolvedBaseNormalized = path.normalize(resolvedBase);
|
|
55
|
+
// Check if the resolved path is within the base path
|
|
56
|
+
const relativePath = path.relative(resolvedBaseNormalized, resolvedPath);
|
|
57
|
+
// If the relative path starts with '..', it's outside the base path
|
|
58
|
+
if (relativePath.startsWith('..')) {
|
|
59
|
+
return {
|
|
60
|
+
valid: false,
|
|
61
|
+
resolved: resolvedPath,
|
|
62
|
+
error: `Path '${filePath}' is outside base path '${basePath}'`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Check for path traversal attempts in the original input
|
|
67
|
+
const normalizedInput = path.normalize(filePath);
|
|
68
|
+
if (normalizedInput.includes('..')) {
|
|
69
|
+
// If basePath is set, allow relative paths with .. as long as they resolve within basePath
|
|
70
|
+
if (!basePath) {
|
|
71
|
+
return {
|
|
72
|
+
valid: false,
|
|
73
|
+
resolved: resolvedPath,
|
|
74
|
+
error: `Path '${filePath}' contains path traversal`,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// Re-check with basePath logic above
|
|
78
|
+
}
|
|
79
|
+
return { valid: true, resolved: resolvedPath };
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
return {
|
|
83
|
+
valid: false,
|
|
84
|
+
resolved: filePath,
|
|
85
|
+
error: error instanceof Error ? error.message : String(error),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Write content to a file atomically using temp file + rename
|
|
91
|
+
*/
|
|
92
|
+
function atomicWrite(filePath, content) {
|
|
93
|
+
try {
|
|
94
|
+
// Ensure parent directory exists
|
|
95
|
+
const parentDir = path.dirname(filePath);
|
|
96
|
+
if (!fs.existsSync(parentDir)) {
|
|
97
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
98
|
+
}
|
|
99
|
+
// Create temp file in same directory to ensure same filesystem
|
|
100
|
+
const tempPath = path.join(parentDir, `.tmp_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2)}`);
|
|
101
|
+
// Write to temp file
|
|
102
|
+
fs.writeFileSync(tempPath, content, 'utf-8');
|
|
103
|
+
// Atomic rename
|
|
104
|
+
fs.renameSync(tempPath, filePath);
|
|
105
|
+
return { success: true };
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: error instanceof Error ? error.message : String(error),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Apply a single file operation atomically
|
|
116
|
+
*/
|
|
117
|
+
function applyFileOperation(operation, filePath, content, options) {
|
|
118
|
+
// Validate the path
|
|
119
|
+
const validation = validatePath(filePath, options?.basePath);
|
|
120
|
+
if (!validation.valid) {
|
|
121
|
+
return { success: false, error: validation.error };
|
|
122
|
+
}
|
|
123
|
+
const resolvedPath = validation.resolved;
|
|
124
|
+
// Block binary files
|
|
125
|
+
const binaryExtensions = ['.exe', '.dll', '.so', '.dylib', '.bin', '.o', '.a', '.lib', '.png', '.jpg', '.jpeg', '.gif', '.ico', '.pdf', '.zip', '.tar', '.gz', '.rar'];
|
|
126
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
127
|
+
if (binaryExtensions.includes(ext)) {
|
|
128
|
+
return { success: false, error: 'Binary file modification blocked' };
|
|
129
|
+
}
|
|
130
|
+
// Warn on large content
|
|
131
|
+
if (content && content.length > 50000) {
|
|
132
|
+
console.log(`Warning: Large file (${Math.round(content.length / 1000)}KB)`);
|
|
133
|
+
}
|
|
134
|
+
// Dry run - just validate
|
|
135
|
+
if (options?.dryRun) {
|
|
136
|
+
switch (operation) {
|
|
137
|
+
case 'create':
|
|
138
|
+
if (fs.existsSync(resolvedPath)) {
|
|
139
|
+
return { success: false, error: `File already exists: ${resolvedPath}` };
|
|
140
|
+
}
|
|
141
|
+
break;
|
|
142
|
+
case 'modify':
|
|
143
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
144
|
+
return { success: false, error: `File does not exist: ${resolvedPath}` };
|
|
145
|
+
}
|
|
146
|
+
if (content === undefined) {
|
|
147
|
+
return { success: false, error: 'Content required for modify operation' };
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
case 'delete':
|
|
151
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
152
|
+
return { success: false, error: `File does not exist: ${resolvedPath}` };
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
return { success: true };
|
|
157
|
+
}
|
|
158
|
+
// Actual operation
|
|
159
|
+
switch (operation) {
|
|
160
|
+
case 'create':
|
|
161
|
+
if (fs.existsSync(resolvedPath)) {
|
|
162
|
+
return { success: false, error: `File already exists: ${resolvedPath}` };
|
|
163
|
+
}
|
|
164
|
+
if (content === undefined) {
|
|
165
|
+
return { success: false, error: 'Content required for create operation' };
|
|
166
|
+
}
|
|
167
|
+
(0, rollback_1.createBackup)(resolvedPath, 'create');
|
|
168
|
+
return atomicWrite(resolvedPath, content);
|
|
169
|
+
case 'modify':
|
|
170
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
171
|
+
return { success: false, error: `File does not exist: ${resolvedPath}` };
|
|
172
|
+
}
|
|
173
|
+
if (content === undefined) {
|
|
174
|
+
return { success: false, error: 'Content required for modify operation' };
|
|
175
|
+
}
|
|
176
|
+
(0, rollback_1.createBackup)(resolvedPath, 'modify');
|
|
177
|
+
return atomicWrite(resolvedPath, content);
|
|
178
|
+
case 'delete':
|
|
179
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
180
|
+
return { success: false, error: `File does not exist: ${resolvedPath}` };
|
|
181
|
+
}
|
|
182
|
+
(0, rollback_1.createBackup)(resolvedPath, 'delete');
|
|
183
|
+
try {
|
|
184
|
+
fs.unlinkSync(resolvedPath);
|
|
185
|
+
return { success: true };
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
return {
|
|
189
|
+
success: false,
|
|
190
|
+
error: error instanceof Error ? error.message : String(error),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
default:
|
|
194
|
+
return { success: false, error: `Unknown operation: ${operation}` };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Apply diff hunks to a file
|
|
199
|
+
*/
|
|
200
|
+
function applyDiff(filePath, hunks, options) {
|
|
201
|
+
// Validate the path
|
|
202
|
+
const validation = validatePath(filePath, options?.basePath);
|
|
203
|
+
if (!validation.valid) {
|
|
204
|
+
return { success: false, error: validation.error };
|
|
205
|
+
}
|
|
206
|
+
const resolvedPath = validation.resolved;
|
|
207
|
+
// Check file exists
|
|
208
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
209
|
+
return { success: false, error: `File does not exist: ${resolvedPath}` };
|
|
210
|
+
}
|
|
211
|
+
// Read existing file
|
|
212
|
+
let lines;
|
|
213
|
+
try {
|
|
214
|
+
const content = fs.readFileSync(resolvedPath, 'utf-8');
|
|
215
|
+
lines = content.split('\n');
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
return {
|
|
219
|
+
success: false,
|
|
220
|
+
error: error instanceof Error ? error.message : String(error),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// Sort hunks in reverse order by start line to apply from bottom to top
|
|
224
|
+
// This prevents line number shifts from affecting earlier hunks
|
|
225
|
+
const sortedHunks = [...hunks].sort((a, b) => b.start - a.start);
|
|
226
|
+
// Apply each hunk
|
|
227
|
+
for (const hunk of sortedHunks) {
|
|
228
|
+
const { start, end, content } = hunk;
|
|
229
|
+
// Convert from 1-indexed to 0-indexed
|
|
230
|
+
const startIndex = start - 1;
|
|
231
|
+
const endIndex = end - 1;
|
|
232
|
+
// Validate line numbers
|
|
233
|
+
if (startIndex < 0 || startIndex >= lines.length) {
|
|
234
|
+
return {
|
|
235
|
+
success: false,
|
|
236
|
+
error: `Invalid hunk start line: ${start} (file has ${lines.length} lines)`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (endIndex < startIndex || endIndex >= lines.length) {
|
|
240
|
+
return {
|
|
241
|
+
success: false,
|
|
242
|
+
error: `Invalid hunk end line: ${end} (file has ${lines.length} lines)`,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// Split content into lines
|
|
246
|
+
const newLines = content.split('\n');
|
|
247
|
+
// Replace lines from start to end with new content
|
|
248
|
+
lines.splice(startIndex, endIndex - startIndex + 1, ...newLines);
|
|
249
|
+
}
|
|
250
|
+
// Dry run - don't write
|
|
251
|
+
if (options?.dryRun) {
|
|
252
|
+
return { success: true };
|
|
253
|
+
}
|
|
254
|
+
// Create backup before applying diff
|
|
255
|
+
(0, rollback_1.createBackup)(resolvedPath, 'modify');
|
|
256
|
+
// Write atomically
|
|
257
|
+
const newContent = lines.join('\n');
|
|
258
|
+
return atomicWrite(resolvedPath, newContent);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Main entry: apply all changes from a ResponseSchema
|
|
262
|
+
*/
|
|
263
|
+
function applyResponse(response, options) {
|
|
264
|
+
const result = {
|
|
265
|
+
success: true,
|
|
266
|
+
applied: [],
|
|
267
|
+
failed: [],
|
|
268
|
+
};
|
|
269
|
+
// Track if any operation failed
|
|
270
|
+
let hasFailures = false;
|
|
271
|
+
// Apply file operations if present
|
|
272
|
+
if (response.files && response.files.length > 0) {
|
|
273
|
+
for (const fileOp of response.files) {
|
|
274
|
+
const opResult = applyFileOperation(fileOp.operation, fileOp.path, fileOp.content, options);
|
|
275
|
+
if (opResult.success) {
|
|
276
|
+
result.applied.push(`${fileOp.operation}:${fileOp.path}`);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
result.failed.push({
|
|
280
|
+
path: fileOp.path,
|
|
281
|
+
error: opResult.error || 'Unknown error',
|
|
282
|
+
});
|
|
283
|
+
hasFailures = true;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// Apply diff operations if present
|
|
288
|
+
if (response.diffs && response.diffs.length > 0) {
|
|
289
|
+
for (const diff of response.diffs) {
|
|
290
|
+
const diffResult = applyDiff(diff.file, diff.hunks, options);
|
|
291
|
+
if (diffResult.success) {
|
|
292
|
+
result.applied.push(`diff:${diff.file}`);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
result.failed.push({
|
|
296
|
+
path: diff.file,
|
|
297
|
+
error: diffResult.error || 'Unknown error',
|
|
298
|
+
});
|
|
299
|
+
hasFailures = true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// Set overall success status
|
|
304
|
+
result.success = !hasFailures && result.failed.length === 0;
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../src/apply.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function getApiKey(): Promise<string | null>;
|
|
2
|
+
export declare function setApiKey(key: string): Promise<void>;
|
|
3
|
+
export declare function deleteApiKey(): Promise<void>;
|
|
4
|
+
export declare function hasValidCredentials(): Promise<boolean>;
|
|
5
|
+
export declare function validateApiKey(key: string): Promise<boolean>;
|
|
6
|
+
export declare function promptForApiKey(): Promise<string>;
|
|
7
|
+
export declare function runOnboarding(): Promise<void>;
|
|
8
|
+
export declare function ensureAuthenticated(): Promise<string>;
|
|
9
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAqCA,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMxD;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAG5D;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUlE;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CA4CvD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAanD;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAU3D"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
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
|
+
exports.getApiKey = getApiKey;
|
|
37
|
+
exports.setApiKey = setApiKey;
|
|
38
|
+
exports.deleteApiKey = deleteApiKey;
|
|
39
|
+
exports.hasValidCredentials = hasValidCredentials;
|
|
40
|
+
exports.validateApiKey = validateApiKey;
|
|
41
|
+
exports.promptForApiKey = promptForApiKey;
|
|
42
|
+
exports.runOnboarding = runOnboarding;
|
|
43
|
+
exports.ensureAuthenticated = ensureAuthenticated;
|
|
44
|
+
const keytar = __importStar(require("keytar"));
|
|
45
|
+
const readline = __importStar(require("readline"));
|
|
46
|
+
const config_1 = require("./config");
|
|
47
|
+
const SERVICE_NAME = 'zai-code';
|
|
48
|
+
const ACCOUNT_NAME = 'api-key';
|
|
49
|
+
async function httpsGet(url, headers) {
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const parsedUrl = new URL(url);
|
|
52
|
+
const options = {
|
|
53
|
+
hostname: parsedUrl.hostname,
|
|
54
|
+
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
|
|
55
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
56
|
+
method: 'GET',
|
|
57
|
+
headers: {
|
|
58
|
+
...headers,
|
|
59
|
+
'User-Agent': 'zai-cli',
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
const req = require('https').request(options, (res) => {
|
|
63
|
+
let data = '';
|
|
64
|
+
res.on('data', (chunk) => {
|
|
65
|
+
data += chunk;
|
|
66
|
+
});
|
|
67
|
+
res.on('end', () => {
|
|
68
|
+
resolve({ statusCode: res.statusCode, data });
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
req.on('error', reject);
|
|
72
|
+
req.end();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async function getApiKey() {
|
|
76
|
+
try {
|
|
77
|
+
return await keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function setApiKey(key) {
|
|
84
|
+
await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, key);
|
|
85
|
+
}
|
|
86
|
+
async function deleteApiKey() {
|
|
87
|
+
await keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME);
|
|
88
|
+
}
|
|
89
|
+
async function hasValidCredentials() {
|
|
90
|
+
const key = await getApiKey();
|
|
91
|
+
return key !== null && key.length > 0;
|
|
92
|
+
}
|
|
93
|
+
async function validateApiKey(key) {
|
|
94
|
+
try {
|
|
95
|
+
const config = (0, config_1.loadConfig)();
|
|
96
|
+
const response = await httpsGet(`${config.api.baseUrl}/models`, {
|
|
97
|
+
Authorization: `Bearer ${key}`,
|
|
98
|
+
});
|
|
99
|
+
return response.statusCode >= 200 && response.statusCode < 300;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function promptForApiKey() {
|
|
106
|
+
return new Promise((resolve) => {
|
|
107
|
+
const rl = readline.createInterface({
|
|
108
|
+
input: process.stdin,
|
|
109
|
+
output: process.stdout,
|
|
110
|
+
});
|
|
111
|
+
// Use readline with muted input for hidden password
|
|
112
|
+
const stdin = process.stdin;
|
|
113
|
+
const stdout = process.stdout;
|
|
114
|
+
stdout.write('Enter API key: ');
|
|
115
|
+
stdin.setRawMode(true);
|
|
116
|
+
stdin.resume();
|
|
117
|
+
stdin.setEncoding('utf8');
|
|
118
|
+
let key = '';
|
|
119
|
+
const onData = (char) => {
|
|
120
|
+
if (char === '\r' || char === '\n' || char === '\u0004') {
|
|
121
|
+
// Enter or Ctrl-D
|
|
122
|
+
stdin.setRawMode(false);
|
|
123
|
+
stdin.pause();
|
|
124
|
+
stdin.removeListener('data', onData);
|
|
125
|
+
stdout.write('\n');
|
|
126
|
+
rl.close();
|
|
127
|
+
resolve(key);
|
|
128
|
+
}
|
|
129
|
+
else if (char === '\u0003') {
|
|
130
|
+
// Ctrl-C
|
|
131
|
+
stdout.write('\n');
|
|
132
|
+
process.exit(0);
|
|
133
|
+
}
|
|
134
|
+
else if (char === '\u007f') {
|
|
135
|
+
// Backspace
|
|
136
|
+
if (key.length > 0) {
|
|
137
|
+
key = key.slice(0, -1);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
key += char;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
stdin.on('data', onData);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
async function runOnboarding() {
|
|
148
|
+
while (true) {
|
|
149
|
+
console.log('Z.ai API key required');
|
|
150
|
+
const key = await promptForApiKey();
|
|
151
|
+
if (await validateApiKey(key)) {
|
|
152
|
+
await setApiKey(key);
|
|
153
|
+
console.log('Authentication successful');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
console.log('Invalid API key');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function ensureAuthenticated() {
|
|
162
|
+
if (await hasValidCredentials()) {
|
|
163
|
+
const key = await getApiKey();
|
|
164
|
+
return key;
|
|
165
|
+
}
|
|
166
|
+
await runOnboarding();
|
|
167
|
+
const key = await getApiKey();
|
|
168
|
+
return key;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=auth.js.map
|