@agentprojectcontext/apx 1.54.0 → 1.55.0
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/package.json +1 -1
- package/src/core/stores/messages.js +69 -0
- package/src/host/daemon/api/conversations.js +25 -0
- package/src/interfaces/cli/commands/code.js +56 -0
- package/src/interfaces/cli/index.js +1 -1
- package/src/interfaces/web/dist/assets/{index-Bks35ks-.js → index-J3_Jhr99.js} +126 -126
- package/src/interfaces/web/dist/assets/{index-Bks35ks-.js.map → index-J3_Jhr99.js.map} +1 -1
- package/src/interfaces/web/dist/index.html +1 -1
- package/src/interfaces/web/src/components/chat/ChatList.tsx +73 -18
- package/src/interfaces/web/src/hooks/useChat.ts +29 -1
- package/src/interfaces/web/src/i18n/en.ts +1 -0
- package/src/interfaces/web/src/i18n/es.ts +1 -0
- package/src/interfaces/web/src/lib/api/conversations.ts +7 -1
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +35 -18
- package/src/interfaces/web/src/types/daemon.ts +16 -0
- package/src/interfaces/cli/commands/sys.js +0 -862
- package/src/interfaces/cli/terminal-chat/renderer.js +0 -520
package/package.json
CHANGED
|
@@ -591,6 +591,75 @@ export function readGlobalMessages({ channel, limit = 100, since } = {}) {
|
|
|
591
591
|
return all.slice(-limit);
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
+
// ---------------------------------------------------------------------------
|
|
595
|
+
// Global channel threads (super-agent chats surfaced in the web Chats sidebar)
|
|
596
|
+
// ---------------------------------------------------------------------------
|
|
597
|
+
// The global ledger is the source of truth for every super-agent turn outside
|
|
598
|
+
// exec (telegram, web quick-chat, desktop, deck …). A "thread" is one
|
|
599
|
+
// channel+day JSONL file — the same granularity the context window reads.
|
|
600
|
+
|
|
601
|
+
const CHANNEL_NAME_RE = /^[a-z0-9_-]+$/i;
|
|
602
|
+
|
|
603
|
+
// List every non-empty channel+day thread, newest-last-activity first.
|
|
604
|
+
export function listGlobalThreads({ channels, _globalMessagesDir } = {}) {
|
|
605
|
+
const base = _globalMessagesDir || GLOBAL_MESSAGES_DIR;
|
|
606
|
+
if (!fs.existsSync(base)) return [];
|
|
607
|
+
const chans = (channels && channels.length
|
|
608
|
+
? channels
|
|
609
|
+
: fs.readdirSync(base).filter((f) => {
|
|
610
|
+
try { return fs.statSync(path.join(base, f)).isDirectory(); } catch { return false; }
|
|
611
|
+
})
|
|
612
|
+
).filter((c) => CHANNEL_NAME_RE.test(c));
|
|
613
|
+
|
|
614
|
+
const out = [];
|
|
615
|
+
for (const ch of chans) {
|
|
616
|
+
const dir = path.join(base, ch);
|
|
617
|
+
let files;
|
|
618
|
+
try { files = fs.readdirSync(dir); } catch { continue; }
|
|
619
|
+
for (const f of files) {
|
|
620
|
+
const m = f.match(/^(\d{4}-\d{2}-\d{2})\.jsonl$/);
|
|
621
|
+
if (!m) continue;
|
|
622
|
+
const msgs = parseDayJsonl(fs.readFileSync(path.join(dir, f), "utf8")).filter(
|
|
623
|
+
(r) => r.type === "user" || r.type === "agent"
|
|
624
|
+
);
|
|
625
|
+
if (!msgs.length) continue;
|
|
626
|
+
const firstUser = msgs.find((r) => r.type === "user");
|
|
627
|
+
const title = String((firstUser || msgs[0]).body || "")
|
|
628
|
+
.replace(/\s+/g, " ")
|
|
629
|
+
.trim()
|
|
630
|
+
.slice(0, 80);
|
|
631
|
+
out.push({
|
|
632
|
+
id: m[1],
|
|
633
|
+
channel: ch,
|
|
634
|
+
title: title || `${ch} · ${m[1]}`,
|
|
635
|
+
messages: msgs.length,
|
|
636
|
+
started_at: msgs[0].ts,
|
|
637
|
+
last_ts: msgs[msgs.length - 1].ts,
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
out.sort((a, b) => (b.last_ts || "").localeCompare(a.last_ts || ""));
|
|
642
|
+
return out;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Read one channel+day thread shaped for the web chat viewer:
|
|
646
|
+
// { id, channel, messages: [{ role, content, ts }] } — or null when missing.
|
|
647
|
+
export function readGlobalThread({ channel, date, _globalMessagesDir } = {}) {
|
|
648
|
+
if (!CHANNEL_NAME_RE.test(String(channel || ""))) return null;
|
|
649
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(String(date || ""))) return null;
|
|
650
|
+
const base = _globalMessagesDir || GLOBAL_MESSAGES_DIR;
|
|
651
|
+
const file = path.join(base, channel, `${date}.jsonl`);
|
|
652
|
+
if (!fs.existsSync(file)) return null;
|
|
653
|
+
const messages = parseDayJsonl(fs.readFileSync(file, "utf8"))
|
|
654
|
+
.filter((r) => r.type === "user" || r.type === "agent")
|
|
655
|
+
.map((r) => ({
|
|
656
|
+
role: r.type === "user" ? "user" : "assistant",
|
|
657
|
+
content: r.body || "",
|
|
658
|
+
ts: r.ts,
|
|
659
|
+
}));
|
|
660
|
+
return { id: date, channel, messages };
|
|
661
|
+
}
|
|
662
|
+
|
|
594
663
|
// Wipe the cache and re-populate from APX project messages. Reads BOTH `.jsonl`
|
|
595
664
|
// (current format) and `.md` (legacy). Called by rebuild.
|
|
596
665
|
export function rebuildMessagesFromFs(db, projectRoot) {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// Per-agent conversation surface: list, fetch, compact, and a2a /send.
|
|
2
2
|
// GET /projects/:pid/agents/:slug/conversations
|
|
3
3
|
// GET /projects/:pid/agents/:slug/conversations/:id
|
|
4
|
+
// GET /projects/:pid/super-agent/threads (channel ledger)
|
|
5
|
+
// GET /projects/:pid/super-agent/threads/:channel/:id
|
|
4
6
|
// POST /projects/:pid/agents/:slug/compact
|
|
5
7
|
// POST /projects/:pid/agents/:slug/conversations/:id/compact
|
|
6
8
|
// POST /projects/:pid/send (agent-to-agent)
|
|
7
9
|
import { readAgents } from "#core/apc/parser.js";
|
|
8
10
|
import { listConversations, readConversation } from "#core/stores/conversations.js";
|
|
11
|
+
import { listGlobalThreads, readGlobalThread } from "#core/stores/messages.js";
|
|
9
12
|
import { compactConversation } from "#core/stores/conversations-compactor.js";
|
|
10
13
|
import { replyAsAgent } from "#core/agent/a2a/reply.js";
|
|
11
14
|
import { nowIso } from "./shared.js";
|
|
@@ -48,6 +51,28 @@ export function register(app, { project, config }) {
|
|
|
48
51
|
});
|
|
49
52
|
});
|
|
50
53
|
|
|
54
|
+
// ---- Super-agent channel threads ----
|
|
55
|
+
// The super-agent's chats (telegram, web quick-chat, desktop, deck …) live
|
|
56
|
+
// in the global per-channel ledger, not in per-agent conversation files.
|
|
57
|
+
// These endpoints surface that ledger as day-threads so the web Chats
|
|
58
|
+
// sidebar can list and reopen them.
|
|
59
|
+
app.get("/projects/:pid/super-agent/threads", (req, res) => {
|
|
60
|
+
const p = project(req, res);
|
|
61
|
+
if (!p) return;
|
|
62
|
+
res.json(listGlobalThreads());
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
app.get("/projects/:pid/super-agent/threads/:channel/:id", (req, res) => {
|
|
66
|
+
const p = project(req, res);
|
|
67
|
+
if (!p) return;
|
|
68
|
+
const thread = readGlobalThread({
|
|
69
|
+
channel: req.params.channel,
|
|
70
|
+
date: req.params.id,
|
|
71
|
+
});
|
|
72
|
+
if (!thread) return res.status(404).json({ error: "thread not found" });
|
|
73
|
+
res.json(thread);
|
|
74
|
+
});
|
|
75
|
+
|
|
51
76
|
async function handleCompact(req, res, filename) {
|
|
52
77
|
const p = project(req, res);
|
|
53
78
|
if (!p) return;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// `apx code` — launch the APX terminal coding assistant (Solid.js TUI).
|
|
2
|
+
// The TUI runs its TypeScript source directly under bun; there is no
|
|
3
|
+
// legacy readline fallback anymore (removed with the old sys.js chat).
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { dirname, resolve } from "node:path";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { resolveProjectId } from "./project.js";
|
|
9
|
+
import { readConfig } from "#core/config/index.js";
|
|
10
|
+
import { readIdentity } from "#core/identity/index.js";
|
|
11
|
+
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const TUI_SRC = resolve(__dirname, "../../tui/run.ts");
|
|
14
|
+
|
|
15
|
+
export async function cmdCode(args) {
|
|
16
|
+
const pid = await resolveProjectId(args?.flags?.project);
|
|
17
|
+
const cfg = readConfig();
|
|
18
|
+
const id = readIdentity();
|
|
19
|
+
|
|
20
|
+
// Optional --agent <slug>: route chat to a project agent instead of the APX
|
|
21
|
+
// default. Empty / missing flag means default ("super-agent" mode).
|
|
22
|
+
const agentFlag = typeof args?.flags?.agent === "string" ? args.flags.agent.trim() : "";
|
|
23
|
+
const routedAgentSlug = agentFlag || null;
|
|
24
|
+
const defaultAgentLabel = id?.agent_name || cfg.super_agent?.name || "APX";
|
|
25
|
+
|
|
26
|
+
if (!existsSync(TUI_SRC)) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
"apx code: TUI source not found at src/interfaces/tui/run.ts — reinstall with `npm i -g @agentprojectcontext/apx`."
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// bun must resolve node_modules/tsconfig from the apx package root, so the
|
|
33
|
+
// spawn cwd stays there — but we pass the user's actual working directory
|
|
34
|
+
// (where they ran `apx code`) via --cwd so the TUI shows the real project
|
|
35
|
+
// path + git branch instead of apx/src.
|
|
36
|
+
const bunBin = process.env.BUN_PATH || "bun";
|
|
37
|
+
const userCwd = process.cwd();
|
|
38
|
+
const result = spawnSync(bunBin, [
|
|
39
|
+
"--preload", "@opentui/solid/preload",
|
|
40
|
+
TUI_SRC,
|
|
41
|
+
"--pid", pid,
|
|
42
|
+
"--agent", routedAgentSlug || defaultAgentLabel,
|
|
43
|
+
"--model", cfg.super_agent?.model || "claude-3-5-sonnet",
|
|
44
|
+
"--cwd", userCwd,
|
|
45
|
+
], { stdio: "inherit", cwd: resolve(__dirname, "../../..") });
|
|
46
|
+
|
|
47
|
+
if (result.error?.code === "ENOENT") {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"apx code: bun is required to run the TUI but was not found. Install it (https://bun.sh) or set BUN_PATH to the binary."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (result.error) throw result.error;
|
|
53
|
+
if (typeof result.status === "number" && result.status !== 0) {
|
|
54
|
+
process.exitCode = result.status;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -90,7 +90,7 @@ import {
|
|
|
90
90
|
cmdConversationsList,
|
|
91
91
|
cmdConversationsGet,
|
|
92
92
|
} from "./commands/chat.js";
|
|
93
|
-
import {
|
|
93
|
+
import { cmdCode } from "./commands/code.js";
|
|
94
94
|
import { cmdRun, cmdEnvDetect } from "./commands/runtime.js";
|
|
95
95
|
import { cmdSend, cmdConnections } from "./commands/a2a.js";
|
|
96
96
|
import {
|