akemon 0.3.3 → 0.3.5
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 +24 -1
- package/dist/cli.js +218 -14
- package/dist/engine-peripheral.js +5 -4
- package/dist/engine-routing.js +99 -0
- package/dist/event-bus.js +63 -17
- package/dist/privacy-filter.js +269 -0
- package/dist/redaction.js +159 -0
- package/dist/relay-client.js +39 -2
- package/dist/server.js +222 -52
- package/dist/software-agent-memory.js +139 -0
- package/dist/software-agent-peripheral.js +599 -33
- package/dist/software-agent-stream-cli.js +101 -0
- package/package.json +1 -1
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export class SoftwareAgentStreamCliRenderer {
|
|
2
|
+
writers;
|
|
3
|
+
taskId;
|
|
4
|
+
stderrEndsWithNewline = true;
|
|
5
|
+
constructor(writers = {
|
|
6
|
+
stdout: (chunk) => process.stdout.write(chunk),
|
|
7
|
+
stderr: (chunk) => process.stderr.write(chunk),
|
|
8
|
+
}) {
|
|
9
|
+
this.writers = writers;
|
|
10
|
+
}
|
|
11
|
+
handleLine(line) {
|
|
12
|
+
const trimmed = line.trim();
|
|
13
|
+
if (!trimmed)
|
|
14
|
+
return false;
|
|
15
|
+
let event;
|
|
16
|
+
try {
|
|
17
|
+
event = JSON.parse(trimmed);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
this.stderrLine(`[software-agent] non-json: ${trimmed}`);
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return this.handleEvent(event);
|
|
24
|
+
}
|
|
25
|
+
handleEvent(event) {
|
|
26
|
+
const type = typeof event?.type === "string" ? event.type : "";
|
|
27
|
+
if (type === "start") {
|
|
28
|
+
const taskId = readString(event.taskId) || "unknown";
|
|
29
|
+
this.taskId = taskId;
|
|
30
|
+
this.stderrLine(`[software-agent] task ${taskId} started`);
|
|
31
|
+
const commandLine = readString(event.commandLine);
|
|
32
|
+
if (commandLine)
|
|
33
|
+
this.stderrLine(`[software-agent] command: ${truncateOneLine(commandLine, 160)}`);
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (type === "stdout" && typeof event.chunk === "string") {
|
|
37
|
+
this.writers.stdout(event.chunk);
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
if (type === "stderr" && typeof event.chunk === "string") {
|
|
41
|
+
this.writers.stderr(event.chunk);
|
|
42
|
+
this.stderrEndsWithNewline = event.chunk.endsWith("\n") || event.chunk.endsWith("\r");
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (type === "end") {
|
|
46
|
+
return this.handleEnd(event);
|
|
47
|
+
}
|
|
48
|
+
if (type === "error") {
|
|
49
|
+
this.stderrLine(`[software-agent] stream error: ${readString(event.error) || "unknown error"}`);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
this.stderrLine(`[software-agent] ignored stream event: ${type || "unknown"}`);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
handleEnd(event) {
|
|
56
|
+
const result = isObject(event.result) ? event.result : {};
|
|
57
|
+
const taskId = readString(event.taskId) || readString(result.taskId) || this.taskId || "unknown";
|
|
58
|
+
const success = result.success === false ? false : true;
|
|
59
|
+
const exitCode = readExitCode(event.exitCode) ?? readExitCode(result.exitCode);
|
|
60
|
+
const durationMs = readDurationMs(event.durationMs) ?? readDurationMs(result.durationMs);
|
|
61
|
+
const parts = [`[software-agent] task ${taskId} ${success ? "finished" : "failed"}`];
|
|
62
|
+
if (exitCode !== undefined)
|
|
63
|
+
parts.push(`exit=${exitCode}`);
|
|
64
|
+
if (durationMs !== undefined)
|
|
65
|
+
parts.push(`duration=${durationMs}ms`);
|
|
66
|
+
this.stderrLine(parts.join(" "));
|
|
67
|
+
const error = readString(result.error);
|
|
68
|
+
if (!success && error) {
|
|
69
|
+
this.stderrLine(`[software-agent] error: ${truncateOneLine(error, 240)}`);
|
|
70
|
+
}
|
|
71
|
+
const output = readString(result.output);
|
|
72
|
+
if (output) {
|
|
73
|
+
this.stderrLine(`[software-agent] summary: ${truncateOneLine(output, 240)}`);
|
|
74
|
+
}
|
|
75
|
+
return !success;
|
|
76
|
+
}
|
|
77
|
+
stderrLine(line) {
|
|
78
|
+
if (!this.stderrEndsWithNewline)
|
|
79
|
+
this.writers.stderr("\n");
|
|
80
|
+
this.writers.stderr(`${line}\n`);
|
|
81
|
+
this.stderrEndsWithNewline = true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function isObject(value) {
|
|
85
|
+
return typeof value === "object" && value !== null;
|
|
86
|
+
}
|
|
87
|
+
function readString(value) {
|
|
88
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
89
|
+
}
|
|
90
|
+
function readExitCode(value) {
|
|
91
|
+
return typeof value === "number" && Number.isInteger(value) ? value : undefined;
|
|
92
|
+
}
|
|
93
|
+
function readDurationMs(value) {
|
|
94
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : undefined;
|
|
95
|
+
}
|
|
96
|
+
function truncateOneLine(value, max) {
|
|
97
|
+
const oneLine = value.replace(/\s+/g, " ").trim();
|
|
98
|
+
if (oneLine.length <= max)
|
|
99
|
+
return oneLine;
|
|
100
|
+
return `${oneLine.slice(0, Math.max(0, max - 3))}...`;
|
|
101
|
+
}
|