agent-relay-server 0.104.5 → 0.105.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/docs/openapi.json +141 -1
- package/package.json +2 -2
- package/public/assets/MessageBubble-CHor4Sxp.js +4 -0
- package/public/assets/{MessageBubble-BpiTbbnp.js.map → MessageBubble-CHor4Sxp.js.map} +1 -1
- package/public/assets/{PlanGraphPanel-k8Aa98g5.js → PlanGraphPanel-jHfkQBX6.js} +2 -2
- package/public/assets/{PlanGraphPanel-k8Aa98g5.js.map → PlanGraphPanel-jHfkQBX6.js.map} +1 -1
- package/public/assets/{activity-CxKi5Erb.js → activity-DDXS6LsX.js} +2 -2
- package/public/assets/{activity-CxKi5Erb.js.map → activity-DDXS6LsX.js.map} +1 -1
- package/public/assets/{agent-profiles-DMZXdN6K.js → agent-profiles-Cn8lCTkg.js} +2 -2
- package/public/assets/{agent-profiles-DMZXdN6K.js.map → agent-profiles-Cn8lCTkg.js.map} +1 -1
- package/public/assets/agents-DBTdcFFz.js +2 -0
- package/public/assets/{agents-BrvpH3gn.js.map → agents-DBTdcFFz.js.map} +1 -1
- package/public/assets/{analytics-1fvh-9ok.js → analytics-VximqXQ9.js} +3 -3
- package/public/assets/{analytics-1fvh-9ok.js.map → analytics-VximqXQ9.js.map} +1 -1
- package/public/assets/{automation-BCgX5WOH.js → automation-L9wq4y5F.js} +2 -2
- package/public/assets/{automation-BCgX5WOH.js.map → automation-L9wq4y5F.js.map} +1 -1
- package/public/assets/{badge-BLar6FjP.js → badge-D8fABzMs.js} +2 -2
- package/public/assets/{badge-BLar6FjP.js.map → badge-D8fABzMs.js.map} +1 -1
- package/public/assets/{branch-state-badge-DYA7bU0i.js → branch-state-badge-CcLZ_u86.js} +2 -2
- package/public/assets/{branch-state-badge-DYA7bU0i.js.map → branch-state-badge-CcLZ_u86.js.map} +1 -1
- package/public/assets/{button-BrIB69qd.js → button-KASZcscA.js} +2 -2
- package/public/assets/{button-BrIB69qd.js.map → button-KASZcscA.js.map} +1 -1
- package/public/assets/card-Cds0MWME.js +2 -0
- package/public/assets/{card-lhnFnBoz.js.map → card-Cds0MWME.js.map} +1 -1
- package/public/assets/{channels-CK80oJYG.js → channels-CcSnLzCG.js} +2 -2
- package/public/assets/{channels-CK80oJYG.js.map → channels-CcSnLzCG.js.map} +1 -1
- package/public/assets/{chat-D_2PEz06.js → chat-BzMj_PO6.js} +2 -2
- package/public/assets/{chat-D_2PEz06.js.map → chat-BzMj_PO6.js.map} +1 -1
- package/public/assets/{connectors-ChGyht5m.js → connectors-DbPOlQhL.js} +2 -2
- package/public/assets/{connectors-ChGyht5m.js.map → connectors-DbPOlQhL.js.map} +1 -1
- package/public/assets/copy-button-d9DFNX9v.js +2 -0
- package/public/assets/{copy-button-Cd-LbSbg.js.map → copy-button-d9DFNX9v.js.map} +1 -1
- package/public/assets/{display-D1xB8NJZ.js → display-BWi8DQCp.js} +2 -2
- package/public/assets/display-BWi8DQCp.js.map +1 -0
- package/public/assets/{dist-BnbGIUmi.js → dist-BbUJ1Vht.js} +2 -2
- package/public/assets/{dist-BnbGIUmi.js.map → dist-BbUJ1Vht.js.map} +1 -1
- package/public/assets/{dist-Bp10H3oR.js → dist-BlZvUZZB.js} +2 -2
- package/public/assets/{dist-Bp10H3oR.js.map → dist-BlZvUZZB.js.map} +1 -1
- package/public/assets/{dist-DDUGmmoi.js → dist-BwwlmyBq.js} +2 -2
- package/public/assets/{dist-DDUGmmoi.js.map → dist-BwwlmyBq.js.map} +1 -1
- package/public/assets/dist-CBVZk9U8.js +2 -0
- package/public/assets/{dist-BEzpMqLy.js.map → dist-CBVZk9U8.js.map} +1 -1
- package/public/assets/{dist-B5VvlkhI.js → dist-CgqfdHSt.js} +2 -2
- package/public/assets/{dist-B5VvlkhI.js.map → dist-CgqfdHSt.js.map} +1 -1
- package/public/assets/dist-DC-TqTz2.js +2 -0
- package/public/assets/{dist-30weaXto.js.map → dist-DC-TqTz2.js.map} +1 -1
- package/public/assets/{dist-DZ97OosY.js → dist-DOAjFOS4.js} +2 -2
- package/public/assets/{dist-DZ97OosY.js.map → dist-DOAjFOS4.js.map} +1 -1
- package/public/assets/{dist-BjOBkHHY.js → dist-DTXKbk2K.js} +2 -2
- package/public/assets/{dist-BjOBkHHY.js.map → dist-DTXKbk2K.js.map} +1 -1
- package/public/assets/dist-DreO5AcZ.js +2 -0
- package/public/assets/{dist-Cgy0FmP-.js.map → dist-DreO5AcZ.js.map} +1 -1
- package/public/assets/{dist-CQF3Jiqg.js → dist-DybScJmm.js} +2 -2
- package/public/assets/{dist-CQF3Jiqg.js.map → dist-DybScJmm.js.map} +1 -1
- package/public/assets/{dist-DAl28ejX.js → dist-UhEAFdvZ.js} +2 -2
- package/public/assets/{dist-DAl28ejX.js.map → dist-UhEAFdvZ.js.map} +1 -1
- package/public/assets/{es2015-B8Z9p8oQ.js → es2015-DUjFyjDp.js} +2 -2
- package/public/assets/{es2015-B8Z9p8oQ.js.map → es2015-DUjFyjDp.js.map} +1 -1
- package/public/assets/{formatted-body-impl-BJ4WCF5J.js → formatted-body-impl-CFWHLkCY.js} +2 -2
- package/public/assets/{formatted-body-impl-BJ4WCF5J.js.map → formatted-body-impl-CFWHLkCY.js.map} +1 -1
- package/public/assets/index-BjjzI2LT.css +2 -0
- package/public/assets/{index-CN7QZlMb.js → index-aCfZQ7LY.js} +13 -13
- package/public/assets/index-aCfZQ7LY.js.map +1 -0
- package/public/assets/{input-B_fUHtLD.js → input-CtHfLn1i.js} +2 -2
- package/public/assets/{input-B_fUHtLD.js.map → input-CtHfLn1i.js.map} +1 -1
- package/public/assets/{insights-BCZRV0hX.js → insights-BuPFE0tf.js} +2 -2
- package/public/assets/{insights-BCZRV0hX.js.map → insights-BuPFE0tf.js.map} +1 -1
- package/public/assets/{integrations-C7UGs00U.js → integrations-hkSW8CzM.js} +2 -2
- package/public/assets/{integrations-C7UGs00U.js.map → integrations-hkSW8CzM.js.map} +1 -1
- package/public/assets/{lib-ng6WZYjE.js → lib-l-JkMVR9.js} +2 -2
- package/public/assets/{lib-ng6WZYjE.js.map → lib-l-JkMVR9.js.map} +1 -1
- package/public/assets/{lucide-react-BYZuAhQs.js → lucide-react-C4eXYCwx.js} +2 -2
- package/public/assets/{lucide-react-BYZuAhQs.js.map → lucide-react-C4eXYCwx.js.map} +1 -1
- package/public/assets/{maintenance-ChYno3Fm.js → maintenance-wYwJ7w6h.js} +2 -2
- package/public/assets/{maintenance-ChYno3Fm.js.map → maintenance-wYwJ7w6h.js.map} +1 -1
- package/public/assets/{managed-agents-DjxZQNIR.js → managed-agents-CKaYD93I.js} +4 -4
- package/public/assets/{managed-agents-DjxZQNIR.js.map → managed-agents-CKaYD93I.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-DFa5HF1H.js → markdown-preview-impl-bf4eDQUM.js} +2 -2
- package/public/assets/{markdown-preview-impl-DFa5HF1H.js.map → markdown-preview-impl-bf4eDQUM.js.map} +1 -1
- package/public/assets/memory-DIneEza9.js +2 -0
- package/public/assets/{memory-CTw6kadT.js.map → memory-DIneEza9.js.map} +1 -1
- package/public/assets/{messages-Cjr816D_.js → messages-DP9Vv_wh.js} +2 -2
- package/public/assets/{messages-Cjr816D_.js.map → messages-DP9Vv_wh.js.map} +1 -1
- package/public/assets/{orchestrators-CdmFKA7K.js → orchestrators-CAnKjxdO.js} +2 -2
- package/public/assets/{orchestrators-CdmFKA7K.js.map → orchestrators-CAnKjxdO.js.map} +1 -1
- package/public/assets/{overview-DBOnjfpP.js → overview-B98U3C-y.js} +2 -2
- package/public/assets/{overview-DBOnjfpP.js.map → overview-B98U3C-y.js.map} +1 -1
- package/public/assets/{pairs-BkcdKdF7.js → pairs-DVeeuxhY.js} +2 -2
- package/public/assets/{pairs-BkcdKdF7.js.map → pairs-DVeeuxhY.js.map} +1 -1
- package/public/assets/{projects-ClKbDQB1.js → projects-vt63bwHN.js} +2 -2
- package/public/assets/{projects-ClKbDQB1.js.map → projects-vt63bwHN.js.map} +1 -1
- package/public/assets/prompt-settings-Df-0ZMJ5.js +2 -0
- package/public/assets/prompt-settings-Df-0ZMJ5.js.map +1 -0
- package/public/assets/{react-dom-Dbhs84ug.js → react-dom-BMF4hNzG.js} +2 -2
- package/public/assets/{react-dom-Dbhs84ug.js.map → react-dom-BMF4hNzG.js.map} +1 -1
- package/public/assets/{registry-Bsf3RtOO.js → registry-DlLZyW7_.js} +2 -2
- package/public/assets/{registry-Bsf3RtOO.js.map → registry-DlLZyW7_.js.map} +1 -1
- package/public/assets/{security-Iyu5bhJw.js → security-Bo4Ty3lz.js} +2 -2
- package/public/assets/{security-Iyu5bhJw.js.map → security-Bo4Ty3lz.js.map} +1 -1
- package/public/assets/{select-Bi6tNJDx.js → select-BguZ80M8.js} +2 -2
- package/public/assets/{select-Bi6tNJDx.js.map → select-BguZ80M8.js.map} +1 -1
- package/public/assets/settings-CpX9Xw2j.js +6 -0
- package/public/assets/{settings-CbHp2F9r.js.map → settings-CpX9Xw2j.js.map} +1 -1
- package/public/assets/{store-zeyDiSKE.js → store-DUfrGvOE.js} +3 -3
- package/public/assets/{store-zeyDiSKE.js.map → store-DUfrGvOE.js.map} +1 -1
- package/public/assets/{tasks-CPlf-5Tr.js → tasks-Cg1HXY9l.js} +2 -2
- package/public/assets/{tasks-CPlf-5Tr.js.map → tasks-Cg1HXY9l.js.map} +1 -1
- package/public/assets/{teams-D2uUNhlY.js → teams-BFcYunxB.js} +2 -2
- package/public/assets/{teams-D2uUNhlY.js.map → teams-BFcYunxB.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-uRzbrlXy.js → terminal-viewer-impl-CF2EBa2K.js} +3 -3
- package/public/assets/{terminal-viewer-impl-uRzbrlXy.js.map → terminal-viewer-impl-CF2EBa2K.js.map} +1 -1
- package/public/assets/types-DorDDvEb.js.map +1 -1
- package/public/assets/{use-keyboard-viewport-D8_NYDkh.js → use-keyboard-viewport-RYMALvu1.js} +2 -2
- package/public/assets/{use-keyboard-viewport-D8_NYDkh.js.map → use-keyboard-viewport-RYMALvu1.js.map} +1 -1
- package/public/assets/user-avatar-D1ffSClz.js +2 -0
- package/public/assets/{user-avatar-GFWMuAGK.js.map → user-avatar-D1ffSClz.js.map} +1 -1
- package/public/assets/{work-queue-B30SNmuq.js → work-queue-DV36cxjp.js} +2 -2
- package/public/assets/{work-queue-B30SNmuq.js.map → work-queue-DV36cxjp.js.map} +1 -1
- package/public/assets/workspaces-CIsQqQby.js +3 -0
- package/public/assets/workspaces-CIsQqQby.js.map +1 -0
- package/public/index.html +22 -22
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/monitors/relay-monitor.provisioned.mjs +114 -23
- package/runner/plugins/claude/monitors/relay-monitor.ts +2 -2
- package/runner/src/adapter.ts +4 -1
- package/src/agent-lifecycle-events.ts +21 -5
- package/src/automations/reconcile.ts +4 -1
- package/src/branch-landed.ts +22 -4
- package/src/config-store.ts +17 -21
- package/src/context-advisory.ts +10 -3
- package/src/db/index.ts +1 -0
- package/src/db/projects.ts +29 -0
- package/src/db/prompt-templates-schema.ts +20 -0
- package/src/db/prompt-templates.ts +91 -0
- package/src/db/schema.ts +5 -4
- package/src/db/tasks.ts +2 -1
- package/src/db/workspaces.ts +41 -1
- package/src/index.ts +3 -0
- package/src/project-instructions.ts +7 -14
- package/src/prompt-resolver.ts +530 -0
- package/src/prompt-template-defaults-runner.ts +136 -0
- package/src/routes/index.ts +5 -0
- package/src/routes/prompt-templates.ts +60 -0
- package/src/routes/workspaces.ts +4 -3
- package/src/routing-policy-push.ts +4 -1
- package/src/security.ts +3 -0
- package/src/self-resume.ts +8 -15
- package/src/services/prompt-templates.ts +19 -0
- package/src/services/register-agent.ts +2 -0
- package/src/services/spawn-issue-activity.ts +107 -0
- package/src/spawn-targets.ts +3 -11
- package/src/steward.ts +5 -23
- package/src/workspace-auto-merge.ts +19 -2
- package/src/workspace-phase.ts +15 -28
- package/public/assets/MessageBubble-BpiTbbnp.js +0 -4
- package/public/assets/agents-BrvpH3gn.js +0 -2
- package/public/assets/card-lhnFnBoz.js +0 -2
- package/public/assets/copy-button-Cd-LbSbg.js +0 -2
- package/public/assets/display-D1xB8NJZ.js.map +0 -1
- package/public/assets/dist-30weaXto.js +0 -2
- package/public/assets/dist-BEzpMqLy.js +0 -2
- package/public/assets/dist-Cgy0FmP-.js +0 -2
- package/public/assets/index-BMO_Sblt.css +0 -2
- package/public/assets/index-CN7QZlMb.js.map +0 -1
- package/public/assets/memory-CTw6kadT.js +0 -2
- package/public/assets/settings-CbHp2F9r.js +0 -6
- package/public/assets/user-avatar-GFWMuAGK.js +0 -2
- package/public/assets/workspaces-CSpmgbPT.js +0 -3
- package/public/assets/workspaces-CSpmgbPT.js.map +0 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { PromptTemplate } from "../types";
|
|
2
|
+
import { ValidationError, getDb } from "./connection.ts";
|
|
3
|
+
|
|
4
|
+
interface PromptTemplateRow {
|
|
5
|
+
slug: string;
|
|
6
|
+
category: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string | null;
|
|
9
|
+
template: string;
|
|
10
|
+
default_template: string;
|
|
11
|
+
variables: string;
|
|
12
|
+
updated_at: number;
|
|
13
|
+
created_at: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface SeedTemplate {
|
|
17
|
+
slug: string;
|
|
18
|
+
category: string;
|
|
19
|
+
title: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
template: string;
|
|
22
|
+
defaultTemplate: string;
|
|
23
|
+
variables: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type PromptTemplateRecord = PromptTemplate;
|
|
27
|
+
|
|
28
|
+
function rowToPromptTemplate(row: PromptTemplateRow): PromptTemplateRecord {
|
|
29
|
+
return {
|
|
30
|
+
slug: row.slug,
|
|
31
|
+
category: row.category,
|
|
32
|
+
title: row.title,
|
|
33
|
+
description: row.description ?? undefined,
|
|
34
|
+
template: row.template,
|
|
35
|
+
defaultTemplate: row.default_template,
|
|
36
|
+
variables: JSON.parse(row.variables) as string[],
|
|
37
|
+
updatedAt: row.updated_at,
|
|
38
|
+
createdAt: row.created_at,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getTemplate(slug: string): PromptTemplateRecord | null {
|
|
43
|
+
const row = getDb().query("SELECT * FROM prompt_templates WHERE slug = ?").get(slug) as PromptTemplateRow | null;
|
|
44
|
+
return row ? rowToPromptTemplate(row) : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function listTemplates(category?: string): PromptTemplateRecord[] {
|
|
48
|
+
const rows = (
|
|
49
|
+
category
|
|
50
|
+
? getDb().query("SELECT * FROM prompt_templates WHERE category = ? ORDER BY category ASC, title ASC, slug ASC").all(category)
|
|
51
|
+
: getDb().query("SELECT * FROM prompt_templates ORDER BY category ASC, title ASC, slug ASC").all()
|
|
52
|
+
) as PromptTemplateRow[];
|
|
53
|
+
return rows.map(rowToPromptTemplate);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function upsertTemplate(slug: string, template: string): void {
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
const result = getDb().query("UPDATE prompt_templates SET template = ?, updated_at = ? WHERE slug = ?").run(template, now, slug);
|
|
59
|
+
if ((result.changes ?? 0) === 0) throw new ValidationError(`prompt template ${slug} not found`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function resetTemplate(slug: string): void {
|
|
63
|
+
const now = Date.now();
|
|
64
|
+
const result = getDb().query("UPDATE prompt_templates SET template = default_template, updated_at = ? WHERE slug = ?").run(now, slug);
|
|
65
|
+
if ((result.changes ?? 0) === 0) throw new ValidationError(`prompt template ${slug} not found`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function seedTemplates(templates: SeedTemplate[]): void {
|
|
69
|
+
const now = Date.now();
|
|
70
|
+
const insert = getDb().query(`
|
|
71
|
+
INSERT OR IGNORE INTO prompt_templates (
|
|
72
|
+
slug, category, title, description, template, default_template, variables, updated_at, created_at
|
|
73
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
74
|
+
`);
|
|
75
|
+
const tx = getDb().transaction((items: SeedTemplate[]) => {
|
|
76
|
+
for (const item of items) {
|
|
77
|
+
insert.run(
|
|
78
|
+
item.slug,
|
|
79
|
+
item.category,
|
|
80
|
+
item.title,
|
|
81
|
+
item.description ?? null,
|
|
82
|
+
item.template,
|
|
83
|
+
item.defaultTemplate,
|
|
84
|
+
JSON.stringify(item.variables),
|
|
85
|
+
now,
|
|
86
|
+
now,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
tx(templates);
|
|
91
|
+
}
|
package/src/db/schema.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { matchAgents } from "../agent-ref";
|
|
|
17
17
|
import { applyConnectionPragmas, getDb, setDb } from "./connection.ts";
|
|
18
18
|
import { ensureContinuationArchiveSearchSchema } from "./continuation-archives.ts";
|
|
19
19
|
import { applyMigrations } from "./migrations.ts";
|
|
20
|
+
import { PROMPT_TEMPLATES_SCHEMA_SQL, seedPromptTemplatesIfNeeded } from "./prompt-templates-schema";
|
|
20
21
|
import type {
|
|
21
22
|
AgentCard,
|
|
22
23
|
ActivityEvent,
|
|
@@ -506,6 +507,8 @@ export function initDb(path: string = "agent-relay.db"): Database {
|
|
|
506
507
|
);
|
|
507
508
|
CREATE INDEX IF NOT EXISTS idx_config_history_key ON config_history(namespace, key, version);
|
|
508
509
|
|
|
510
|
+
${PROMPT_TEMPLATES_SCHEMA_SQL}
|
|
511
|
+
|
|
509
512
|
-- Per-user settings (#391, epic #388). The user dimension the global \`config\` table lacks:
|
|
510
513
|
-- the same \`(namespace, key)\` descriptor address resolves to a per-user value, keyed by the
|
|
511
514
|
-- resolved \`users.id\` (#393). \`config\` semantics are untouched — \`tier:"user"\` descriptors
|
|
@@ -1009,8 +1012,7 @@ export function initDb(path: string = "agent-relay.db"): Database {
|
|
|
1009
1012
|
);
|
|
1010
1013
|
`);
|
|
1011
1014
|
|
|
1012
|
-
ensureContinuationArchiveSearchSchema();
|
|
1013
|
-
applyMigrations();
|
|
1015
|
+
ensureContinuationArchiveSearchSchema(); applyMigrations(); seedPromptTemplatesIfNeeded();
|
|
1014
1016
|
|
|
1015
1017
|
// Bootstrap planner statistics on first run (sqlite_stat1 absent means ANALYZE
|
|
1016
1018
|
// has never run — the planner would otherwise rely on heuristics only), then
|
|
@@ -1018,8 +1020,7 @@ export function initDb(path: string = "agent-relay.db"): Database {
|
|
|
1018
1020
|
const hasStats = getDb()
|
|
1019
1021
|
.query("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'sqlite_stat1'")
|
|
1020
1022
|
.get();
|
|
1021
|
-
if (!hasStats) getDb().run("ANALYZE");
|
|
1022
|
-
getDb().run("PRAGMA optimize");
|
|
1023
|
+
if (!hasStats) getDb().run("ANALYZE"); getDb().run("PRAGMA optimize");
|
|
1023
1024
|
|
|
1024
1025
|
return conn;
|
|
1025
1026
|
}
|
package/src/db/tasks.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { rowToTask, rowToTaskEvent } from "./mappers.ts";
|
|
|
21
21
|
import { claimMessageRow } from "./message-claims.ts";
|
|
22
22
|
import { TASK_SELECT, insertTaskEvent } from "./task-core.ts";
|
|
23
23
|
import { settleSingleTargetOnDemandTasks } from "./task-maintenance.ts";
|
|
24
|
+
import { renderTemplate } from "../prompt-resolver";
|
|
24
25
|
import type {
|
|
25
26
|
AgentCard,
|
|
26
27
|
ActivityEvent,
|
|
@@ -101,7 +102,7 @@ export function taskMessageBody(task: Pick<Task, "id" | "source" | "severity" |
|
|
|
101
102
|
];
|
|
102
103
|
if (task.externalUrl) lines.push("", `External: ${task.externalUrl}`);
|
|
103
104
|
if (task.dedupeKey) lines.push(`Dedupe: ${task.dedupeKey}`);
|
|
104
|
-
lines.push("", "
|
|
105
|
+
lines.push("", renderTemplate("task.claim.instruction"));
|
|
105
106
|
return lines.join("\n");
|
|
106
107
|
}
|
|
107
108
|
|
package/src/db/workspaces.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { STALE_TTL_MS, DAY_MS, CLAIM_LEASE_MS, POOL_CLAIM_LEASE_MS, WORKSPACE_MERGE_LEASE_MS } from "../config";
|
|
16
16
|
import { matchAgents } from "../agent-ref";
|
|
17
17
|
import { getDb } from "./connection.ts";
|
|
18
|
+
import { resolveProjectsForCwds } from "./projects.ts";
|
|
18
19
|
import type {
|
|
19
20
|
AgentCard,
|
|
20
21
|
ActivityEvent,
|
|
@@ -161,7 +162,7 @@ export function upsertWorkspaceFromManagedAgent(agent: ManagedAgent): WorkspaceR
|
|
|
161
162
|
// overwrite the true base, and the next land advances a local-only branch that never
|
|
162
163
|
// reaches origin/main (#285). Trust the existing row's branch/base over registration;
|
|
163
164
|
// only a brand-new row takes the runner's values.
|
|
164
|
-
|
|
165
|
+
const result = upsertWorkspace({
|
|
165
166
|
id: workspace.id,
|
|
166
167
|
repoRoot: workspace.repoRoot,
|
|
167
168
|
sourceCwd: workspace.sourceCwd ?? agent.cwd,
|
|
@@ -185,6 +186,8 @@ export function upsertWorkspaceFromManagedAgent(agent: ManagedAgent): WorkspaceR
|
|
|
185
186
|
tmuxSession: agent.tmuxSession,
|
|
186
187
|
},
|
|
187
188
|
});
|
|
189
|
+
if (!existing) emitWorkspaceCreate(result);
|
|
190
|
+
return result;
|
|
188
191
|
}
|
|
189
192
|
// Shared-mode occupancy: one row per agent sharing a git repo, with no
|
|
190
193
|
// worktree. Records true repo occupancy in the Workspaces view (informational
|
|
@@ -271,6 +274,25 @@ export function listWorkspaces(filter: { repoRoot?: string; ownerAgentId?: strin
|
|
|
271
274
|
return (getDb().query(sql).all(...params) as any[]).map(rowToWorkspace);
|
|
272
275
|
}
|
|
273
276
|
|
|
277
|
+
export function withResolvedWorkspaceProjects(
|
|
278
|
+
workspaces: WorkspaceRecord[],
|
|
279
|
+
filter: { projectId?: string } = {},
|
|
280
|
+
): WorkspaceRecord[] {
|
|
281
|
+
const projectsByRepoRoot = resolveProjectsForCwds(workspaces.map((workspace) => workspace.repoRoot));
|
|
282
|
+
return workspaces.flatMap((workspace) => {
|
|
283
|
+
const project = projectsByRepoRoot.get(workspace.repoRoot);
|
|
284
|
+
if (filter.projectId && project?.id !== filter.projectId) return [];
|
|
285
|
+
return [{
|
|
286
|
+
...workspace,
|
|
287
|
+
...(project ? {
|
|
288
|
+
projectId: project.id,
|
|
289
|
+
projectSlug: project.slug,
|
|
290
|
+
...(project.title ? { projectTitle: project.title } : {}),
|
|
291
|
+
} : {}),
|
|
292
|
+
}];
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
274
296
|
export function deleteWorkspace(id: string): boolean {
|
|
275
297
|
return getDb().query("DELETE FROM workspaces WHERE id = ?").run(id).changes > 0;
|
|
276
298
|
}
|
|
@@ -325,6 +347,24 @@ export function emitWorkspaceChange(workspace: WorkspaceRecord | null | undefine
|
|
|
325
347
|
}
|
|
326
348
|
}
|
|
327
349
|
|
|
350
|
+
// Late-bound listeners for a newly created isolated workspace. Fired once per workspace
|
|
351
|
+
// (on the INSERT path), allowing upper layers to record issue activity without a
|
|
352
|
+
// db→service import cycle. index.ts registers the spawn-issue-activity handler.
|
|
353
|
+
type WorkspaceCreateListener = (workspace: WorkspaceRecord) => void;
|
|
354
|
+
const workspaceCreateListeners = new Set<WorkspaceCreateListener>();
|
|
355
|
+
export function onWorkspaceCreate(listener: WorkspaceCreateListener): void {
|
|
356
|
+
workspaceCreateListeners.add(listener);
|
|
357
|
+
}
|
|
358
|
+
function emitWorkspaceCreate(workspace: WorkspaceRecord): void {
|
|
359
|
+
for (const listener of workspaceCreateListeners) {
|
|
360
|
+
try {
|
|
361
|
+
listener(workspace);
|
|
362
|
+
} catch {
|
|
363
|
+
// A create listener must never break a workspace write.
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
328
368
|
export function updateWorkspaceStatus(id: string, status: WorkspaceStatus, metadata: Record<string, unknown> = {}): WorkspaceRecord | null {
|
|
329
369
|
const existing = getWorkspace(id);
|
|
330
370
|
if (!existing) return null;
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,8 @@ import { installNotificationSubscriptionRule } from "./notification-subscription
|
|
|
14
14
|
import { installQuotaAdvisoryHandler } from "./quota-advisory";
|
|
15
15
|
import { startPlanLiveBindings } from "./services/plan-live-bindings";
|
|
16
16
|
import { startRelayScheduler } from "./services/scheduler";
|
|
17
|
+
import { recordWorkspaceIssueActivity } from "./services/spawn-issue-activity";
|
|
18
|
+
import { onWorkspaceCreate } from "./db";
|
|
17
19
|
import { resolve, sep } from "path";
|
|
18
20
|
import { gzipSync, brotliCompressSync, constants as zlibConstants } from "node:zlib";
|
|
19
21
|
import {
|
|
@@ -78,6 +80,7 @@ function startServer(): void {
|
|
|
78
80
|
|
|
79
81
|
assertSafeNetworkConfig(HOST);
|
|
80
82
|
initDb(DB_PATH);
|
|
83
|
+
onWorkspaceCreate(recordWorkspaceIssueActivity);
|
|
81
84
|
installQuotaAdvisoryHandler();
|
|
82
85
|
installNotificationSubscriptionRule();
|
|
83
86
|
startPlanLiveBindings();
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// is that lever: the included-source set is a policy PARAMETER, and the `vanilla`
|
|
12
12
|
// policy includes `manual`+`promoted` while excluding `ingested`.
|
|
13
13
|
import { resolveProjectEntries } from "./db";
|
|
14
|
+
import { renderTemplate } from "./prompt-resolver";
|
|
14
15
|
import { PROJECT_ENTRY_SOURCES, type AgentProfile, type Project, type ProjectEntryKind, type ProjectEntrySource, type RelayInjectionCategory, type ResolvedProjectEntry } from "./types";
|
|
15
16
|
|
|
16
17
|
/** Named source policies — THE additive-from-empty lever (#403 decision 4).
|
|
@@ -64,16 +65,6 @@ interface ComposedSpawnInstructions {
|
|
|
64
65
|
const DEFAULT_KINDS: readonly ProjectEntryKind[] = ["rule", "fact"];
|
|
65
66
|
const DEFAULT_MAX_BYTES = 8192;
|
|
66
67
|
const TRUNCATION_NOTICE = "_(… additional project entries omitted to fit the instruction budget.)_";
|
|
67
|
-
const SPAWNED_CHILD_REPORTUP_INSTRUCTION = [
|
|
68
|
-
"Agent Relay report-up:",
|
|
69
|
-
"You are a spawned child agent. Just respond normally when your turn is complete; Relay automatically delivers your final response to your coordinator. Do not call a messaging tool only to report completion.",
|
|
70
|
-
"You have no interactive human at your terminal, so do not use blocking prompts: AskUserQuestion and plan mode/ExitPlanMode will hang with no one to answer. If you need a decision, approval, or clarification, ask your coordinator via Relay and continue once they respond.",
|
|
71
|
-
].join("\n");
|
|
72
|
-
const COORDINATOR_CHILD_REPORTUP_INSTRUCTION = [
|
|
73
|
-
"Agent Relay child responses:",
|
|
74
|
-
"When you spawn child agents, their turn-final responses arrive automatically as Relay messages. Do not put report-up instructions or your own agent id in child briefs.",
|
|
75
|
-
].join("\n");
|
|
76
|
-
|
|
77
68
|
const KIND_HEADINGS: Record<ProjectEntryKind, string> = {
|
|
78
69
|
rule: "Rules",
|
|
79
70
|
fact: "Facts",
|
|
@@ -257,19 +248,21 @@ export function composeSpawnInstructionsWithEvents(input: {
|
|
|
257
248
|
});
|
|
258
249
|
}
|
|
259
250
|
if (input.spawnedBy) {
|
|
260
|
-
|
|
251
|
+
const instruction = renderTemplate("spawn.reportup.child");
|
|
252
|
+
appendBlocks.push(instruction);
|
|
261
253
|
relayInjectionEvents.push({
|
|
262
254
|
category: "instructions",
|
|
263
255
|
summary: "injected spawned-child report-up instructions",
|
|
264
|
-
detail: { source: "spawned-child-report-up", spawnedBy: input.spawnedBy, content:
|
|
256
|
+
detail: { source: "spawned-child-report-up", spawnedBy: input.spawnedBy, content: instruction },
|
|
265
257
|
});
|
|
266
258
|
}
|
|
267
259
|
if ((input.profile?.maxSpawnedAgents ?? 0) > 0) {
|
|
268
|
-
|
|
260
|
+
const instruction = renderTemplate("spawn.reportup.coordinator");
|
|
261
|
+
appendBlocks.push(instruction);
|
|
269
262
|
relayInjectionEvents.push({
|
|
270
263
|
category: "instructions",
|
|
271
264
|
summary: "injected coordinator child-response instructions",
|
|
272
|
-
detail: { source: "coordinator-child-report-up", content:
|
|
265
|
+
detail: { source: "coordinator-child-report-up", content: instruction },
|
|
273
266
|
});
|
|
274
267
|
}
|
|
275
268
|
const profileSystem = input.profile?.instructions.system?.trim();
|