palmier 0.5.0 → 0.5.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/run.js +10 -2
- package/dist/platform/windows.js +17 -1
- package/dist/rpc-handler.js +8 -1
- package/dist/transports/http-transport.js +6 -3
- package/package.json +1 -1
- package/src/commands/run.ts +10 -2
- package/src/platform/windows.ts +14 -1
- package/src/rpc-handler.ts +8 -1
- package/src/transports/http-transport.ts +9 -3
package/dist/commands/run.js
CHANGED
|
@@ -372,7 +372,11 @@ async function requestPermission(config, task, taskDir, requiredPermissions) {
|
|
|
372
372
|
permissions: requiredPermissions,
|
|
373
373
|
}),
|
|
374
374
|
});
|
|
375
|
-
const
|
|
375
|
+
const body = await res.json();
|
|
376
|
+
const response = body.response;
|
|
377
|
+
if (!response || !["granted", "granted_all", "aborted"].includes(response)) {
|
|
378
|
+
throw new Error(`Permission request failed: ${body.error ?? `unexpected response: ${JSON.stringify(body)}`}`);
|
|
379
|
+
}
|
|
376
380
|
writeTaskStatus(taskDir, {
|
|
377
381
|
running_state: response === "aborted" ? "aborted" : "started",
|
|
378
382
|
time_stamp: Date.now(),
|
|
@@ -386,7 +390,11 @@ async function requestConfirmation(config, task, taskDir) {
|
|
|
386
390
|
headers: { "Content-Type": "application/json" },
|
|
387
391
|
body: JSON.stringify({ taskId: task.frontmatter.id, taskName: task.frontmatter.name }),
|
|
388
392
|
});
|
|
389
|
-
const
|
|
393
|
+
const body = await res.json();
|
|
394
|
+
if (typeof body.confirmed !== "boolean") {
|
|
395
|
+
throw new Error(`Confirmation request failed: ${body.error ?? `unexpected response: ${JSON.stringify(body)}`}`);
|
|
396
|
+
}
|
|
397
|
+
const { confirmed } = body;
|
|
390
398
|
writeTaskStatus(taskDir, {
|
|
391
399
|
running_state: confirmed ? "started" : "aborted",
|
|
392
400
|
time_stamp: Date.now(),
|
package/dist/platform/windows.js
CHANGED
|
@@ -106,7 +106,7 @@ export class WindowsPlatform {
|
|
|
106
106
|
this.startDaemonTask();
|
|
107
107
|
process.exit(0);
|
|
108
108
|
}
|
|
109
|
-
// Kill old daemon
|
|
109
|
+
// Kill old daemon by PID
|
|
110
110
|
if (oldPid) {
|
|
111
111
|
try {
|
|
112
112
|
execFileSync("taskkill", ["/pid", oldPid, "/f", "/t"], { windowsHide: true, stdio: "pipe" });
|
|
@@ -115,6 +115,22 @@ export class WindowsPlatform {
|
|
|
115
115
|
// Process may have already exited
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
+
// Also kill any stale palmier serve processes (e.g. leftover from a previous daemon)
|
|
119
|
+
try {
|
|
120
|
+
const out = execFileSync("wmic", ["process", "where", `CommandLine like '%palmier%serve%' and ProcessId != '${process.pid}'`, "get", "ProcessId"], { encoding: "utf-8", windowsHide: true, stdio: "pipe" });
|
|
121
|
+
for (const line of out.split("\n")) {
|
|
122
|
+
const pid = line.trim();
|
|
123
|
+
if (pid && /^\d+$/.test(pid)) {
|
|
124
|
+
try {
|
|
125
|
+
execFileSync("taskkill", ["/pid", pid, "/f", "/t"], { windowsHide: true, stdio: "pipe" });
|
|
126
|
+
}
|
|
127
|
+
catch { }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// wmic may not be available on all Windows versions
|
|
133
|
+
}
|
|
118
134
|
this.startDaemonTask();
|
|
119
135
|
}
|
|
120
136
|
/** Create or update the Task Scheduler entry for the daemon. */
|
package/dist/rpc-handler.js
CHANGED
|
@@ -126,10 +126,17 @@ const activeFollowups = new Map();
|
|
|
126
126
|
export function createRpcHandler(config, nc) {
|
|
127
127
|
function flattenTask(task) {
|
|
128
128
|
const taskDir = getTaskDir(config.projectRoot, task.frontmatter.id);
|
|
129
|
+
const status = readTaskStatus(taskDir);
|
|
130
|
+
const pending = getPending(task.frontmatter.id);
|
|
129
131
|
return {
|
|
130
132
|
...task.frontmatter,
|
|
131
133
|
body: task.body,
|
|
132
|
-
status:
|
|
134
|
+
status: status ? {
|
|
135
|
+
...status,
|
|
136
|
+
...(pending?.type === "confirmation" ? { pending_confirmation: true } : {}),
|
|
137
|
+
...(pending?.type === "permission" ? { pending_permission: pending.params } : {}),
|
|
138
|
+
...(pending?.type === "input" ? { pending_input: pending.params } : {}),
|
|
139
|
+
} : undefined,
|
|
133
140
|
};
|
|
134
141
|
}
|
|
135
142
|
async function handleRpc(request) {
|
|
@@ -242,13 +242,14 @@ export async function startHttpTransport(config, handleRpc, port, nc, pairingCod
|
|
|
242
242
|
}
|
|
243
243
|
const taskDir = getTaskDir(config.projectRoot, taskId);
|
|
244
244
|
const task = parseTaskFile(taskDir);
|
|
245
|
+
const pendingPromise = registerPending(taskId, "input", descriptions);
|
|
245
246
|
await publishEvent(taskId, {
|
|
246
247
|
event_type: "input-request",
|
|
247
248
|
host_id: config.hostId,
|
|
248
249
|
input_descriptions: descriptions,
|
|
249
250
|
name: task.frontmatter.name,
|
|
250
251
|
});
|
|
251
|
-
const response = await
|
|
252
|
+
const response = await pendingPromise;
|
|
252
253
|
if (response.length === 1 && response[0] === "aborted") {
|
|
253
254
|
await publishEvent(taskId, { event_type: "input-resolved", host_id: config.hostId, status: "aborted" });
|
|
254
255
|
if (runId) {
|
|
@@ -283,11 +284,12 @@ export async function startHttpTransport(config, handleRpc, port, nc, pairingCod
|
|
|
283
284
|
sendJson(res, 400, { error: "taskId is required" });
|
|
284
285
|
return;
|
|
285
286
|
}
|
|
287
|
+
const pendingPromise = registerPending(taskId, "confirmation");
|
|
286
288
|
await publishEvent(taskId, {
|
|
287
289
|
event_type: "confirm-request",
|
|
288
290
|
host_id: config.hostId,
|
|
289
291
|
});
|
|
290
|
-
const response = await
|
|
292
|
+
const response = await pendingPromise;
|
|
291
293
|
const confirmed = response[0] === "confirmed";
|
|
292
294
|
await publishEvent(taskId, {
|
|
293
295
|
event_type: "confirm-resolved",
|
|
@@ -314,13 +316,14 @@ export async function startHttpTransport(config, handleRpc, port, nc, pairingCod
|
|
|
314
316
|
sendJson(res, 400, { error: "taskId and permissions are required" });
|
|
315
317
|
return;
|
|
316
318
|
}
|
|
319
|
+
const pendingPromise = registerPending(taskId, "permission", permissions);
|
|
317
320
|
await publishEvent(taskId, {
|
|
318
321
|
event_type: "permission-request",
|
|
319
322
|
host_id: config.hostId,
|
|
320
323
|
required_permissions: permissions,
|
|
321
324
|
name: taskName,
|
|
322
325
|
});
|
|
323
|
-
const response = await
|
|
326
|
+
const response = await pendingPromise;
|
|
324
327
|
const status = response[0];
|
|
325
328
|
await publishEvent(taskId, {
|
|
326
329
|
event_type: "permission-resolved",
|
package/package.json
CHANGED
package/src/commands/run.ts
CHANGED
|
@@ -454,7 +454,11 @@ async function requestPermission(
|
|
|
454
454
|
permissions: requiredPermissions,
|
|
455
455
|
}),
|
|
456
456
|
});
|
|
457
|
-
const
|
|
457
|
+
const body = await res.json() as { response?: string; error?: string };
|
|
458
|
+
const response = body.response as "granted" | "granted_all" | "aborted" | undefined;
|
|
459
|
+
if (!response || !["granted", "granted_all", "aborted"].includes(response)) {
|
|
460
|
+
throw new Error(`Permission request failed: ${body.error ?? `unexpected response: ${JSON.stringify(body)}`}`);
|
|
461
|
+
}
|
|
458
462
|
writeTaskStatus(taskDir, {
|
|
459
463
|
running_state: response === "aborted" ? "aborted" : "started",
|
|
460
464
|
time_stamp: Date.now(),
|
|
@@ -474,7 +478,11 @@ async function requestConfirmation(
|
|
|
474
478
|
headers: { "Content-Type": "application/json" },
|
|
475
479
|
body: JSON.stringify({ taskId: task.frontmatter.id, taskName: task.frontmatter.name }),
|
|
476
480
|
});
|
|
477
|
-
const
|
|
481
|
+
const body = await res.json() as { confirmed?: boolean; error?: string };
|
|
482
|
+
if (typeof body.confirmed !== "boolean") {
|
|
483
|
+
throw new Error(`Confirmation request failed: ${body.error ?? `unexpected response: ${JSON.stringify(body)}`}`);
|
|
484
|
+
}
|
|
485
|
+
const { confirmed } = body;
|
|
478
486
|
writeTaskStatus(taskDir, {
|
|
479
487
|
running_state: confirmed ? "started" : "aborted",
|
|
480
488
|
time_stamp: Date.now(),
|
package/src/platform/windows.ts
CHANGED
|
@@ -127,7 +127,7 @@ export class WindowsPlatform implements PlatformService {
|
|
|
127
127
|
process.exit(0);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
// Kill old daemon
|
|
130
|
+
// Kill old daemon by PID
|
|
131
131
|
if (oldPid) {
|
|
132
132
|
try {
|
|
133
133
|
execFileSync("taskkill", ["/pid", oldPid, "/f", "/t"], { windowsHide: true, stdio: "pipe" });
|
|
@@ -136,6 +136,19 @@ export class WindowsPlatform implements PlatformService {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
// Also kill any stale palmier serve processes (e.g. leftover from a previous daemon)
|
|
140
|
+
try {
|
|
141
|
+
const out = execFileSync("wmic", ["process", "where", `CommandLine like '%palmier%serve%' and ProcessId != '${process.pid}'`, "get", "ProcessId"], { encoding: "utf-8", windowsHide: true, stdio: "pipe" });
|
|
142
|
+
for (const line of out.split("\n")) {
|
|
143
|
+
const pid = line.trim();
|
|
144
|
+
if (pid && /^\d+$/.test(pid)) {
|
|
145
|
+
try { execFileSync("taskkill", ["/pid", pid, "/f", "/t"], { windowsHide: true, stdio: "pipe" }); } catch {}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
// wmic may not be available on all Windows versions
|
|
150
|
+
}
|
|
151
|
+
|
|
139
152
|
this.startDaemonTask();
|
|
140
153
|
}
|
|
141
154
|
|
package/src/rpc-handler.ts
CHANGED
|
@@ -151,10 +151,17 @@ const activeFollowups = new Map<string, ChildProcess>();
|
|
|
151
151
|
export function createRpcHandler(config: HostConfig, nc?: NatsConnection) {
|
|
152
152
|
function flattenTask(task: ParsedTask) {
|
|
153
153
|
const taskDir = getTaskDir(config.projectRoot, task.frontmatter.id);
|
|
154
|
+
const status = readTaskStatus(taskDir);
|
|
155
|
+
const pending = getPending(task.frontmatter.id);
|
|
154
156
|
return {
|
|
155
157
|
...task.frontmatter,
|
|
156
158
|
body: task.body,
|
|
157
|
-
status:
|
|
159
|
+
status: status ? {
|
|
160
|
+
...status,
|
|
161
|
+
...(pending?.type === "confirmation" ? { pending_confirmation: true } : {}),
|
|
162
|
+
...(pending?.type === "permission" ? { pending_permission: pending.params } : {}),
|
|
163
|
+
...(pending?.type === "input" ? { pending_input: pending.params } : {}),
|
|
164
|
+
} : undefined,
|
|
158
165
|
};
|
|
159
166
|
}
|
|
160
167
|
|
|
@@ -262,6 +262,8 @@ export async function startHttpTransport(
|
|
|
262
262
|
const taskDir = getTaskDir(config.projectRoot, taskId);
|
|
263
263
|
const task = parseTaskFile(taskDir);
|
|
264
264
|
|
|
265
|
+
const pendingPromise = registerPending(taskId, "input", descriptions);
|
|
266
|
+
|
|
265
267
|
await publishEvent(taskId, {
|
|
266
268
|
event_type: "input-request",
|
|
267
269
|
host_id: config.hostId,
|
|
@@ -269,7 +271,7 @@ export async function startHttpTransport(
|
|
|
269
271
|
name: task.frontmatter.name,
|
|
270
272
|
});
|
|
271
273
|
|
|
272
|
-
const response = await
|
|
274
|
+
const response = await pendingPromise;
|
|
273
275
|
|
|
274
276
|
if (response.length === 1 && response[0] === "aborted") {
|
|
275
277
|
await publishEvent(taskId, { event_type: "input-resolved", host_id: config.hostId, status: "aborted" });
|
|
@@ -300,12 +302,14 @@ export async function startHttpTransport(
|
|
|
300
302
|
const { taskId } = JSON.parse(body) as { taskId: string };
|
|
301
303
|
if (!taskId) { sendJson(res, 400, { error: "taskId is required" }); return; }
|
|
302
304
|
|
|
305
|
+
const pendingPromise = registerPending(taskId, "confirmation");
|
|
306
|
+
|
|
303
307
|
await publishEvent(taskId, {
|
|
304
308
|
event_type: "confirm-request",
|
|
305
309
|
host_id: config.hostId,
|
|
306
310
|
});
|
|
307
311
|
|
|
308
|
-
const response = await
|
|
312
|
+
const response = await pendingPromise;
|
|
309
313
|
const confirmed = response[0] === "confirmed";
|
|
310
314
|
|
|
311
315
|
await publishEvent(taskId, {
|
|
@@ -335,6 +339,8 @@ export async function startHttpTransport(
|
|
|
335
339
|
return;
|
|
336
340
|
}
|
|
337
341
|
|
|
342
|
+
const pendingPromise = registerPending(taskId, "permission", permissions);
|
|
343
|
+
|
|
338
344
|
await publishEvent(taskId, {
|
|
339
345
|
event_type: "permission-request",
|
|
340
346
|
host_id: config.hostId,
|
|
@@ -342,7 +348,7 @@ export async function startHttpTransport(
|
|
|
342
348
|
name: taskName,
|
|
343
349
|
});
|
|
344
350
|
|
|
345
|
-
const response = await
|
|
351
|
+
const response = await pendingPromise;
|
|
346
352
|
const status = response[0] as "granted" | "granted_all" | "aborted";
|
|
347
353
|
|
|
348
354
|
await publishEvent(taskId, {
|