nolo-cli 0.1.11 → 0.1.13
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/README.md +45 -0
- package/agentRuntimeCommands.ts +6 -4
- package/ai/agent/agentSlice.ts +2 -0
- package/ai/agent/cliExecutor.ts +733 -0
- package/ai/agent/cliPrompt.ts +10 -0
- package/ai/agent/machineRunPermissions.ts +95 -0
- package/ai/agent.ts +2 -0
- package/ai/index.ts +1 -0
- package/authCommands.ts +185 -21
- package/client/compactDialog.ts +222 -0
- package/commandRegistry.ts +2 -0
- package/connector-experimental/capabilities.ts +73 -0
- package/connector-experimental/codexBinary.ts +41 -0
- package/connector-experimental/heartbeatLoop.ts +22 -0
- package/connector-experimental/machineInfo.ts +46 -0
- package/connector-experimental/protocol.ts +54 -0
- package/machineCommands.ts +5 -5
- package/package.json +7 -11
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type HeartbeatLoopOptions = {
|
|
2
|
+
intervalMs: number;
|
|
3
|
+
sendHeartbeat: () => Promise<void>;
|
|
4
|
+
sleep?: (ms: number) => Promise<void>;
|
|
5
|
+
signal?: AbortSignal;
|
|
6
|
+
maxBeats?: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const defaultSleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
10
|
+
|
|
11
|
+
export async function runHeartbeatLoop(options: HeartbeatLoopOptions): Promise<void> {
|
|
12
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
13
|
+
let beats = 0;
|
|
14
|
+
|
|
15
|
+
while (!options.signal?.aborted) {
|
|
16
|
+
await options.sendHeartbeat();
|
|
17
|
+
beats += 1;
|
|
18
|
+
if (options.maxBeats && beats >= options.maxBeats) return;
|
|
19
|
+
if (options.signal?.aborted) return;
|
|
20
|
+
await sleep(options.intervalMs);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { arch, hostname, homedir, platform } from "node:os";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
|
|
6
|
+
import { detectRuntimeCapabilities } from "./capabilities";
|
|
7
|
+
import type { MachineHeartbeat } from "./protocol";
|
|
8
|
+
|
|
9
|
+
const CONNECTOR_VERSION = "0.1.0-experimental";
|
|
10
|
+
|
|
11
|
+
function defaultMachineIdPath() {
|
|
12
|
+
return join(homedir(), ".nolo", "machine-id");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function resolveMachineId(path = defaultMachineIdPath()) {
|
|
16
|
+
try {
|
|
17
|
+
if (existsSync(path)) {
|
|
18
|
+
const existing = readFileSync(path, "utf8").trim();
|
|
19
|
+
if (existing) return existing;
|
|
20
|
+
}
|
|
21
|
+
const next = `machine-${randomUUID()}`;
|
|
22
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
23
|
+
writeFileSync(path, `${next}\n`, "utf8");
|
|
24
|
+
return next;
|
|
25
|
+
} catch {
|
|
26
|
+
return `machine-${hostname().toLowerCase()}`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function detectMachineInfo(overrides?: {
|
|
31
|
+
machineId?: string;
|
|
32
|
+
name?: string;
|
|
33
|
+
capabilities?: string[];
|
|
34
|
+
probeLaunchable?: boolean;
|
|
35
|
+
}): MachineHeartbeat {
|
|
36
|
+
return {
|
|
37
|
+
machineId: overrides?.machineId ?? resolveMachineId(),
|
|
38
|
+
name: overrides?.name ?? hostname(),
|
|
39
|
+
platform: platform(),
|
|
40
|
+
arch: arch(),
|
|
41
|
+
connectorVersion: CONNECTOR_VERSION,
|
|
42
|
+
capabilities: overrides?.capabilities ?? detectRuntimeCapabilities({
|
|
43
|
+
probeLaunchable: overrides?.probeLaunchable,
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type MachineHeartbeatInput = {
|
|
2
|
+
machineId?: unknown;
|
|
3
|
+
name?: unknown;
|
|
4
|
+
platform?: unknown;
|
|
5
|
+
arch?: unknown;
|
|
6
|
+
connectorVersion?: unknown;
|
|
7
|
+
capabilities?: unknown;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type MachineHeartbeat = {
|
|
11
|
+
machineId: string;
|
|
12
|
+
name: string;
|
|
13
|
+
platform: string;
|
|
14
|
+
arch: string;
|
|
15
|
+
connectorVersion?: string;
|
|
16
|
+
capabilities: string[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const normalizeRequiredString = (value: unknown, field: string) => {
|
|
20
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
21
|
+
throw new Error(`${field} is required`);
|
|
22
|
+
}
|
|
23
|
+
return value.trim();
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const normalizeOptionalString = (value: unknown) =>
|
|
27
|
+
typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
28
|
+
|
|
29
|
+
export function normalizeCapabilityList(value: unknown): string[] {
|
|
30
|
+
if (!Array.isArray(value)) return [];
|
|
31
|
+
const seen = new Set<string>();
|
|
32
|
+
const result: string[] = [];
|
|
33
|
+
for (const item of value) {
|
|
34
|
+
if (typeof item !== "string") continue;
|
|
35
|
+
const normalized = item.trim();
|
|
36
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
37
|
+
seen.add(normalized);
|
|
38
|
+
result.push(normalized);
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function normalizeMachineHeartbeat(input: MachineHeartbeatInput): MachineHeartbeat {
|
|
44
|
+
const heartbeat: MachineHeartbeat = {
|
|
45
|
+
machineId: normalizeRequiredString(input.machineId, "machineId"),
|
|
46
|
+
name: normalizeRequiredString(input.name, "name"),
|
|
47
|
+
platform: normalizeRequiredString(input.platform, "platform"),
|
|
48
|
+
arch: normalizeRequiredString(input.arch, "arch"),
|
|
49
|
+
capabilities: normalizeCapabilityList(input.capabilities),
|
|
50
|
+
};
|
|
51
|
+
const connectorVersion = normalizeOptionalString(input.connectorVersion);
|
|
52
|
+
if (connectorVersion) heartbeat.connectorVersion = connectorVersion;
|
|
53
|
+
return heartbeat;
|
|
54
|
+
}
|
package/machineCommands.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { MachineHeartbeat } from "connector-experimental/protocol";
|
|
2
|
-
import { detectMachineInfo } from "connector-experimental/machineInfo";
|
|
1
|
+
import type { MachineHeartbeat } from "./connector-experimental/protocol";
|
|
2
|
+
import { detectMachineInfo } from "./connector-experimental/machineInfo";
|
|
3
3
|
import { mkdirSync, openSync } from "node:fs";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
@@ -7,12 +7,12 @@ import { DEFAULT_NOLO_SERVER_URL } from "./defaultServer";
|
|
|
7
7
|
import {
|
|
8
8
|
type HeartbeatLoopOptions,
|
|
9
9
|
runHeartbeatLoop as defaultRunHeartbeatLoop,
|
|
10
|
-
} from "connector-experimental/heartbeatLoop";
|
|
10
|
+
} from "./connector-experimental/heartbeatLoop";
|
|
11
11
|
import {
|
|
12
12
|
assertMachineRunAllowed,
|
|
13
13
|
buildMachinePermissionPromptBlock,
|
|
14
14
|
resolveMachineRunPermissionPolicy,
|
|
15
|
-
} from "
|
|
15
|
+
} from "./ai/agent/machineRunPermissions";
|
|
16
16
|
import { resolveConnectorWebSocketTarget } from "./connectorWebSocketTarget";
|
|
17
17
|
|
|
18
18
|
type EnvLike = Record<string, string | undefined>;
|
|
@@ -161,7 +161,7 @@ async function defaultConnectWebSocket(url: string, options: ConnectorWebSocketO
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
async function defaultExecuteCli(provider: string, prompt: string, options: { model?: string; yolo?: boolean }) {
|
|
164
|
-
const { executeCli } = await import("ai/agent/cliExecutor");
|
|
164
|
+
const { executeCli } = await import("./ai/agent/cliExecutor");
|
|
165
165
|
return executeCli(provider as any, prompt, options);
|
|
166
166
|
}
|
|
167
167
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nolo-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent-first terminal workspace for Nolo",
|
|
6
6
|
"bin": {
|
|
@@ -16,21 +16,17 @@
|
|
|
16
16
|
"defaultServer.ts",
|
|
17
17
|
"machineCommands.ts",
|
|
18
18
|
"updateCommands.ts",
|
|
19
|
-
"client
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
19
|
+
"client/**/*.ts",
|
|
20
|
+
"tui/**/*.ts",
|
|
21
|
+
"README.md",
|
|
22
|
+
"ai/**/*.ts",
|
|
23
|
+
"connector-experimental/**/*.ts"
|
|
24
24
|
],
|
|
25
25
|
"publishConfig": {
|
|
26
26
|
"access": "public"
|
|
27
27
|
},
|
|
28
|
-
"devDependencies": {
|
|
29
|
-
"bun-types": "latest"
|
|
30
|
-
},
|
|
31
28
|
"dependencies": {
|
|
32
|
-
"
|
|
33
|
-
"connector-experimental": "workspace:*"
|
|
29
|
+
"ulid": "^2.3.0"
|
|
34
30
|
},
|
|
35
31
|
"peerDependencies": {
|
|
36
32
|
"typescript": "^5.0.0"
|