akemon 0.3.5 → 0.3.7
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 +128 -0
- package/README.md +156 -19
- package/TRADEMARK.md +74 -0
- package/dist/akemon-home.js +56 -0
- package/dist/akemon-message.js +107 -0
- package/dist/best-effort.js +8 -0
- package/dist/cli.js +1411 -132
- package/dist/cognitive-artifact-store.js +101 -0
- package/dist/cognitive-event-log.js +47 -0
- package/dist/config.js +45 -9
- package/dist/context.js +27 -6
- package/dist/core/contracts/layers.js +1 -0
- package/dist/core/contracts/permission.js +1 -0
- package/dist/core/contracts/workspace.js +1 -0
- package/dist/core-cognitive-module.js +768 -0
- package/dist/engine-peripheral.js +127 -26
- package/dist/engine-routing.js +58 -17
- package/dist/interactive-session.js +361 -0
- package/dist/local-interconnect.js +156 -0
- package/dist/local-registry.js +178 -0
- package/dist/mcp-server.js +4 -1
- package/dist/memory-proposal.js +379 -0
- package/dist/memory-recorder.js +368 -0
- package/dist/orphan-scan.js +36 -24
- package/dist/passive-reflection-cognitive-module.js +172 -0
- package/dist/peripheral-registry.js +235 -0
- package/dist/permission-audit.js +132 -0
- package/dist/relay-client.js +68 -9
- package/dist/relay-mode.js +34 -0
- package/dist/relay-peripheral.js +139 -49
- package/dist/runtime-platform.js +122 -0
- package/dist/secretariat/client.js +87 -0
- package/dist/self.js +15 -6
- package/dist/server.js +3695 -439
- package/dist/social-discovery.js +231 -0
- package/dist/software-agent-peripheral.js +314 -235
- package/dist/software-agent-result-cli.js +69 -0
- package/dist/software-agent-stream-cli.js +23 -0
- package/dist/software-agent-transport.js +177 -0
- package/dist/task-module.js +243 -0
- package/dist/task-registry.js +756 -0
- package/dist/vendor/xterm/addon-fit.js +2 -0
- package/dist/vendor/xterm/addon-search.js +2 -0
- package/dist/vendor/xterm/addon-web-links.js +2 -0
- package/dist/vendor/xterm/xterm.css +285 -0
- package/dist/vendor/xterm/xterm.js +2 -0
- package/dist/work-memory.js +339 -0
- package/dist/workbench-peripheral-guide.js +79 -0
- package/dist/workbench-session.js +1074 -0
- package/dist/workbench.html +4011 -0
- package/package.json +11 -4
- package/scripts/build.cjs +24 -0
- package/scripts/check-architecture-baseline.cjs +68 -0
- package/scripts/test.cjs +38 -0
package/dist/relay-peripheral.js
CHANGED
|
@@ -8,9 +8,53 @@
|
|
|
8
8
|
* Migration strategy: server.ts can import and use this directly — no need for
|
|
9
9
|
* the full Core/EventBus wiring yet. That comes later.
|
|
10
10
|
*/
|
|
11
|
+
import { createHash } from "crypto";
|
|
11
12
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
12
13
|
import { join } from "path";
|
|
13
|
-
import {
|
|
14
|
+
import { agentRelayImportsDir } from "./akemon-home.js";
|
|
15
|
+
import { actorRef } from "./akemon-message.js";
|
|
16
|
+
import { appendPermissionAuditRecord } from "./permission-audit.js";
|
|
17
|
+
import { logBestEffortError } from "./best-effort.js";
|
|
18
|
+
import { selfDir, loadLatestIdentity, loadRecentCanvasEntries, loadGameList, loadGame, loadNotesList, loadNote, loadPageList, loadPage, loadDirectives, directivesSummary, loadBioState, } from "./self.js";
|
|
19
|
+
function shortHash(value) {
|
|
20
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 8);
|
|
21
|
+
}
|
|
22
|
+
function safeRelayArtifactSlug(slug) {
|
|
23
|
+
const raw = String(slug || "untitled").trim() || "untitled";
|
|
24
|
+
const base = raw
|
|
25
|
+
.replace(/[^A-Za-z0-9._-]+/g, "_")
|
|
26
|
+
.replace(/^\.+/, "")
|
|
27
|
+
.replace(/[. ]+$/g, "")
|
|
28
|
+
.slice(0, 100) || "untitled";
|
|
29
|
+
const portableBase = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i.test(base) ? `_${base}` : base;
|
|
30
|
+
return portableBase === raw && raw.length <= 100 ? portableBase : `${portableBase}-${shortHash(raw)}`;
|
|
31
|
+
}
|
|
32
|
+
async function stageRelayArtifactImport(input) {
|
|
33
|
+
const dir = join(agentRelayImportsDir(input.agentName), input.kind);
|
|
34
|
+
await mkdir(dir, { recursive: true });
|
|
35
|
+
const filename = `${safeRelayArtifactSlug(input.slug)}.${input.extension}`;
|
|
36
|
+
const artifactPath = join(dir, filename);
|
|
37
|
+
try {
|
|
38
|
+
await readFile(artifactPath, "utf-8");
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
catch { }
|
|
42
|
+
await writeFile(artifactPath, input.content, "utf-8");
|
|
43
|
+
await writeFile(`${artifactPath}.relay-import.json`, JSON.stringify({
|
|
44
|
+
schemaVersion: 1,
|
|
45
|
+
source: "relay",
|
|
46
|
+
authority: "remote-projection",
|
|
47
|
+
canonicalSelfMemory: false,
|
|
48
|
+
importedInto: "inbox",
|
|
49
|
+
relayAgent: input.agentName,
|
|
50
|
+
kind: input.kind,
|
|
51
|
+
originalSlug: input.slug,
|
|
52
|
+
localFile: filename,
|
|
53
|
+
sourceUrl: input.sourceUrl,
|
|
54
|
+
importedAt: new Date().toISOString(),
|
|
55
|
+
}, null, 2) + "\n", "utf-8");
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
14
58
|
export class RelayPeripheral {
|
|
15
59
|
id = "relay";
|
|
16
60
|
name = "Akemon Relay";
|
|
@@ -266,7 +310,9 @@ export class RelayPeripheral {
|
|
|
266
310
|
signal: AbortSignal.timeout(10_000),
|
|
267
311
|
});
|
|
268
312
|
}
|
|
269
|
-
catch {
|
|
313
|
+
catch (error) {
|
|
314
|
+
logBestEffortError("relay session context set", error);
|
|
315
|
+
}
|
|
270
316
|
}
|
|
271
317
|
// ---------------------------------------------------------------------------
|
|
272
318
|
// 10. Explore — plain-text environment briefing for Modules
|
|
@@ -406,6 +452,9 @@ export class RelayPeripheral {
|
|
|
406
452
|
personality: bio.personality,
|
|
407
453
|
},
|
|
408
454
|
});
|
|
455
|
+
let syncedGames = 0;
|
|
456
|
+
let syncedNotes = 0;
|
|
457
|
+
let syncedPages = 0;
|
|
409
458
|
// Sync games
|
|
410
459
|
try {
|
|
411
460
|
const localGames = await loadGameList(workdir, agentName);
|
|
@@ -413,10 +462,13 @@ export class RelayPeripheral {
|
|
|
413
462
|
const html = await loadGame(workdir, agentName, g.slug);
|
|
414
463
|
if (html && html.includes("<!DOCTYPE html>")) {
|
|
415
464
|
this.syncGame(g.slug, g.title, g.description, html);
|
|
465
|
+
syncedGames++;
|
|
416
466
|
}
|
|
417
467
|
}
|
|
418
468
|
}
|
|
419
|
-
catch {
|
|
469
|
+
catch (error) {
|
|
470
|
+
logBestEffortError("relay sync games", error);
|
|
471
|
+
}
|
|
420
472
|
// Sync notes
|
|
421
473
|
try {
|
|
422
474
|
const localNotes = await loadNotesList(workdir, agentName);
|
|
@@ -424,10 +476,13 @@ export class RelayPeripheral {
|
|
|
424
476
|
const content = await loadNote(workdir, agentName, n.slug);
|
|
425
477
|
if (content) {
|
|
426
478
|
this.syncNote(n.slug, n.title, content);
|
|
479
|
+
syncedNotes++;
|
|
427
480
|
}
|
|
428
481
|
}
|
|
429
482
|
}
|
|
430
|
-
catch {
|
|
483
|
+
catch (error) {
|
|
484
|
+
logBestEffortError("relay sync notes", error);
|
|
485
|
+
}
|
|
431
486
|
// Sync pages
|
|
432
487
|
try {
|
|
433
488
|
const localPages = await loadPageList(workdir, agentName);
|
|
@@ -435,82 +490,117 @@ export class RelayPeripheral {
|
|
|
435
490
|
const html = await loadPage(workdir, agentName, p.slug);
|
|
436
491
|
if (html && html.includes("<!DOCTYPE html>")) {
|
|
437
492
|
this.syncPage(p.slug, p.title, p.description, html);
|
|
493
|
+
syncedPages++;
|
|
438
494
|
}
|
|
439
495
|
}
|
|
440
496
|
}
|
|
441
|
-
catch {
|
|
497
|
+
catch (error) {
|
|
498
|
+
logBestEffortError("relay sync pages", error);
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
await appendPermissionAuditRecord(agentName, {
|
|
502
|
+
actionKind: "relay-publication",
|
|
503
|
+
action: "relay.sync-to-relay",
|
|
504
|
+
requestedBy: actorRef("system", "relay-sync", "local"),
|
|
505
|
+
performedBy: actorRef("agent", agentName, "relay"),
|
|
506
|
+
target: actorRef("relay", this.baseUrl, "relay"),
|
|
507
|
+
riskLevel: "low",
|
|
508
|
+
memoryScope: "public",
|
|
509
|
+
workdir,
|
|
510
|
+
projectScope: "global",
|
|
511
|
+
transport: "relay",
|
|
512
|
+
decision: {
|
|
513
|
+
result: "allowed",
|
|
514
|
+
mode: "automatic",
|
|
515
|
+
reason: "Relay peripheral published local public projections to relay.",
|
|
516
|
+
},
|
|
517
|
+
metadata: {
|
|
518
|
+
fields: ["self_intro", "canvas", "mood", "profile_html", "directives_summary", "bio_state"],
|
|
519
|
+
broadcast: !!broadcast,
|
|
520
|
+
syncedGames,
|
|
521
|
+
syncedNotes,
|
|
522
|
+
syncedPages,
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
catch (error) {
|
|
527
|
+
logBestEffortError("relay sync audit append", error);
|
|
528
|
+
}
|
|
442
529
|
}
|
|
443
|
-
/**
|
|
444
|
-
|
|
530
|
+
/**
|
|
531
|
+
* Pull games/notes/pages from relay into the local inbox.
|
|
532
|
+
* Relay artifacts are external projections, not canonical self memory.
|
|
533
|
+
*/
|
|
534
|
+
async pullFromRelay(_workdir, agentName) {
|
|
445
535
|
const baseUrl = `${this.config.httpUrl}/v1/agent/${encodeURIComponent(agentName)}`;
|
|
446
|
-
let
|
|
447
|
-
//
|
|
536
|
+
let staged = 0;
|
|
537
|
+
// Stage games
|
|
448
538
|
try {
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
const res = await fetch(`${baseUrl}/games`);
|
|
539
|
+
const listUrl = `${baseUrl}/games`;
|
|
540
|
+
const res = await fetch(listUrl);
|
|
452
541
|
if (res.ok) {
|
|
453
542
|
const games = await res.json();
|
|
454
543
|
for (const g of games) {
|
|
455
|
-
if (!g.html)
|
|
544
|
+
if (!g.slug || !g.html)
|
|
456
545
|
continue;
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
546
|
+
if (await stageRelayArtifactImport({
|
|
547
|
+
agentName,
|
|
548
|
+
kind: "games",
|
|
549
|
+
slug: g.slug,
|
|
550
|
+
extension: "html",
|
|
551
|
+
content: g.html,
|
|
552
|
+
sourceUrl: `${baseUrl}/games/${encodeURIComponent(g.slug)}`,
|
|
553
|
+
}))
|
|
554
|
+
staged++;
|
|
465
555
|
}
|
|
466
556
|
}
|
|
467
557
|
}
|
|
468
558
|
catch { }
|
|
469
|
-
//
|
|
559
|
+
// Stage notes
|
|
470
560
|
try {
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
const res = await fetch(`${baseUrl}/notes`);
|
|
561
|
+
const listUrl = `${baseUrl}/notes`;
|
|
562
|
+
const res = await fetch(listUrl);
|
|
474
563
|
if (res.ok) {
|
|
475
564
|
const notes = await res.json();
|
|
476
565
|
for (const n of notes) {
|
|
477
|
-
if (!n.content)
|
|
566
|
+
if (!n.slug || !n.content)
|
|
478
567
|
continue;
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
}
|
|
568
|
+
if (await stageRelayArtifactImport({
|
|
569
|
+
agentName,
|
|
570
|
+
kind: "notes",
|
|
571
|
+
slug: n.slug,
|
|
572
|
+
extension: "md",
|
|
573
|
+
content: n.content,
|
|
574
|
+
sourceUrl: `${baseUrl}/notes/${encodeURIComponent(n.slug)}`,
|
|
575
|
+
}))
|
|
576
|
+
staged++;
|
|
487
577
|
}
|
|
488
578
|
}
|
|
489
579
|
}
|
|
490
580
|
catch { }
|
|
491
|
-
//
|
|
581
|
+
// Stage pages
|
|
492
582
|
try {
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
const res = await fetch(`${baseUrl}/pages`);
|
|
583
|
+
const listUrl = `${baseUrl}/pages`;
|
|
584
|
+
const res = await fetch(listUrl);
|
|
496
585
|
if (res.ok) {
|
|
497
586
|
const pages = await res.json();
|
|
498
587
|
for (const p of pages) {
|
|
499
|
-
if (!p.html)
|
|
588
|
+
if (!p.slug || !p.html)
|
|
500
589
|
continue;
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
}
|
|
590
|
+
if (await stageRelayArtifactImport({
|
|
591
|
+
agentName,
|
|
592
|
+
kind: "pages",
|
|
593
|
+
slug: p.slug,
|
|
594
|
+
extension: "html",
|
|
595
|
+
content: p.html,
|
|
596
|
+
sourceUrl: `${baseUrl}/pages/${encodeURIComponent(p.slug)}`,
|
|
597
|
+
}))
|
|
598
|
+
staged++;
|
|
509
599
|
}
|
|
510
600
|
}
|
|
511
601
|
}
|
|
512
602
|
catch { }
|
|
513
|
-
if (
|
|
514
|
-
console.log(`[sync]
|
|
603
|
+
if (staged > 0)
|
|
604
|
+
console.log(`[sync] Staged ${staged} relay items in inbox/relay-imports`);
|
|
515
605
|
}
|
|
516
606
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { tmpdir } from "os";
|
|
3
|
+
export function getRuntimePlatform(platform = process.platform) {
|
|
4
|
+
return {
|
|
5
|
+
platform,
|
|
6
|
+
tempDir: tmpdir(),
|
|
7
|
+
defaultShell: defaultShellForPlatform(platform),
|
|
8
|
+
capabilities: runtimeCapabilities(platform),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function runtimeCapabilities(platform = process.platform) {
|
|
12
|
+
const isPosixDesktop = platform === "darwin" || platform === "linux";
|
|
13
|
+
return {
|
|
14
|
+
canSpawnProcess: true,
|
|
15
|
+
canOpenBrowser: platform === "darwin" || platform === "linux" || platform === "win32",
|
|
16
|
+
canStartPty: isPosixDesktop,
|
|
17
|
+
canKillProcessTree: isPosixDesktop || platform === "win32",
|
|
18
|
+
canScanOrphanProcesses: isPosixDesktop,
|
|
19
|
+
supportsProcessGroups: isPosixDesktop,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function defaultShellForPlatform(platform = process.platform) {
|
|
23
|
+
if (platform === "win32")
|
|
24
|
+
return process.env.ComSpec || process.env.COMSPEC || "cmd.exe";
|
|
25
|
+
return process.env.SHELL || "/bin/sh";
|
|
26
|
+
}
|
|
27
|
+
export async function openUrl(url, platform = process.platform) {
|
|
28
|
+
const command = openUrlCommand(url, platform);
|
|
29
|
+
if (!command) {
|
|
30
|
+
throw new Error(`Opening browser is not supported on platform: ${platform}`);
|
|
31
|
+
}
|
|
32
|
+
await new Promise((resolve, reject) => {
|
|
33
|
+
const child = spawn(command.command, command.args, {
|
|
34
|
+
stdio: "ignore",
|
|
35
|
+
detached: true,
|
|
36
|
+
windowsHide: true,
|
|
37
|
+
});
|
|
38
|
+
child.once("error", reject);
|
|
39
|
+
child.once("spawn", () => {
|
|
40
|
+
child.unref();
|
|
41
|
+
resolve();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
export function openUrlCommand(url, platform = process.platform) {
|
|
46
|
+
if (platform === "darwin")
|
|
47
|
+
return { command: "open", args: [url] };
|
|
48
|
+
if (platform === "linux")
|
|
49
|
+
return { command: "xdg-open", args: [url] };
|
|
50
|
+
if (platform === "win32")
|
|
51
|
+
return { command: "cmd", args: ["/c", "start", "", url] };
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
export function shouldDetachChildProcess(platform = process.platform) {
|
|
55
|
+
return runtimeCapabilities(platform).supportsProcessGroups;
|
|
56
|
+
}
|
|
57
|
+
export function terminateProcessTree(pid, options = {}, platform = process.platform) {
|
|
58
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
59
|
+
return;
|
|
60
|
+
const signal = options.signal || "SIGTERM";
|
|
61
|
+
if (platform === "win32") {
|
|
62
|
+
runTaskkill(pid, signal === "SIGKILL");
|
|
63
|
+
}
|
|
64
|
+
else if (runtimeCapabilities(platform).supportsProcessGroups) {
|
|
65
|
+
try {
|
|
66
|
+
process.kill(-pid, signal);
|
|
67
|
+
}
|
|
68
|
+
catch { }
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
try {
|
|
72
|
+
process.kill(pid, signal);
|
|
73
|
+
}
|
|
74
|
+
catch { }
|
|
75
|
+
}
|
|
76
|
+
if (options.forceAfterMs !== undefined && signal !== "SIGKILL") {
|
|
77
|
+
const timer = setTimeout(() => {
|
|
78
|
+
terminateProcessTree(pid, { signal: "SIGKILL" }, platform);
|
|
79
|
+
}, options.forceAfterMs);
|
|
80
|
+
timer.unref?.();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export function isProcessAlive(pid) {
|
|
84
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
85
|
+
return false;
|
|
86
|
+
try {
|
|
87
|
+
process.kill(pid, 0);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return error.code === "EPERM";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export function assertPortablePathSegment(value, label = "path segment") {
|
|
95
|
+
const cleaned = value.trim();
|
|
96
|
+
if (!cleaned)
|
|
97
|
+
throw new Error(`Invalid ${label}: must not be empty`);
|
|
98
|
+
if (/[/\\]/.test(cleaned))
|
|
99
|
+
throw new Error(`Invalid ${label}: must not contain path separators`);
|
|
100
|
+
if (/[<>:"|?*\x00-\x1f\x7f]/.test(cleaned)) {
|
|
101
|
+
throw new Error(`Invalid ${label}: contains characters that are not portable across filesystems`);
|
|
102
|
+
}
|
|
103
|
+
if (/[. ]$/.test(cleaned)) {
|
|
104
|
+
throw new Error(`Invalid ${label}: must not end with a dot or space`);
|
|
105
|
+
}
|
|
106
|
+
const upper = cleaned.toUpperCase();
|
|
107
|
+
if (/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\..*)?$/.test(upper)) {
|
|
108
|
+
throw new Error(`Invalid ${label}: reserved Windows device name`);
|
|
109
|
+
}
|
|
110
|
+
return cleaned;
|
|
111
|
+
}
|
|
112
|
+
function runTaskkill(pid, force) {
|
|
113
|
+
const args = ["/PID", String(pid), "/T"];
|
|
114
|
+
if (force)
|
|
115
|
+
args.push("/F");
|
|
116
|
+
const child = spawn("taskkill", args, {
|
|
117
|
+
stdio: "ignore",
|
|
118
|
+
windowsHide: true,
|
|
119
|
+
});
|
|
120
|
+
child.on("error", () => { });
|
|
121
|
+
child.unref();
|
|
122
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { actorRef, createAkemonMessage } from "../akemon-message.js";
|
|
2
|
+
export class SecretariatClient {
|
|
3
|
+
requestJson;
|
|
4
|
+
constructor(transport) {
|
|
5
|
+
this.requestJson = transport.requestJson;
|
|
6
|
+
}
|
|
7
|
+
submitOwnerIntent(input) {
|
|
8
|
+
return this.requestJson("/self/message", {
|
|
9
|
+
method: "POST",
|
|
10
|
+
body: JSON.stringify({
|
|
11
|
+
message: input.message,
|
|
12
|
+
...(input.wait === false ? { wait: false } : {}),
|
|
13
|
+
}),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
queueOwnerFollowUp(input) {
|
|
17
|
+
const message = {
|
|
18
|
+
...input.message,
|
|
19
|
+
metadata: {
|
|
20
|
+
...(input.message.metadata || {}),
|
|
21
|
+
followUpForTaskId: input.taskId,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
return this.requestJson("/self/message", {
|
|
25
|
+
method: "POST",
|
|
26
|
+
body: JSON.stringify({ message }),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async getTaskStatus(taskId) {
|
|
30
|
+
return this.requestJson(`/self/tasks/${encodeURIComponent(taskId)}`, { method: "GET" });
|
|
31
|
+
}
|
|
32
|
+
async getTaskReport(taskId) {
|
|
33
|
+
return this.getTaskStatus(taskId);
|
|
34
|
+
}
|
|
35
|
+
async listConversationTasks(input = {}) {
|
|
36
|
+
const params = new URLSearchParams();
|
|
37
|
+
params.set("limit", String(input.limit || 50));
|
|
38
|
+
if (input.status)
|
|
39
|
+
params.set("status", input.status);
|
|
40
|
+
if (input.route)
|
|
41
|
+
params.set("route", input.route);
|
|
42
|
+
if (input.visibility)
|
|
43
|
+
params.set("visibility", input.visibility);
|
|
44
|
+
const response = await this.requestJson(`/self/tasks?${params.toString()}`, { method: "GET" });
|
|
45
|
+
if (!input.conversationId)
|
|
46
|
+
return response;
|
|
47
|
+
const tasks = (response.tasks || []).filter((task) => task.conversationId === input.conversationId);
|
|
48
|
+
const taskIds = new Set(tasks.map((task) => task.taskId));
|
|
49
|
+
return {
|
|
50
|
+
...response,
|
|
51
|
+
tasks,
|
|
52
|
+
taskViews: (response.taskViews || []).filter((view) => taskIds.has(view.taskId)),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function createOwnerChatMessage(input) {
|
|
57
|
+
return createAkemonMessage({
|
|
58
|
+
type: "akemon.message",
|
|
59
|
+
id: input.id,
|
|
60
|
+
createdAt: input.createdAt,
|
|
61
|
+
source: actorRef("owner", "owner", "local"),
|
|
62
|
+
target: actorRef("agent", input.targetAgent, "local"),
|
|
63
|
+
conversationId: input.conversationId,
|
|
64
|
+
memoryScope: input.memoryScope || "owner",
|
|
65
|
+
permissions: {},
|
|
66
|
+
transport: "local",
|
|
67
|
+
metadata: input.metadata,
|
|
68
|
+
payload: {
|
|
69
|
+
text: input.text,
|
|
70
|
+
format: "text",
|
|
71
|
+
kind: "chat",
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
export function taskIdFromOwnerChatMessage(message) {
|
|
76
|
+
const suffix = message.id || `${message.conversationId || "local"}_${Date.now()}`;
|
|
77
|
+
return `task_${suffix.replace(/[^a-zA-Z0-9_.:-]/g, "_")}`;
|
|
78
|
+
}
|
|
79
|
+
export function taskIsTerminal(task) {
|
|
80
|
+
if (!task)
|
|
81
|
+
return false;
|
|
82
|
+
return task.stage === "done"
|
|
83
|
+
|| task.stage === "blocked"
|
|
84
|
+
|| task.status === "succeeded"
|
|
85
|
+
|| task.status === "failed"
|
|
86
|
+
|| task.status === "info";
|
|
87
|
+
}
|
package/dist/self.js
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* Manages the agent's self-awareness: world knowledge, first-person memory,
|
|
5
5
|
* identity (five questions), bio-simulation, and inner canvas.
|
|
6
6
|
*
|
|
7
|
-
* All data lives in
|
|
7
|
+
* All self data lives in Akemon home under agents/{name}/self/ — separate from
|
|
8
|
+
* project work context.
|
|
8
9
|
*/
|
|
9
10
|
import { readFile, writeFile, appendFile, mkdir, readdir } from "fs/promises";
|
|
10
11
|
import { join } from "path";
|
|
12
|
+
import { agentConfigPath as homeAgentConfigPath, agentAuditDir, agentContactsDir, agentHomeDir, agentInboxDir, agentSelfDir, globalWorkMemoryDir, } from "./akemon-home.js";
|
|
11
13
|
/** Local timestamp string like "2026-03-26T19:13:26" (server timezone, no Z suffix) */
|
|
12
14
|
export function localNow() {
|
|
13
15
|
const d = new Date();
|
|
@@ -21,8 +23,8 @@ export function localNowFilename() {
|
|
|
21
23
|
// ---------------------------------------------------------------------------
|
|
22
24
|
// Paths
|
|
23
25
|
// ---------------------------------------------------------------------------
|
|
24
|
-
export function selfDir(
|
|
25
|
-
return
|
|
26
|
+
export function selfDir(_workdir, agentName) {
|
|
27
|
+
return agentSelfDir(agentName);
|
|
26
28
|
}
|
|
27
29
|
function worldPath(workdir, agentName) {
|
|
28
30
|
return join(selfDir(workdir, agentName), "world.md");
|
|
@@ -60,8 +62,8 @@ export function guidePath(workdir, agentName) {
|
|
|
60
62
|
export function biosPath(workdir, agentName) {
|
|
61
63
|
return join(selfDir(workdir, agentName), "bios.md");
|
|
62
64
|
}
|
|
63
|
-
function agentConfigPath(
|
|
64
|
-
return
|
|
65
|
+
function agentConfigPath(_workdir, agentName) {
|
|
66
|
+
return homeAgentConfigPath(agentName);
|
|
65
67
|
}
|
|
66
68
|
export function directivesPath(workdir, agentName) {
|
|
67
69
|
return join(selfDir(workdir, agentName), "tasks.md");
|
|
@@ -139,6 +141,7 @@ const DEFAULT_CONFIG = {
|
|
|
139
141
|
auto_offline_enabled: true,
|
|
140
142
|
hunger_decay_interval: 300_000, // 5 minutes per hunger point (was 30s — way too fast)
|
|
141
143
|
context_budget: 4096,
|
|
144
|
+
owner_language: "auto",
|
|
142
145
|
};
|
|
143
146
|
export async function initAgentConfig(workdir, agentName) {
|
|
144
147
|
const p = agentConfigPath(workdir, agentName);
|
|
@@ -146,8 +149,14 @@ export async function initAgentConfig(workdir, agentName) {
|
|
|
146
149
|
await readFile(p, "utf-8");
|
|
147
150
|
}
|
|
148
151
|
catch {
|
|
149
|
-
|
|
152
|
+
const home = agentHomeDir(agentName);
|
|
153
|
+
await mkdir(selfDir(workdir, agentName), { recursive: true });
|
|
154
|
+
await mkdir(globalWorkMemoryDir(agentName), { recursive: true });
|
|
155
|
+
await mkdir(agentAuditDir(agentName), { recursive: true });
|
|
156
|
+
await mkdir(agentContactsDir(agentName), { recursive: true });
|
|
157
|
+
await mkdir(agentInboxDir(agentName), { recursive: true });
|
|
150
158
|
await writeFile(p, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n");
|
|
159
|
+
console.log(`[self] First use for agent "${agentName}"; created identity home at ${home}`);
|
|
151
160
|
console.log(`[self] Created config.json with defaults`);
|
|
152
161
|
}
|
|
153
162
|
}
|