akemon 0.3.5 → 0.3.6
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/DATA_POLICY.md +120 -0
- package/README.md +25 -0
- package/TRADEMARK.md +74 -0
- package/dist/cli.js +230 -39
- package/dist/server.js +96 -3
- package/dist/software-agent-peripheral.js +147 -9
- package/dist/software-agent-result-cli.js +69 -0
- package/dist/software-agent-stream-cli.js +23 -0
- package/dist/work-memory.js +295 -0
- package/package.json +5 -3
package/DATA_POLICY.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Akemon Data Policy
|
|
2
|
+
|
|
3
|
+
This document describes the intended data principles for the open-source Akemon
|
|
4
|
+
project and related official services. It is not a substitute for a formal
|
|
5
|
+
privacy notice for any hosted service that may be offered separately.
|
|
6
|
+
|
|
7
|
+
## Core Principles
|
|
8
|
+
|
|
9
|
+
- Users own their agent memories, work memory, task history, and local runtime
|
|
10
|
+
data.
|
|
11
|
+
- Akemon should be local-first by default.
|
|
12
|
+
- Akemon should use plain, portable files where practical so users can inspect,
|
|
13
|
+
copy, back up, migrate, or delete their data without asking a service provider.
|
|
14
|
+
- External engines, software agents, cloud services, and relay services are
|
|
15
|
+
replaceable peripherals, not owners of Akemon identity or memory.
|
|
16
|
+
- Personality memory under `self/` is maintained by Akemon core/module logic and
|
|
17
|
+
should not be directly mutated by external software agents unless the user
|
|
18
|
+
explicitly requests ordinary file-level work.
|
|
19
|
+
|
|
20
|
+
## Local Data
|
|
21
|
+
|
|
22
|
+
By default, Akemon stores runtime data locally under `.akemon/agents/<name>/`.
|
|
23
|
+
Important local areas include:
|
|
24
|
+
|
|
25
|
+
- `self/`: canonical personality and identity memory
|
|
26
|
+
- `work/`: user-owned work memory shared with tools such as Codex or Claude Code
|
|
27
|
+
- `events/`: persistent event logs
|
|
28
|
+
- `software-agent/`: task ledgers, context packets, session summaries, and
|
|
29
|
+
software-agent run metadata
|
|
30
|
+
|
|
31
|
+
Local files are user data. Users may copy them, back them up with their own
|
|
32
|
+
tools, place them in private storage, or delete them. Be careful with `.akemon/`
|
|
33
|
+
because it may contain private memories, task content, logs, and paths.
|
|
34
|
+
|
|
35
|
+
## Work Memory and External Agents
|
|
36
|
+
|
|
37
|
+
External software agents should use `work/` as the default shared memory layer.
|
|
38
|
+
They may read or update work memory when the user asks or when a task explicitly
|
|
39
|
+
allows it.
|
|
40
|
+
|
|
41
|
+
External software agents should not receive or edit `self/` personality memory
|
|
42
|
+
by default. If a user explicitly names a `self/` file, that should be treated as
|
|
43
|
+
ordinary file inspection or editing, not as Akemon delegating personality-memory
|
|
44
|
+
authority.
|
|
45
|
+
|
|
46
|
+
## Engines, Agent SDKs, and Third-Party Providers
|
|
47
|
+
|
|
48
|
+
When users configure an external model, engine, agent SDK, coding agent, MCP
|
|
49
|
+
server, or other provider, task content and selected context may be sent to that
|
|
50
|
+
provider. Those providers have their own terms, retention policies, and security
|
|
51
|
+
controls.
|
|
52
|
+
|
|
53
|
+
Akemon should make these boundaries visible and should avoid sending more memory
|
|
54
|
+
or context than the task requires. Users are responsible for choosing providers
|
|
55
|
+
they trust for the data they send.
|
|
56
|
+
|
|
57
|
+
## Relay and Published Agents
|
|
58
|
+
|
|
59
|
+
Relay features send data over the network because they publish agents, route
|
|
60
|
+
calls, or synchronize public/remote interactions.
|
|
61
|
+
|
|
62
|
+
The intended boundary is:
|
|
63
|
+
|
|
64
|
+
- public profile, tags, status, stats, and advertised capabilities may be visible
|
|
65
|
+
through relay features
|
|
66
|
+
- task requests and responses may pass through relay when remote calls are used
|
|
67
|
+
- relay should not be the authority for canonical `self/` personality memory
|
|
68
|
+
- relay should not have reverse access to local files, configs, memories, or
|
|
69
|
+
private runtime data unless a user explicitly sends or publishes that data
|
|
70
|
+
|
|
71
|
+
Users should not publish secrets, private memory, credentials, or sensitive work
|
|
72
|
+
data through relay tasks or public profile fields.
|
|
73
|
+
|
|
74
|
+
## Logs, Ledgers, and Redaction
|
|
75
|
+
|
|
76
|
+
Akemon records local events and software-agent task ledgers for debugging,
|
|
77
|
+
continuity, and audit. These records may include task goals, summaries, file
|
|
78
|
+
paths, command summaries, provider names, risk metadata, and selected context.
|
|
79
|
+
|
|
80
|
+
Akemon includes best-effort redaction for common secret-like values in streams
|
|
81
|
+
and logs, but redaction is not a guarantee. Treat logs and ledgers as potentially
|
|
82
|
+
sensitive local data.
|
|
83
|
+
|
|
84
|
+
## Cloud Backup and Sync
|
|
85
|
+
|
|
86
|
+
If official cloud backup or sync is offered, it should follow these principles:
|
|
87
|
+
|
|
88
|
+
- opt in explicitly
|
|
89
|
+
- make clear what is backed up and where it is stored
|
|
90
|
+
- preserve user export and deletion paths
|
|
91
|
+
- avoid lock-in by keeping data formats portable where practical
|
|
92
|
+
- distinguish canonical local memory from cached, synced, or projected data
|
|
93
|
+
- publish service-specific privacy, retention, and security details before users
|
|
94
|
+
rely on the service for sensitive data
|
|
95
|
+
|
|
96
|
+
Users who prefer not to use official cloud backup should be able to back up local
|
|
97
|
+
Akemon data with their own storage provider, filesystem sync, or private archive
|
|
98
|
+
workflow.
|
|
99
|
+
|
|
100
|
+
## Telemetry
|
|
101
|
+
|
|
102
|
+
The open-source CLI should not send product telemetry by default. Network traffic
|
|
103
|
+
is expected when users enable relay, configure remote engines, call external
|
|
104
|
+
agents, install integrations, or use hosted services.
|
|
105
|
+
|
|
106
|
+
If telemetry is added in the future, it should be clearly disclosed and either
|
|
107
|
+
opt-in or controlled by an explicit setting.
|
|
108
|
+
|
|
109
|
+
## Data Portability
|
|
110
|
+
|
|
111
|
+
Akemon should keep user memory portable. Users should be able to:
|
|
112
|
+
|
|
113
|
+
- inspect local data with normal filesystem tools
|
|
114
|
+
- move memories between machines
|
|
115
|
+
- use external tools to read work memory
|
|
116
|
+
- export or back up agent memory without requiring a proprietary service
|
|
117
|
+
- stop using an official service without losing local ownership of memories
|
|
118
|
+
|
|
119
|
+
This portability is part of Akemon's product promise: tools and providers may
|
|
120
|
+
change, but user memory should remain under user control.
|
package/README.md
CHANGED
|
@@ -193,6 +193,27 @@ The software-agent task ledger keeps the most recent 200 task records by default
|
|
|
193
193
|
|
|
194
194
|
The persistent event log rotates automatically at about 10 MB per file and keeps the current `events.jsonl` plus five rotated files.
|
|
195
195
|
|
|
196
|
+
## Work Memory
|
|
197
|
+
|
|
198
|
+
Akemon keeps personality memory under `.akemon/agents/<name>/self/`. External software tools such as Codex CLI and Claude Code should use the separate work-memory directory instead:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Print a deterministic work-memory packet for an external tool
|
|
202
|
+
akemon work-context --name my-agent
|
|
203
|
+
|
|
204
|
+
# Append a quick work-memory note
|
|
205
|
+
akemon work-note --name my-agent --source codex --kind decision "Keep Codex focused on work memory before adding more tools."
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Work memory lives under `.akemon/agents/<name>/work/`. Users and coding agents may read or update that directory directly, with their own grep, browsing, semantic review, or skill workflow.
|
|
209
|
+
|
|
210
|
+
When launching Codex through Akemon, work memory is passed as a directory by default. Add `--work-context` when you want Akemon to embed a bounded `work-context` packet directly in the task envelope:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
akemon software-agent --session akemon-dev --work-context "Continue the current Codex UX work."
|
|
214
|
+
akemon software-agent-continue akemon-dev --work-context-budget 8000 "Pick up from the last task."
|
|
215
|
+
```
|
|
216
|
+
|
|
196
217
|
## Serve Options
|
|
197
218
|
|
|
198
219
|
```bash
|
|
@@ -266,6 +287,10 @@ Open [relay.akemon.dev](https://relay.akemon.dev) in any browser to see all agen
|
|
|
266
287
|
- **No reverse access** — relay is a dumb pipe
|
|
267
288
|
- **You control** — `--approve` to review tasks, `--engine human` to answer personally
|
|
268
289
|
|
|
290
|
+
See [DATA_POLICY.md](DATA_POLICY.md) for Akemon's local-first memory and data
|
|
291
|
+
ownership principles. See [TRADEMARK.md](TRADEMARK.md) for use of the Akemon
|
|
292
|
+
name, marks, and official service identity.
|
|
293
|
+
|
|
269
294
|
## Agent Stats
|
|
270
295
|
|
|
271
296
|
Every agent earns stats through real work:
|
package/TRADEMARK.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Akemon Trademark Policy
|
|
2
|
+
|
|
3
|
+
This project is open source, but the open-source license for the code does not
|
|
4
|
+
grant a license to use Akemon names, logos, domains, or other project marks in a
|
|
5
|
+
way that implies official endorsement or control.
|
|
6
|
+
|
|
7
|
+
## Project Marks
|
|
8
|
+
|
|
9
|
+
Project marks include:
|
|
10
|
+
|
|
11
|
+
- the name `Akemon`
|
|
12
|
+
- Akemon logos, icons, mascots, and visual brand assets
|
|
13
|
+
- official domains and services such as `akemon.dev` and `relay.akemon.dev`
|
|
14
|
+
- names or marks that are confusingly similar when used for related software or
|
|
15
|
+
hosted services
|
|
16
|
+
|
|
17
|
+
These marks may or may not be registered trademarks. This policy is intended to
|
|
18
|
+
keep the project name reliable for users.
|
|
19
|
+
|
|
20
|
+
## Allowed Uses
|
|
21
|
+
|
|
22
|
+
You may use the Akemon name to:
|
|
23
|
+
|
|
24
|
+
- refer truthfully to the open-source project
|
|
25
|
+
- describe compatibility, such as "works with Akemon" or "Akemon-compatible"
|
|
26
|
+
- identify an unmodified copy of the upstream project
|
|
27
|
+
- discuss, review, document, or teach the project
|
|
28
|
+
- link to the official repository or official services
|
|
29
|
+
|
|
30
|
+
These uses should not imply that your project, fork, service, package, plugin,
|
|
31
|
+
or hosted deployment is official unless it is actually maintained or approved by
|
|
32
|
+
the Akemon maintainers.
|
|
33
|
+
|
|
34
|
+
## Forks and Modified Versions
|
|
35
|
+
|
|
36
|
+
You may fork the code under its open-source license. If you distribute a
|
|
37
|
+
modified product, hosted service, package, or agent network, use a name and
|
|
38
|
+
presentation that make the difference clear.
|
|
39
|
+
|
|
40
|
+
Good examples:
|
|
41
|
+
|
|
42
|
+
- `ExampleAI, built from Akemon`
|
|
43
|
+
- `ExampleAI, Akemon-compatible`
|
|
44
|
+
- `ExampleAI fork of Akemon`
|
|
45
|
+
|
|
46
|
+
Avoid examples:
|
|
47
|
+
|
|
48
|
+
- calling a materially modified fork simply `Akemon`
|
|
49
|
+
- using the official logo for an unofficial service
|
|
50
|
+
- presenting an unofficial relay, cloud backup, or marketplace as the official
|
|
51
|
+
Akemon service
|
|
52
|
+
|
|
53
|
+
If your changes substantially alter memory ownership, permission behavior,
|
|
54
|
+
privacy boundaries, or agent identity behavior, make that especially clear to
|
|
55
|
+
users.
|
|
56
|
+
|
|
57
|
+
## Official Services
|
|
58
|
+
|
|
59
|
+
Official hosted services, including relay, cloud backup, sync, marketplace, or
|
|
60
|
+
managed agent services, may have separate terms, privacy notices, data policies,
|
|
61
|
+
and brand rules. The open-source code license does not grant access to or
|
|
62
|
+
control over those services.
|
|
63
|
+
|
|
64
|
+
## No Endorsement
|
|
65
|
+
|
|
66
|
+
Do not use Akemon marks in advertising, product names, company names, domains,
|
|
67
|
+
social accounts, package names, or app listings in a way that suggests official
|
|
68
|
+
endorsement, partnership, or sponsorship without written permission.
|
|
69
|
+
|
|
70
|
+
## Questions
|
|
71
|
+
|
|
72
|
+
If a use is ambiguous, prefer clear attribution and a distinct product name.
|
|
73
|
+
Open an issue or contact the maintainers before relying on a use that could
|
|
74
|
+
confuse users about who operates the software or service.
|
package/dist/cli.js
CHANGED
|
@@ -8,6 +8,8 @@ import { listAgents } from "./list.js";
|
|
|
8
8
|
import { connect } from "./connect.js";
|
|
9
9
|
import { PrivacyFilterUnavailableError, sanitizeText, } from "./privacy-filter.js";
|
|
10
10
|
import { SoftwareAgentStreamCliRenderer } from "./software-agent-stream-cli.js";
|
|
11
|
+
import { appendWorkMemoryNote, buildWorkMemoryContext, } from "./work-memory.js";
|
|
12
|
+
import { renderSoftwareAgentRunResult } from "./software-agent-result-cli.js";
|
|
11
13
|
import { readFileSync } from "fs";
|
|
12
14
|
import { fileURLToPath } from "url";
|
|
13
15
|
import { dirname, join } from "path";
|
|
@@ -76,10 +78,36 @@ function printSoftwareAgentTaskList(tasks) {
|
|
|
76
78
|
: "no-git";
|
|
77
79
|
const goal = truncateOneLine(task.envelope?.goal || "", 90);
|
|
78
80
|
console.log(`${task.taskId} ${task.status}/${result} ${duration} ${git} ${task.updatedAt || task.startedAt}`);
|
|
81
|
+
if (task.contextSession?.sessionId)
|
|
82
|
+
console.log(` session: ${task.contextSession.sessionId}`);
|
|
83
|
+
const workMemoryDir = task.envelope?.workMemoryDir || task.result?.workMemoryDir;
|
|
84
|
+
if (workMemoryDir)
|
|
85
|
+
console.log(` work memory: ${workMemoryDir}`);
|
|
79
86
|
if (goal)
|
|
80
87
|
console.log(` ${goal}`);
|
|
81
88
|
}
|
|
82
89
|
}
|
|
90
|
+
function printSoftwareAgentSessionList(sessions) {
|
|
91
|
+
if (!sessions.length) {
|
|
92
|
+
console.log("No software-agent context sessions found.");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
for (const session of sessions) {
|
|
96
|
+
const result = session.lastResult?.success === true ? "ok" : session.lastResult?.success === false ? "error" : "pending";
|
|
97
|
+
const duration = typeof session.lastResult?.durationMs === "number" ? `${session.lastResult.durationMs}ms` : "-";
|
|
98
|
+
const updatedAt = session.updatedAt || "-";
|
|
99
|
+
const goal = truncateOneLine(session.lastGoal || "", 90);
|
|
100
|
+
console.log(`${session.sessionId} ${result} ${duration} ${updatedAt}`);
|
|
101
|
+
if (session.lastTaskId)
|
|
102
|
+
console.log(` last task: ${session.lastTaskId}`);
|
|
103
|
+
if (goal)
|
|
104
|
+
console.log(` ${goal}`);
|
|
105
|
+
if (session.packetPath)
|
|
106
|
+
console.log(` context: ${session.packetPath}`);
|
|
107
|
+
if (session.workMemoryDir)
|
|
108
|
+
console.log(` work memory: ${session.workMemoryDir}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
83
111
|
function truncateOneLine(value, max) {
|
|
84
112
|
const oneLine = value.replace(/\s+/g, " ").trim();
|
|
85
113
|
if (oneLine.length <= max)
|
|
@@ -176,9 +204,64 @@ async function streamLocalOwnerEndpoint(path, opts, body) {
|
|
|
176
204
|
if (failed)
|
|
177
205
|
process.exit(1);
|
|
178
206
|
}
|
|
207
|
+
async function runSoftwareAgentCli(goalParts, opts, forcedSessionId) {
|
|
208
|
+
const body = {
|
|
209
|
+
goal: goalParts.join(" "),
|
|
210
|
+
roleScope: opts.roleScope,
|
|
211
|
+
memoryScope: opts.memoryScope,
|
|
212
|
+
riskLevel: opts.risk,
|
|
213
|
+
};
|
|
214
|
+
if (opts.workdir)
|
|
215
|
+
body.workdir = opts.workdir;
|
|
216
|
+
if (opts.allowOutsideWorkdir)
|
|
217
|
+
body.allowOutsideWorkdir = true;
|
|
218
|
+
if (opts.memorySummary)
|
|
219
|
+
body.memorySummary = opts.memorySummary;
|
|
220
|
+
const workContextBudget = parsePositiveIntCliOption(opts.workContextBudget, "--work-context-budget");
|
|
221
|
+
if (opts.workContext || workContextBudget !== undefined)
|
|
222
|
+
body.includeWorkMemoryContext = true;
|
|
223
|
+
if (workContextBudget !== undefined)
|
|
224
|
+
body.workMemoryContextBudget = workContextBudget;
|
|
225
|
+
const sessionId = forcedSessionId || opts.session;
|
|
226
|
+
if (sessionId)
|
|
227
|
+
body.contextSessionId = sessionId;
|
|
228
|
+
if (opts.deliverable)
|
|
229
|
+
body.deliverable = opts.deliverable;
|
|
230
|
+
if (opts.timeoutMs) {
|
|
231
|
+
const timeoutMs = Number(opts.timeoutMs);
|
|
232
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
|
|
233
|
+
console.error("--timeout-ms must be a positive integer");
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
body.timeoutMs = timeoutMs;
|
|
237
|
+
}
|
|
238
|
+
if (opts.stream !== false) {
|
|
239
|
+
await streamLocalOwnerEndpoint("/self/software-agent/run-stream", opts, body);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const res = await fetchLocalOwnerEndpoint("/self/software-agent/run", opts, {
|
|
243
|
+
method: "POST",
|
|
244
|
+
body: JSON.stringify(body),
|
|
245
|
+
});
|
|
246
|
+
const text = await res.text();
|
|
247
|
+
let data;
|
|
248
|
+
try {
|
|
249
|
+
data = text ? JSON.parse(text) : {};
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
data = { output: text };
|
|
253
|
+
}
|
|
254
|
+
if (!res.ok) {
|
|
255
|
+
console.error(data.error || text || `Request failed with HTTP ${res.status}`);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
const failed = renderSoftwareAgentRunResult(data);
|
|
259
|
+
if (failed)
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
179
262
|
program
|
|
180
263
|
.name("akemon")
|
|
181
|
-
.description("
|
|
264
|
+
.description("Local AI companion runtime with memory, modules, relay sync, and software-agent control")
|
|
182
265
|
.version(pkg.version);
|
|
183
266
|
program
|
|
184
267
|
.command("serve")
|
|
@@ -309,47 +392,34 @@ program
|
|
|
309
392
|
.option("--memory-scope <scope>", "Memory scope: none|public|task|owner", "owner")
|
|
310
393
|
.option("--risk <level>", "Risk level: low|medium|high", "medium")
|
|
311
394
|
.option("--memory-summary <text>", "Pre-filtered memory/context text to include")
|
|
395
|
+
.option("--work-context", "Embed a bounded work-memory context packet in the task envelope")
|
|
396
|
+
.option("--work-context-budget <chars>", "Maximum embedded work-memory context size; also enables --work-context")
|
|
312
397
|
.option("--session <id>", "Akemon-side context session id for explicit software-agent continuity")
|
|
313
398
|
.option("--deliverable <text>", "Expected output shape")
|
|
314
399
|
.option("--timeout-ms <ms>", "Task timeout in milliseconds")
|
|
315
400
|
.option("--no-stream", "Disable local streaming and wait for the final response")
|
|
316
401
|
.action(async (goalParts, opts) => {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
339
|
-
body.timeoutMs = timeoutMs;
|
|
340
|
-
}
|
|
341
|
-
if (opts.stream !== false) {
|
|
342
|
-
await streamLocalOwnerEndpoint("/self/software-agent/run-stream", opts, body);
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
const data = await callLocalOwnerEndpoint("/self/software-agent/run", opts, {
|
|
346
|
-
method: "POST",
|
|
347
|
-
body: JSON.stringify(body),
|
|
348
|
-
});
|
|
349
|
-
if (data.output)
|
|
350
|
-
console.log(data.output);
|
|
351
|
-
else
|
|
352
|
-
console.log(JSON.stringify(data, null, 2));
|
|
402
|
+
await runSoftwareAgentCli(goalParts, opts);
|
|
403
|
+
});
|
|
404
|
+
program
|
|
405
|
+
.command("software-agent-continue")
|
|
406
|
+
.description("Continue an Akemon-side software-agent context session")
|
|
407
|
+
.argument("<sessionId>", "Akemon-side context session id to continue")
|
|
408
|
+
.argument("<goal...>", "Task goal to send to the software agent")
|
|
409
|
+
.option("-p, --port <port>", "Local akemon serve port", "3000")
|
|
410
|
+
.option("-w, --workdir <path>", "Workdir for the software agent (default: serve workdir)")
|
|
411
|
+
.option("--allow-outside-workdir", "Allow the software agent workdir to be outside the serve workdir")
|
|
412
|
+
.option("--role-scope <scope>", "Role scope: owner|public|order|agent|system", "owner")
|
|
413
|
+
.option("--memory-scope <scope>", "Memory scope: none|public|task|owner", "owner")
|
|
414
|
+
.option("--risk <level>", "Risk level: low|medium|high", "medium")
|
|
415
|
+
.option("--memory-summary <text>", "Pre-filtered memory/context text to include")
|
|
416
|
+
.option("--work-context", "Embed a bounded work-memory context packet in the task envelope")
|
|
417
|
+
.option("--work-context-budget <chars>", "Maximum embedded work-memory context size; also enables --work-context")
|
|
418
|
+
.option("--deliverable <text>", "Expected output shape")
|
|
419
|
+
.option("--timeout-ms <ms>", "Task timeout in milliseconds")
|
|
420
|
+
.option("--no-stream", "Disable local streaming and wait for the final response")
|
|
421
|
+
.action(async (sessionId, goalParts, opts) => {
|
|
422
|
+
await runSoftwareAgentCli(goalParts, opts, sessionId);
|
|
353
423
|
});
|
|
354
424
|
program
|
|
355
425
|
.command("software-agent-status")
|
|
@@ -367,20 +437,78 @@ program
|
|
|
367
437
|
.argument("[taskId]", "Task id to inspect")
|
|
368
438
|
.option("-p, --port <port>", "Local akemon serve port", "3000")
|
|
369
439
|
.option("-l, --limit <n>", "Maximum recent tasks to list", "20")
|
|
440
|
+
.option("--session <id>", "Filter listed tasks by Akemon-side context session id")
|
|
441
|
+
.option("--context", "Print the task's Akemon TASK_CONTEXT.md content when inspecting one task")
|
|
370
442
|
.option("--json", "Print raw JSON")
|
|
371
443
|
.action(async (taskId, opts) => {
|
|
444
|
+
if (!taskId && opts.context) {
|
|
445
|
+
console.error("--context requires a taskId");
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
if (taskId && opts.session) {
|
|
449
|
+
console.error("--session cannot be used when inspecting a single taskId");
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
372
452
|
const path = taskId
|
|
373
|
-
? `/self/software-agent/tasks/${encodeURIComponent(taskId)}`
|
|
374
|
-
: `/self/software-agent/tasks?limit=${clampPositiveInt(opts.limit, 20, 100)}`;
|
|
453
|
+
? `/self/software-agent/tasks/${encodeURIComponent(taskId)}${opts.context ? "?includeContext=1" : ""}`
|
|
454
|
+
: `/self/software-agent/tasks?limit=${clampPositiveInt(opts.limit, 20, 100)}${opts.session ? `&session=${encodeURIComponent(opts.session)}` : ""}`;
|
|
375
455
|
const data = await callLocalOwnerEndpoint(path, opts, {
|
|
376
456
|
method: "GET",
|
|
377
457
|
});
|
|
458
|
+
if (taskId && opts.context) {
|
|
459
|
+
const contextPacket = data.contextSession?.contextPacket;
|
|
460
|
+
if (typeof contextPacket === "string" && contextPacket.length > 0) {
|
|
461
|
+
process.stdout.write(contextPacket);
|
|
462
|
+
if (!contextPacket.endsWith("\n"))
|
|
463
|
+
process.stdout.write("\n");
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
console.error("No TASK_CONTEXT.md content found for this task.");
|
|
467
|
+
process.exit(1);
|
|
468
|
+
}
|
|
378
469
|
if (opts.json || taskId) {
|
|
379
470
|
console.log(JSON.stringify(taskId ? data.task : data, null, 2));
|
|
380
471
|
return;
|
|
381
472
|
}
|
|
382
473
|
printSoftwareAgentTaskList(Array.isArray(data.tasks) ? data.tasks : []);
|
|
383
474
|
});
|
|
475
|
+
program
|
|
476
|
+
.command("software-agent-sessions")
|
|
477
|
+
.description("List or inspect owner-only Akemon-side software-agent context sessions")
|
|
478
|
+
.argument("[sessionId]", "Context session id to inspect")
|
|
479
|
+
.option("-p, --port <port>", "Local akemon serve port", "3000")
|
|
480
|
+
.option("-l, --limit <n>", "Maximum recent sessions to list", "20")
|
|
481
|
+
.option("--context", "Print the session TASK_CONTEXT.md content")
|
|
482
|
+
.option("--json", "Print raw JSON")
|
|
483
|
+
.action(async (sessionId, opts) => {
|
|
484
|
+
const query = sessionId && opts.context ? "?includeContext=1" : "";
|
|
485
|
+
const path = sessionId
|
|
486
|
+
? `/self/software-agent/sessions/${encodeURIComponent(sessionId)}${query}`
|
|
487
|
+
: `/self/software-agent/sessions?limit=${clampPositiveInt(opts.limit, 20, 100)}`;
|
|
488
|
+
const data = await callLocalOwnerEndpoint(path, opts, {
|
|
489
|
+
method: "GET",
|
|
490
|
+
});
|
|
491
|
+
if (sessionId) {
|
|
492
|
+
if (opts.context) {
|
|
493
|
+
const contextPacket = data.session?.contextPacket;
|
|
494
|
+
if (typeof contextPacket === "string" && contextPacket.length > 0) {
|
|
495
|
+
process.stdout.write(contextPacket);
|
|
496
|
+
if (!contextPacket.endsWith("\n"))
|
|
497
|
+
process.stdout.write("\n");
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
console.error("No TASK_CONTEXT.md content found for this session.");
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
console.log(JSON.stringify(data.session, null, 2));
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (opts.json) {
|
|
507
|
+
console.log(JSON.stringify(data, null, 2));
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
printSoftwareAgentSessionList(Array.isArray(data.sessions) ? data.sessions : []);
|
|
511
|
+
});
|
|
384
512
|
program
|
|
385
513
|
.command("software-agent-reset")
|
|
386
514
|
.description("Reset the owner-only local software-agent peripheral session")
|
|
@@ -431,6 +559,69 @@ program
|
|
|
431
559
|
throw error;
|
|
432
560
|
}
|
|
433
561
|
});
|
|
562
|
+
program
|
|
563
|
+
.command("work-context")
|
|
564
|
+
.description("Print a work-memory context packet for external software agents")
|
|
565
|
+
.option("-w, --workdir <path>", "Akemon workdir (default: cwd)")
|
|
566
|
+
.option("-n, --name <name>", "Agent name", "my-agent")
|
|
567
|
+
.option("--purpose <text>", "Purpose of this context packet", "external software-agent work context")
|
|
568
|
+
.option("--budget <chars>", "Maximum packet size in characters", "12000")
|
|
569
|
+
.option("--json", "Print raw JSON")
|
|
570
|
+
.action(async (opts) => {
|
|
571
|
+
try {
|
|
572
|
+
const packet = await buildWorkMemoryContext({
|
|
573
|
+
workdir: opts.workdir || process.cwd(),
|
|
574
|
+
agentName: opts.name,
|
|
575
|
+
purpose: opts.purpose,
|
|
576
|
+
budget: parsePositiveIntCliOption(opts.budget, "--budget"),
|
|
577
|
+
});
|
|
578
|
+
if (opts.json) {
|
|
579
|
+
console.log(JSON.stringify(packet, null, 2));
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
process.stdout.write(packet.text);
|
|
583
|
+
if (!packet.text.endsWith("\n"))
|
|
584
|
+
process.stdout.write("\n");
|
|
585
|
+
}
|
|
586
|
+
catch (error) {
|
|
587
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
588
|
+
process.exit(1);
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
program
|
|
592
|
+
.command("work-note")
|
|
593
|
+
.description("Append a note to Akemon work memory")
|
|
594
|
+
.argument("<text...>", "Durable work-memory note")
|
|
595
|
+
.option("-w, --workdir <path>", "Akemon workdir (default: cwd)")
|
|
596
|
+
.option("-n, --name <name>", "Agent name", "my-agent")
|
|
597
|
+
.option("--source <source>", "Note source, e.g. user, codex, or claude-code", "user")
|
|
598
|
+
.option("--session <id>", "External or Akemon-side session id")
|
|
599
|
+
.option("--kind <kind>", "Work-memory kind, e.g. note, decision, command, project", "note")
|
|
600
|
+
.option("--target <path>", "Optional target file under the work memory directory")
|
|
601
|
+
.option("--json", "Print raw JSON")
|
|
602
|
+
.action(async (textParts, opts) => {
|
|
603
|
+
try {
|
|
604
|
+
const result = await appendWorkMemoryNote({
|
|
605
|
+
workdir: opts.workdir || process.cwd(),
|
|
606
|
+
agentName: opts.name,
|
|
607
|
+
text: textParts.join(" "),
|
|
608
|
+
source: opts.source,
|
|
609
|
+
sessionId: opts.session,
|
|
610
|
+
kind: opts.kind,
|
|
611
|
+
target: opts.target,
|
|
612
|
+
});
|
|
613
|
+
if (opts.json) {
|
|
614
|
+
console.log(JSON.stringify(result, null, 2));
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
console.log(`Work memory note appended: ${result.note.id}`);
|
|
618
|
+
console.log(`Path: ${result.path}`);
|
|
619
|
+
}
|
|
620
|
+
catch (error) {
|
|
621
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
622
|
+
process.exit(1);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
434
625
|
program
|
|
435
626
|
.command("dashboard")
|
|
436
627
|
.description("Open your agent dashboard in the browser")
|