palmier 0.2.9 → 0.3.1
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/commands/serve.js +4 -0
- package/dist/rpc-handler.js +10 -2
- package/dist/task.d.ts +0 -4
- package/dist/task.js +0 -12
- package/dist/update-checker.d.ts +15 -0
- package/dist/update-checker.js +73 -0
- package/package.json +1 -1
- package/src/commands/serve.ts +5 -0
- package/src/rpc-handler.ts +10 -2
- package/src/task.ts +0 -12
- package/src/update-checker.ts +74 -0
package/dist/commands/serve.js
CHANGED
|
@@ -7,6 +7,7 @@ import { startNatsTransport } from "../transports/nats-transport.js";
|
|
|
7
7
|
import { getTaskDir, readTaskStatus, writeTaskStatus, appendHistory, parseTaskFile } from "../task.js";
|
|
8
8
|
import { publishHostEvent } from "../events.js";
|
|
9
9
|
import { getPlatform } from "../platform/index.js";
|
|
10
|
+
import { checkForUpdate } from "../update-checker.js";
|
|
10
11
|
import { CONFIG_DIR } from "../config.js";
|
|
11
12
|
const POLL_INTERVAL_MS = 30_000;
|
|
12
13
|
const DAEMON_PID_FILE = path.join(CONFIG_DIR, "daemon.pid");
|
|
@@ -80,6 +81,9 @@ export async function serveCommand() {
|
|
|
80
81
|
console.error("[monitor] Error checking stale tasks:", err);
|
|
81
82
|
});
|
|
82
83
|
}, POLL_INTERVAL_MS);
|
|
84
|
+
// Check for updates on startup and every 24 hours
|
|
85
|
+
checkForUpdate().catch(() => { });
|
|
86
|
+
setInterval(() => { checkForUpdate().catch(() => { }); }, 24 * 60 * 60 * 1000);
|
|
83
87
|
const handleRpc = createRpcHandler(config, nc);
|
|
84
88
|
await startNatsTransport(config, handleRpc, nc);
|
|
85
89
|
}
|
package/dist/rpc-handler.js
CHANGED
|
@@ -3,12 +3,13 @@ import * as fs from "fs";
|
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { parse as parseYaml } from "yaml";
|
|
6
|
-
import { listTasks, parseTaskFile, writeTaskFile, getTaskDir,
|
|
6
|
+
import { listTasks, parseTaskFile, writeTaskFile, getTaskDir, readTaskStatus, writeTaskStatus, readHistory, deleteHistoryEntry, appendTaskList, removeFromTaskList } from "./task.js";
|
|
7
7
|
import { getPlatform } from "./platform/index.js";
|
|
8
8
|
import { spawnCommand } from "./spawn-command.js";
|
|
9
9
|
import { getAgent } from "./agents/agent.js";
|
|
10
10
|
import { validateSession } from "./session-store.js";
|
|
11
11
|
import { publishHostEvent } from "./events.js";
|
|
12
|
+
import { currentVersion, getLatestVersion, performUpdate } from "./update-checker.js";
|
|
12
13
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
14
|
const PLAN_GENERATION_PROMPT = fs.readFileSync(path.join(__dirname, "commands", "plan-generation.md"), "utf-8");
|
|
14
15
|
/**
|
|
@@ -92,7 +93,6 @@ export function createRpcHandler(config, nc) {
|
|
|
92
93
|
return {
|
|
93
94
|
...task.frontmatter,
|
|
94
95
|
body: task.body,
|
|
95
|
-
created_at: getTaskCreatedAt(taskDir),
|
|
96
96
|
status: readTaskStatus(taskDir),
|
|
97
97
|
};
|
|
98
98
|
}
|
|
@@ -107,6 +107,8 @@ export function createRpcHandler(config, nc) {
|
|
|
107
107
|
return {
|
|
108
108
|
tasks: tasks.map((task) => flattenTask(task)),
|
|
109
109
|
agents: config.agents ?? [],
|
|
110
|
+
version: currentVersion,
|
|
111
|
+
latest_version: getLatestVersion(),
|
|
110
112
|
};
|
|
111
113
|
}
|
|
112
114
|
case "task.create": {
|
|
@@ -332,6 +334,12 @@ export function createRpcHandler(config, nc) {
|
|
|
332
334
|
}
|
|
333
335
|
return { ok: true, task_id: params.task_id, result_file: params.result_file };
|
|
334
336
|
}
|
|
337
|
+
case "host.update": {
|
|
338
|
+
const error = await performUpdate();
|
|
339
|
+
if (error)
|
|
340
|
+
return { error };
|
|
341
|
+
return { ok: true };
|
|
342
|
+
}
|
|
335
343
|
default:
|
|
336
344
|
return { error: `Unknown method: ${request.method}` };
|
|
337
345
|
}
|
package/dist/task.d.ts
CHANGED
|
@@ -25,10 +25,6 @@ export declare function listTasks(projectRoot: string): ParsedTask[];
|
|
|
25
25
|
* Get the directory path for a task by its ID.
|
|
26
26
|
*/
|
|
27
27
|
export declare function getTaskDir(projectRoot: string, taskId: string): string;
|
|
28
|
-
/**
|
|
29
|
-
* Get the creation time (birthtime) of a TASK.md file in ms since epoch.
|
|
30
|
-
*/
|
|
31
|
-
export declare function getTaskCreatedAt(taskDir: string): number;
|
|
32
28
|
/**
|
|
33
29
|
* Write task status to status.json in the task directory.
|
|
34
30
|
*/
|
package/dist/task.js
CHANGED
|
@@ -109,18 +109,6 @@ export function listTasks(projectRoot) {
|
|
|
109
109
|
export function getTaskDir(projectRoot, taskId) {
|
|
110
110
|
return path.join(projectRoot, "tasks", taskId);
|
|
111
111
|
}
|
|
112
|
-
/**
|
|
113
|
-
* Get the creation time (birthtime) of a TASK.md file in ms since epoch.
|
|
114
|
-
*/
|
|
115
|
-
export function getTaskCreatedAt(taskDir) {
|
|
116
|
-
const filePath = path.join(taskDir, "TASK.md");
|
|
117
|
-
try {
|
|
118
|
-
return fs.statSync(filePath).birthtimeMs;
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
return 0;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
112
|
/**
|
|
125
113
|
* Write task status to status.json in the task directory.
|
|
126
114
|
*/
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const currentVersion: string;
|
|
2
|
+
/**
|
|
3
|
+
* Check the npm registry for the latest version of palmier.
|
|
4
|
+
*/
|
|
5
|
+
export declare function checkForUpdate(): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Get the latest version from npm, or null if not yet checked.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getLatestVersion(): string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Run the update and restart the daemon.
|
|
12
|
+
* Returns an error message if the update fails.
|
|
13
|
+
*/
|
|
14
|
+
export declare function performUpdate(): Promise<string | null>;
|
|
15
|
+
//# sourceMappingURL=update-checker.d.ts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { spawnCommand } from "./spawn-command.js";
|
|
5
|
+
import { getPlatform } from "./platform/index.js";
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8"));
|
|
8
|
+
export const currentVersion = pkg.version;
|
|
9
|
+
let latestVersion = null;
|
|
10
|
+
let lastCheckTime = 0;
|
|
11
|
+
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
12
|
+
/**
|
|
13
|
+
* Check the npm registry for the latest version of palmier.
|
|
14
|
+
*/
|
|
15
|
+
export async function checkForUpdate() {
|
|
16
|
+
const now = Date.now();
|
|
17
|
+
if (now - lastCheckTime < CHECK_INTERVAL_MS)
|
|
18
|
+
return;
|
|
19
|
+
lastCheckTime = now;
|
|
20
|
+
try {
|
|
21
|
+
const res = await fetch("https://registry.npmjs.org/palmier/latest", {
|
|
22
|
+
signal: AbortSignal.timeout(10_000),
|
|
23
|
+
});
|
|
24
|
+
if (!res.ok)
|
|
25
|
+
return;
|
|
26
|
+
const data = (await res.json());
|
|
27
|
+
if (data.version) {
|
|
28
|
+
latestVersion = data.version;
|
|
29
|
+
console.log(`[update] Latest version: ${data.version} (current: ${currentVersion})`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Network errors are expected (offline, etc.)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the latest version from npm, or null if not yet checked.
|
|
38
|
+
*/
|
|
39
|
+
export function getLatestVersion() {
|
|
40
|
+
return latestVersion;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Run the update and restart the daemon.
|
|
44
|
+
* Returns an error message if the update fails.
|
|
45
|
+
*/
|
|
46
|
+
export async function performUpdate() {
|
|
47
|
+
try {
|
|
48
|
+
const { output, exitCode } = await spawnCommand("npm", ["update", "-g", "palmier"], {
|
|
49
|
+
cwd: process.cwd(),
|
|
50
|
+
timeout: 120_000,
|
|
51
|
+
resolveOnFailure: true,
|
|
52
|
+
});
|
|
53
|
+
if (exitCode !== 0) {
|
|
54
|
+
console.error(`[update] npm update failed (exit ${exitCode}):`, output);
|
|
55
|
+
return `Update failed. Please run manually:\nnpm update -g palmier`;
|
|
56
|
+
}
|
|
57
|
+
console.log("[update] Update installed, restarting daemon...");
|
|
58
|
+
latestVersion = null;
|
|
59
|
+
// Small delay to allow the RPC response to be sent
|
|
60
|
+
setTimeout(() => {
|
|
61
|
+
getPlatform().restartDaemon().catch((err) => {
|
|
62
|
+
console.error("[update] Restart failed:", err);
|
|
63
|
+
});
|
|
64
|
+
}, 1000);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
69
|
+
console.error("[update] Update failed:", msg);
|
|
70
|
+
return `Update failed. Please run manually:\nnpm update -g palmier`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=update-checker.js.map
|
package/package.json
CHANGED
package/src/commands/serve.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { startNatsTransport } from "../transports/nats-transport.js";
|
|
|
7
7
|
import { getTaskDir, readTaskStatus, writeTaskStatus, appendHistory, parseTaskFile } from "../task.js";
|
|
8
8
|
import { publishHostEvent } from "../events.js";
|
|
9
9
|
import { getPlatform } from "../platform/index.js";
|
|
10
|
+
import { checkForUpdate } from "../update-checker.js";
|
|
10
11
|
import type { HostConfig } from "../types.js";
|
|
11
12
|
import { CONFIG_DIR } from "../config.js";
|
|
12
13
|
import type { NatsConnection } from "nats";
|
|
@@ -100,6 +101,10 @@ export async function serveCommand(): Promise<void> {
|
|
|
100
101
|
});
|
|
101
102
|
}, POLL_INTERVAL_MS);
|
|
102
103
|
|
|
104
|
+
// Check for updates on startup and every 24 hours
|
|
105
|
+
checkForUpdate().catch(() => {});
|
|
106
|
+
setInterval(() => { checkForUpdate().catch(() => {}); }, 24 * 60 * 60 * 1000);
|
|
107
|
+
|
|
103
108
|
const handleRpc = createRpcHandler(config, nc);
|
|
104
109
|
await startNatsTransport(config, handleRpc, nc);
|
|
105
110
|
}
|
package/src/rpc-handler.ts
CHANGED
|
@@ -4,12 +4,13 @@ import * as path from "path";
|
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { parse as parseYaml } from "yaml";
|
|
6
6
|
import { type NatsConnection } from "nats";
|
|
7
|
-
import { listTasks, parseTaskFile, writeTaskFile, getTaskDir,
|
|
7
|
+
import { listTasks, parseTaskFile, writeTaskFile, getTaskDir, readTaskStatus, writeTaskStatus, readHistory, deleteHistoryEntry, appendTaskList, removeFromTaskList } from "./task.js";
|
|
8
8
|
import { getPlatform } from "./platform/index.js";
|
|
9
9
|
import { spawnCommand } from "./spawn-command.js";
|
|
10
10
|
import { getAgent } from "./agents/agent.js";
|
|
11
11
|
import { validateSession } from "./session-store.js";
|
|
12
12
|
import { publishHostEvent } from "./events.js";
|
|
13
|
+
import { currentVersion, getLatestVersion, performUpdate } from "./update-checker.js";
|
|
13
14
|
import type { HostConfig, ParsedTask, RpcMessage } from "./types.js";
|
|
14
15
|
|
|
15
16
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -105,7 +106,6 @@ export function createRpcHandler(config: HostConfig, nc?: NatsConnection) {
|
|
|
105
106
|
return {
|
|
106
107
|
...task.frontmatter,
|
|
107
108
|
body: task.body,
|
|
108
|
-
created_at: getTaskCreatedAt(taskDir),
|
|
109
109
|
status: readTaskStatus(taskDir),
|
|
110
110
|
};
|
|
111
111
|
}
|
|
@@ -122,6 +122,8 @@ export function createRpcHandler(config: HostConfig, nc?: NatsConnection) {
|
|
|
122
122
|
return {
|
|
123
123
|
tasks: tasks.map((task) => flattenTask(task)),
|
|
124
124
|
agents: config.agents ?? [],
|
|
125
|
+
version: currentVersion,
|
|
126
|
+
latest_version: getLatestVersion(),
|
|
125
127
|
};
|
|
126
128
|
}
|
|
127
129
|
|
|
@@ -379,6 +381,12 @@ export function createRpcHandler(config: HostConfig, nc?: NatsConnection) {
|
|
|
379
381
|
return { ok: true, task_id: params.task_id, result_file: params.result_file };
|
|
380
382
|
}
|
|
381
383
|
|
|
384
|
+
case "host.update": {
|
|
385
|
+
const error = await performUpdate();
|
|
386
|
+
if (error) return { error };
|
|
387
|
+
return { ok: true };
|
|
388
|
+
}
|
|
389
|
+
|
|
382
390
|
default:
|
|
383
391
|
return { error: `Unknown method: ${request.method}` };
|
|
384
392
|
}
|
package/src/task.ts
CHANGED
|
@@ -126,18 +126,6 @@ export function getTaskDir(projectRoot: string, taskId: string): string {
|
|
|
126
126
|
return path.join(projectRoot, "tasks", taskId);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
/**
|
|
130
|
-
* Get the creation time (birthtime) of a TASK.md file in ms since epoch.
|
|
131
|
-
*/
|
|
132
|
-
export function getTaskCreatedAt(taskDir: string): number {
|
|
133
|
-
const filePath = path.join(taskDir, "TASK.md");
|
|
134
|
-
try {
|
|
135
|
-
return fs.statSync(filePath).birthtimeMs;
|
|
136
|
-
} catch {
|
|
137
|
-
return 0;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
129
|
/**
|
|
142
130
|
* Write task status to status.json in the task directory.
|
|
143
131
|
*/
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { spawnCommand } from "./spawn-command.js";
|
|
5
|
+
import { getPlatform } from "./platform/index.js";
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8")) as { version: string };
|
|
9
|
+
export const currentVersion = pkg.version;
|
|
10
|
+
|
|
11
|
+
let latestVersion: string | null = null;
|
|
12
|
+
let lastCheckTime = 0;
|
|
13
|
+
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check the npm registry for the latest version of palmier.
|
|
17
|
+
*/
|
|
18
|
+
export async function checkForUpdate(): Promise<void> {
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
if (now - lastCheckTime < CHECK_INTERVAL_MS) return;
|
|
21
|
+
lastCheckTime = now;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch("https://registry.npmjs.org/palmier/latest", {
|
|
25
|
+
signal: AbortSignal.timeout(10_000),
|
|
26
|
+
});
|
|
27
|
+
if (!res.ok) return;
|
|
28
|
+
const data = (await res.json()) as { version?: string };
|
|
29
|
+
if (data.version) {
|
|
30
|
+
latestVersion = data.version;
|
|
31
|
+
console.log(`[update] Latest version: ${data.version} (current: ${currentVersion})`);
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
// Network errors are expected (offline, etc.)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get the latest version from npm, or null if not yet checked.
|
|
40
|
+
*/
|
|
41
|
+
export function getLatestVersion(): string | null {
|
|
42
|
+
return latestVersion;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Run the update and restart the daemon.
|
|
47
|
+
* Returns an error message if the update fails.
|
|
48
|
+
*/
|
|
49
|
+
export async function performUpdate(): Promise<string | null> {
|
|
50
|
+
try {
|
|
51
|
+
const { output, exitCode } = await spawnCommand("npm", ["update", "-g", "palmier"], {
|
|
52
|
+
cwd: process.cwd(),
|
|
53
|
+
timeout: 120_000,
|
|
54
|
+
resolveOnFailure: true,
|
|
55
|
+
});
|
|
56
|
+
if (exitCode !== 0) {
|
|
57
|
+
console.error(`[update] npm update failed (exit ${exitCode}):`, output);
|
|
58
|
+
return `Update failed. Please run manually:\nnpm update -g palmier`;
|
|
59
|
+
}
|
|
60
|
+
console.log("[update] Update installed, restarting daemon...");
|
|
61
|
+
latestVersion = null;
|
|
62
|
+
// Small delay to allow the RPC response to be sent
|
|
63
|
+
setTimeout(() => {
|
|
64
|
+
getPlatform().restartDaemon().catch((err) => {
|
|
65
|
+
console.error("[update] Restart failed:", err);
|
|
66
|
+
});
|
|
67
|
+
}, 1000);
|
|
68
|
+
return null;
|
|
69
|
+
} catch (err) {
|
|
70
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
71
|
+
console.error("[update] Update failed:", msg);
|
|
72
|
+
return `Update failed. Please run manually:\nnpm update -g palmier`;
|
|
73
|
+
}
|
|
74
|
+
}
|