@nghyane/arcane 0.1.21 → 0.1.23
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/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/cli/setup-cli.ts +40 -12
- package/src/ipy/kernel.ts +1 -2
- package/src/patch/edit-tool.ts +3 -3
- package/src/patch/hashline.ts +6 -6
- package/src/patch/schemas.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.1.23] - 2026-03-08
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fix Python setup installing packages into system Python instead of managed venv, causing "kernel unavailable" even after install
|
|
10
|
+
- Fix missing `ensurepip` step when managed venv lacks pip
|
|
11
|
+
- Fix misleading error message to point users to `arcane setup python`
|
|
12
|
+
|
|
13
|
+
## [0.1.22] - 2026-03-08
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Rename edit operation `replace` to `replace_range` for clarity
|
|
18
|
+
|
|
5
19
|
## [0.1.21] - 2026-03-05
|
|
6
20
|
|
|
7
21
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@nghyane/arcane",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.23",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/nghyane/arcane",
|
|
7
7
|
"author": "Can Bölük",
|
package/src/cli/setup-cli.ts
CHANGED
|
@@ -160,7 +160,18 @@ async function installPythonPackages(
|
|
|
160
160
|
pythonPath: string,
|
|
161
161
|
uvPath?: string,
|
|
162
162
|
pipPath?: string,
|
|
163
|
+
usingManagedEnv?: boolean,
|
|
163
164
|
): Promise<{ success: boolean; usedManagedEnv: boolean }> {
|
|
165
|
+
const managedPython = managedPythonPath();
|
|
166
|
+
const hasManagedEnv = await Bun.file(managedPython).exists();
|
|
167
|
+
|
|
168
|
+
// If the managed venv already exists, install directly into it.
|
|
169
|
+
// resolvePythonRuntime prefers managed venv over system Python,
|
|
170
|
+
// so installing into system Python would be invisible to the check.
|
|
171
|
+
if (hasManagedEnv || usingManagedEnv) {
|
|
172
|
+
return installIntoManagedEnv(packages, pythonPath, uvPath);
|
|
173
|
+
}
|
|
174
|
+
|
|
164
175
|
if (uvPath) {
|
|
165
176
|
console.log(chalk.dim(`Installing via uv: ${packages.join(" ")}`));
|
|
166
177
|
const result = await $`${uvPath} pip install ${packages}`.nothrow();
|
|
@@ -178,24 +189,35 @@ async function installPythonPackages(
|
|
|
178
189
|
}
|
|
179
190
|
|
|
180
191
|
console.log(chalk.dim(`Falling back to managed virtual environment: ${MANAGED_PYTHON_ENV}`));
|
|
192
|
+
return installIntoManagedEnv(packages, pythonPath, uvPath);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function installIntoManagedEnv(
|
|
196
|
+
packages: string[],
|
|
197
|
+
pythonPath: string,
|
|
198
|
+
uvPath?: string,
|
|
199
|
+
): Promise<{ success: boolean; usedManagedEnv: boolean }> {
|
|
200
|
+
console.log(chalk.dim(`Installing into managed environment: ${MANAGED_PYTHON_ENV}`));
|
|
181
201
|
|
|
182
202
|
if (uvPath) {
|
|
183
|
-
|
|
203
|
+
// Ensure venv exists (no-op if already created)
|
|
204
|
+
await $`${uvPath} venv ${MANAGED_PYTHON_ENV}`.quiet().nothrow();
|
|
205
|
+
const result = await $`${uvPath} pip install --python ${MANAGED_PYTHON_ENV} ${packages}`.nothrow();
|
|
206
|
+
return { success: result.exitCode === 0, usedManagedEnv: true };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const managedPython = managedPythonPath();
|
|
210
|
+
if (!(await Bun.file(managedPython).exists())) {
|
|
211
|
+
const createEnv = await $`${pythonPath} -m venv ${MANAGED_PYTHON_ENV}`.quiet().nothrow();
|
|
184
212
|
if (createEnv.exitCode !== 0) {
|
|
185
213
|
return { success: false, usedManagedEnv: true };
|
|
186
214
|
}
|
|
187
|
-
const installInManagedEnv = await $`${uvPath} pip install --python ${MANAGED_PYTHON_ENV} ${packages}`.nothrow();
|
|
188
|
-
return { success: installInManagedEnv.exitCode === 0, usedManagedEnv: true };
|
|
189
215
|
}
|
|
190
216
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const managedPython = managedPythonPath();
|
|
197
|
-
const installInManagedEnv = await $`${managedPython} -m pip install ${packages}`.nothrow();
|
|
198
|
-
return { success: installInManagedEnv.exitCode === 0, usedManagedEnv: true };
|
|
217
|
+
// Ensure pip is available in the managed env
|
|
218
|
+
await $`${managedPython} -m ensurepip`.quiet().nothrow();
|
|
219
|
+
const result = await $`${managedPython} -m pip install ${packages}`.nothrow();
|
|
220
|
+
return { success: result.exitCode === 0, usedManagedEnv: true };
|
|
199
221
|
}
|
|
200
222
|
|
|
201
223
|
/**
|
|
@@ -258,7 +280,13 @@ async function handlePythonSetup(flags: { json?: boolean; check?: boolean }): Pr
|
|
|
258
280
|
}
|
|
259
281
|
|
|
260
282
|
console.log("");
|
|
261
|
-
const install = await installPythonPackages(
|
|
283
|
+
const install = await installPythonPackages(
|
|
284
|
+
check.missingPackages,
|
|
285
|
+
check.pythonPath,
|
|
286
|
+
check.uvPath,
|
|
287
|
+
check.pipPath,
|
|
288
|
+
check.usingManagedEnv,
|
|
289
|
+
);
|
|
262
290
|
|
|
263
291
|
if (!install.success) {
|
|
264
292
|
console.error(chalk.red(`\n${theme.status.error} Installation failed`));
|
package/src/ipy/kernel.ts
CHANGED
|
@@ -129,8 +129,7 @@ export async function checkPythonKernelAvailability(cwd: string): Promise<Python
|
|
|
129
129
|
return {
|
|
130
130
|
ok: false,
|
|
131
131
|
pythonPath: runtime.pythonPath,
|
|
132
|
-
reason:
|
|
133
|
-
"kernel_gateway (jupyter-kernel-gateway) or ipykernel not installed. Run: python -m pip install jupyter_kernel_gateway ipykernel",
|
|
132
|
+
reason: "kernel_gateway (jupyter-kernel-gateway) or ipykernel not installed. Run: arcane setup python",
|
|
134
133
|
};
|
|
135
134
|
} catch (err: unknown) {
|
|
136
135
|
return { ok: false, reason: err instanceof Error ? err.message : String(err) };
|
package/src/patch/edit-tool.ts
CHANGED
|
@@ -314,10 +314,10 @@ export class EditTool implements AgentTool<TInput, any, Theme> {
|
|
|
314
314
|
});
|
|
315
315
|
break;
|
|
316
316
|
}
|
|
317
|
-
case "
|
|
317
|
+
case "replace_range": {
|
|
318
318
|
const { first, last, content } = edit;
|
|
319
319
|
anchorEdits.push({
|
|
320
|
-
op: "
|
|
320
|
+
op: "replace_range",
|
|
321
321
|
first: parseTag(first),
|
|
322
322
|
last: parseTag(last),
|
|
323
323
|
content: hashlineParseContent(content),
|
|
@@ -419,7 +419,7 @@ export class EditTool implements AgentTool<TInput, any, Theme> {
|
|
|
419
419
|
case "set":
|
|
420
420
|
refs.push(edit.tag);
|
|
421
421
|
break;
|
|
422
|
-
case "
|
|
422
|
+
case "replace_range":
|
|
423
423
|
refs.push(edit.first, edit.last);
|
|
424
424
|
break;
|
|
425
425
|
case "append":
|
package/src/patch/hashline.ts
CHANGED
|
@@ -17,7 +17,7 @@ import type { HashMismatch } from "./types";
|
|
|
17
17
|
export type LineTag = { line: number; hash: string };
|
|
18
18
|
export type HashlineEdit =
|
|
19
19
|
| { op: "set"; tag: LineTag; content: string[] }
|
|
20
|
-
| { op: "
|
|
20
|
+
| { op: "replace_range"; first: LineTag; last: LineTag; content: string[] }
|
|
21
21
|
| { op: "append"; after?: LineTag; content: string[] }
|
|
22
22
|
| { op: "prepend"; before?: LineTag; content: string[] }
|
|
23
23
|
| { op: "insert"; after: LineTag; before: LineTag; content: string[] };
|
|
@@ -647,7 +647,7 @@ export function applyHashlineEdits(
|
|
|
647
647
|
case "set":
|
|
648
648
|
touched.add(edit.tag.line);
|
|
649
649
|
break;
|
|
650
|
-
case "
|
|
650
|
+
case "replace_range":
|
|
651
651
|
for (let ln = edit.first.line; ln <= edit.last.line; ln++) touched.add(ln);
|
|
652
652
|
break;
|
|
653
653
|
case "append":
|
|
@@ -715,7 +715,7 @@ export function applyHashlineEdits(
|
|
|
715
715
|
if (!afterValid || !beforeValid) continue;
|
|
716
716
|
break;
|
|
717
717
|
}
|
|
718
|
-
case "
|
|
718
|
+
case "replace_range": {
|
|
719
719
|
if (edit.first.line > edit.last.line) {
|
|
720
720
|
throw new Error(`Range start line ${edit.first.line} must be <= end line ${edit.last.line}`);
|
|
721
721
|
}
|
|
@@ -740,7 +740,7 @@ export function applyHashlineEdits(
|
|
|
740
740
|
case "set":
|
|
741
741
|
lineKey = `s:${edit.tag.line}`;
|
|
742
742
|
break;
|
|
743
|
-
case "
|
|
743
|
+
case "replace_range":
|
|
744
744
|
lineKey = `r:${edit.first.line}:${edit.last.line}`;
|
|
745
745
|
break;
|
|
746
746
|
case "append":
|
|
@@ -783,7 +783,7 @@ export function applyHashlineEdits(
|
|
|
783
783
|
sortLine = edit.tag.line;
|
|
784
784
|
precedence = 0;
|
|
785
785
|
break;
|
|
786
|
-
case "
|
|
786
|
+
case "replace_range":
|
|
787
787
|
sortLine = edit.last.line;
|
|
788
788
|
precedence = 0;
|
|
789
789
|
break;
|
|
@@ -850,7 +850,7 @@ export function applyHashlineEdits(
|
|
|
850
850
|
trackFirstChanged(edit.tag.line);
|
|
851
851
|
break;
|
|
852
852
|
}
|
|
853
|
-
case "
|
|
853
|
+
case "replace_range": {
|
|
854
854
|
const count = edit.last.line - edit.first.line + 1;
|
|
855
855
|
const origLines = originalFileLines.slice(edit.first.line - 1, edit.first.line - 1 + count);
|
|
856
856
|
let stripped = autocorrect
|
package/src/patch/schemas.ts
CHANGED
|
@@ -133,7 +133,7 @@ const hashlinePrependEditSchema = Type.Object(
|
|
|
133
133
|
|
|
134
134
|
const hashlineRangeEditSchema = Type.Object(
|
|
135
135
|
{
|
|
136
|
-
op: Type.Literal("
|
|
136
|
+
op: Type.Literal("replace_range"),
|
|
137
137
|
first: hashlineTagFormat("first line"),
|
|
138
138
|
last: hashlineTagFormat("last line"),
|
|
139
139
|
content: hashlineReplaceContentFormat("Replacement"),
|