borgmcp 0.2.0-beta.8 → 0.3.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/README.md +2 -2
- package/dist/auth.js +5 -5
- package/dist/auth.js.map +1 -1
- package/dist/claude.d.ts +9 -4
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +62 -26
- package/dist/claude.js.map +1 -1
- package/dist/config-utils.d.ts +32 -0
- package/dist/config-utils.d.ts.map +1 -1
- package/dist/config-utils.js +159 -0
- package/dist/config-utils.js.map +1 -1
- package/dist/cubes.d.ts +51 -0
- package/dist/cubes.d.ts.map +1 -0
- package/dist/cubes.js +161 -0
- package/dist/cubes.js.map +1 -0
- package/dist/inbox.d.ts +33 -0
- package/dist/inbox.d.ts.map +1 -0
- package/dist/inbox.js +125 -0
- package/dist/inbox.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +353 -25
- package/dist/index.js.map +1 -1
- package/dist/log-audit.d.ts +27 -0
- package/dist/log-audit.d.ts.map +1 -0
- package/dist/log-audit.js +161 -0
- package/dist/log-audit.js.map +1 -0
- package/dist/postinstall.d.ts +1 -1
- package/dist/postinstall.d.ts.map +1 -1
- package/dist/postinstall.js +4 -4
- package/dist/postinstall.js.map +1 -1
- package/dist/regen-format.d.ts +53 -0
- package/dist/regen-format.d.ts.map +1 -0
- package/dist/regen-format.js +164 -0
- package/dist/regen-format.js.map +1 -0
- package/dist/regen.d.ts +19 -0
- package/dist/regen.d.ts.map +1 -0
- package/dist/regen.js +35 -0
- package/dist/regen.js.map +1 -0
- package/dist/remote-client.d.ts +107 -2
- package/dist/remote-client.d.ts.map +1 -1
- package/dist/remote-client.js +141 -11
- package/dist/remote-client.js.map +1 -1
- package/dist/setup.js +43 -36
- package/dist/setup.js.map +1 -1
- package/dist/sync.js +1 -1
- package/dist/sync.js.map +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* borg-log-audit
|
|
4
|
+
*
|
|
5
|
+
* Domain-agnostic nudge: scans the Claude Code transcript and emits a
|
|
6
|
+
* one-line warning to stdout if the drone has accumulated MATERIAL_THRESHOLD
|
|
7
|
+
* or more state-changing tool calls (Edit / Write / Bash / etc.) since the
|
|
8
|
+
* last borg:log post. Wired in as a UserPromptSubmit hook so the warning
|
|
9
|
+
* becomes additional context for the next turn.
|
|
10
|
+
*
|
|
11
|
+
* Two refinements vs the v1 1-tool threshold (per drone-6's review):
|
|
12
|
+
* 1. Counts material tools across all assistant turns until either the
|
|
13
|
+
* threshold is hit OR a borg:log call is found (cooldown). One
|
|
14
|
+
* diagnostic Bash no longer triggers; substantive work always does.
|
|
15
|
+
* 2. Any borg:log in the scanback suppresses the nudge — so the drone
|
|
16
|
+
* gets a turn of breathing room after each post.
|
|
17
|
+
*
|
|
18
|
+
* Stays generic — knows nothing about git, branches, or any project's
|
|
19
|
+
* conventions. Only the Anthropic tool name `mcp__borg__borg_log` and a
|
|
20
|
+
* small set of canonical mutating tool names. If no cube is active in
|
|
21
|
+
* this project, silently exits.
|
|
22
|
+
*
|
|
23
|
+
* Hook input arrives as JSON on stdin (Claude Code's standard hook
|
|
24
|
+
* contract). The relevant field is `transcript_path`.
|
|
25
|
+
*/
|
|
26
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
27
|
+
import { getActiveCube } from './cubes.js';
|
|
28
|
+
const MATERIAL_TOOLS = new Set([
|
|
29
|
+
'Edit',
|
|
30
|
+
'Write',
|
|
31
|
+
'MultiEdit',
|
|
32
|
+
'NotebookEdit',
|
|
33
|
+
'Bash',
|
|
34
|
+
]);
|
|
35
|
+
const LOG_TOOL = 'mcp__borg__borg_log';
|
|
36
|
+
// Number of state-changing tool calls since the last borg:log that the
|
|
37
|
+
// drone is allowed before the audit nudges. 1 false-positives on
|
|
38
|
+
// diagnostic Bash (git status, ls, etc.); 3 has been comfortable in
|
|
39
|
+
// dogfooding — any substantive work crosses it within a turn or two.
|
|
40
|
+
const MATERIAL_THRESHOLD = 3;
|
|
41
|
+
// Cap on how many transcript entries we scan backwards before giving up.
|
|
42
|
+
// Sessions with thousands of turns still resolve in milliseconds at this
|
|
43
|
+
// bound, and anything truly old is no longer "the last span the drone
|
|
44
|
+
// failed to log."
|
|
45
|
+
const MAX_SCAN = 400;
|
|
46
|
+
function isUserPrompt(entry) {
|
|
47
|
+
const type = entry?.type ?? entry?.role;
|
|
48
|
+
if (type !== 'user')
|
|
49
|
+
return false;
|
|
50
|
+
const content = entry?.message?.content ?? entry?.content;
|
|
51
|
+
if (typeof content === 'string')
|
|
52
|
+
return content.trim().length > 0;
|
|
53
|
+
if (!Array.isArray(content))
|
|
54
|
+
return false;
|
|
55
|
+
// A "real" user prompt has at least one text block. A tool_result-only
|
|
56
|
+
// user message is a continuation of an assistant span, not a prompt.
|
|
57
|
+
return content.some((b) => b?.type === 'text');
|
|
58
|
+
}
|
|
59
|
+
function isAssistant(entry) {
|
|
60
|
+
const type = entry?.type ?? entry?.role;
|
|
61
|
+
return type === 'assistant';
|
|
62
|
+
}
|
|
63
|
+
function scanAssistant(entry, state) {
|
|
64
|
+
const content = entry?.message?.content ?? entry?.content ?? [];
|
|
65
|
+
if (!Array.isArray(content))
|
|
66
|
+
return;
|
|
67
|
+
// Walk the blocks newest-first WITHIN the entry. The caller already
|
|
68
|
+
// visits entries newest-first. Counting forward within an entry would
|
|
69
|
+
// either miss post-log material work (if log is in the same entry as
|
|
70
|
+
// later material blocks) or inflate the count with pre-log work that
|
|
71
|
+
// the log already covered. Reversing here keeps "material since the
|
|
72
|
+
// last log" honest at block granularity.
|
|
73
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
74
|
+
const block = content[i];
|
|
75
|
+
if (block?.type !== 'tool_use')
|
|
76
|
+
continue;
|
|
77
|
+
if (block.name === LOG_TOOL) {
|
|
78
|
+
state.loggedRecently = true;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (MATERIAL_TOOLS.has(block.name))
|
|
82
|
+
state.material += 1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function readStdin() {
|
|
86
|
+
if (process.stdin.isTTY)
|
|
87
|
+
return '';
|
|
88
|
+
const chunks = [];
|
|
89
|
+
for await (const chunk of process.stdin)
|
|
90
|
+
chunks.push(chunk);
|
|
91
|
+
return Buffer.concat(chunks).toString('utf-8');
|
|
92
|
+
}
|
|
93
|
+
async function main() {
|
|
94
|
+
const raw = await readStdin();
|
|
95
|
+
let input = {};
|
|
96
|
+
if (raw.trim()) {
|
|
97
|
+
try {
|
|
98
|
+
input = JSON.parse(raw);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// No usable input — silent exit.
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (!input.transcript_path || !existsSync(input.transcript_path))
|
|
106
|
+
return;
|
|
107
|
+
// Only nudge if there's an active cube in this project. Otherwise the
|
|
108
|
+
// hook is fully inert.
|
|
109
|
+
const active = await getActiveCube();
|
|
110
|
+
if (!active)
|
|
111
|
+
return;
|
|
112
|
+
const lines = readFileSync(input.transcript_path, 'utf-8').split('\n').filter(Boolean);
|
|
113
|
+
if (lines.length === 0)
|
|
114
|
+
return;
|
|
115
|
+
// Walk the transcript backwards from the end. The trailing entry MAY
|
|
116
|
+
// be the user prompt that triggered this hook; skip it if so. From
|
|
117
|
+
// there, accumulate material tool calls until either we hit a borg:log
|
|
118
|
+
// (cooldown — suppress) or we cross MATERIAL_THRESHOLD (nudge). The
|
|
119
|
+
// scan stops after MAX_SCAN entries to bound work on huge sessions.
|
|
120
|
+
let i = lines.length - 1;
|
|
121
|
+
const tail = safeParse(lines[i]);
|
|
122
|
+
if (tail && isUserPrompt(tail))
|
|
123
|
+
i--;
|
|
124
|
+
const state = { material: 0, loggedRecently: false };
|
|
125
|
+
let scanned = 0;
|
|
126
|
+
for (; i >= 0 && scanned < MAX_SCAN; i--, scanned++) {
|
|
127
|
+
const entry = safeParse(lines[i]);
|
|
128
|
+
if (!entry)
|
|
129
|
+
continue;
|
|
130
|
+
if (isAssistant(entry)) {
|
|
131
|
+
scanAssistant(entry, state);
|
|
132
|
+
// Threshold has primacy over cooldown: when both could fire on the
|
|
133
|
+
// same entry (e.g. an entry containing [log, Bash, Bash, Bash]
|
|
134
|
+
// where the reversed scan first counts 3 material blocks before
|
|
135
|
+
// hitting the log), we want the nudge — the post-log material
|
|
136
|
+
// work hasn't been logged yet.
|
|
137
|
+
if (state.material >= MATERIAL_THRESHOLD) {
|
|
138
|
+
process.stdout.write(`Heads up: ${state.material}+ state-changing tool calls since the last \`borg:log\` post. ` +
|
|
139
|
+
'If that work was a substantive unit (a change that ships, a blocker hit, a finding ' +
|
|
140
|
+
"worth sharing), post to the cube log per your role's conventions before continuing.\n");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (state.loggedRecently)
|
|
144
|
+
return; // cooldown
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Reached MAX_SCAN or start of transcript without finding either a
|
|
148
|
+
// log call or enough material work. Silent.
|
|
149
|
+
}
|
|
150
|
+
function safeParse(line) {
|
|
151
|
+
try {
|
|
152
|
+
return JSON.parse(line);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
main().catch(() => {
|
|
159
|
+
// Never fail a hook — silent on error.
|
|
160
|
+
});
|
|
161
|
+
//# sourceMappingURL=log-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-audit.js","sourceRoot":"","sources":["../src/log-audit.ts"],"names":[],"mappings":"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"}
|
package/dist/postinstall.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postinstall.d.ts","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":";AACA;;;;GAIG
|
|
1
|
+
{"version":3,"file":"postinstall.d.ts","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":";AACA;;;;GAIG"}
|
package/dist/postinstall.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
2
|
/**
|
|
4
3
|
* Post-install script
|
|
5
4
|
*
|
|
@@ -8,7 +7,7 @@
|
|
|
8
7
|
// Check if this is a local install (npm_config_global is not set)
|
|
9
8
|
const isGlobal = process.env.npm_config_global === 'true';
|
|
10
9
|
if (!isGlobal) {
|
|
11
|
-
console.error('\n
|
|
10
|
+
console.error('\n◼ Error: borg must be installed globally\n');
|
|
12
11
|
console.error('Please install with:');
|
|
13
12
|
console.error(' npm install -g borg@beta\n');
|
|
14
13
|
console.error('Local installation is not supported.\n');
|
|
@@ -16,8 +15,9 @@ if (!isGlobal) {
|
|
|
16
15
|
}
|
|
17
16
|
// Global install - show instructions
|
|
18
17
|
console.log('\n╔════════════════════════════════════╗');
|
|
19
|
-
console.log('║
|
|
18
|
+
console.log('║ ◼ Borg MCP Installed ◼ ║');
|
|
20
19
|
console.log('╚════════════════════════════════════╝\n');
|
|
21
20
|
console.log('Next step:');
|
|
22
|
-
console.log(' borg
|
|
21
|
+
console.log(' borg-setup\n');
|
|
22
|
+
export {};
|
|
23
23
|
//# sourceMappingURL=postinstall.js.map
|
package/dist/postinstall.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postinstall.js","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"postinstall.js","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH,kEAAkE;AAClE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM,CAAC;AAE1D,IAAI,CAAC,QAAQ,EAAE,CAAC;IACd,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAC9D,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACtC,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAC9C,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,qCAAqC;AACrC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AACxD,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;AACtD,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AACxD,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAC1B,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatting helpers used by both the MCP `borg:regen` handler in
|
|
3
|
+
* index.ts and the standalone `borg-regen` CLI in regen.ts.
|
|
4
|
+
*
|
|
5
|
+
* Lives in its own module so regen.ts can import these without pulling in
|
|
6
|
+
* index.ts's stdio MCP server bootstrap.
|
|
7
|
+
*/
|
|
8
|
+
export type DroneMode = 'autonomous' | 'supervised';
|
|
9
|
+
/**
|
|
10
|
+
* Read the drone mode from the BORG_MODE environment variable.
|
|
11
|
+
* Defaults to "supervised" — the typical Claude Code session where a
|
|
12
|
+
* human is available to escalate to.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getDroneMode(): DroneMode;
|
|
15
|
+
/**
|
|
16
|
+
* Build the drone playbook for the given mode.
|
|
17
|
+
*
|
|
18
|
+
* The playbook is appended to every regen / cube / assimilate response.
|
|
19
|
+
* Including it on every refresh is intentional: it protects against
|
|
20
|
+
* /compact and /clear losing the procedural knowledge while state still
|
|
21
|
+
* flows through.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getDronePlaybook(mode?: DroneMode): string;
|
|
24
|
+
/**
|
|
25
|
+
* Backward-compatible export. Kept as the supervised-mode playbook for
|
|
26
|
+
* any caller that hasn't been updated to pass mode explicitly.
|
|
27
|
+
*/
|
|
28
|
+
export declare const DRONE_PLAYBOOK: string;
|
|
29
|
+
/**
|
|
30
|
+
* Format an absolute timestamp as a coarse "Xs/Xm/Xh ago" string.
|
|
31
|
+
*/
|
|
32
|
+
export declare function humanAgo(date: Date | string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Format a regen() composite into the markdown text shown to drones.
|
|
35
|
+
*
|
|
36
|
+
* The playbook is always appended. The token cost is bounded (~500 tokens),
|
|
37
|
+
* but the risk of a drone losing the playbook to /compact or /clear and
|
|
38
|
+
* being left with state but no procedural knowledge is unbounded. Always
|
|
39
|
+
* include — robustness wins.
|
|
40
|
+
*
|
|
41
|
+
* Mode controls which playbook variant is rendered (supervised vs
|
|
42
|
+
* autonomous). Mode is also surfaced in the header so the drone can
|
|
43
|
+
* see at a glance whether it should escalate to the user or not.
|
|
44
|
+
*/
|
|
45
|
+
export declare function formatRegenMarkdown(result: {
|
|
46
|
+
cube: any;
|
|
47
|
+
role: any;
|
|
48
|
+
drone: any;
|
|
49
|
+
roles: any[];
|
|
50
|
+
drones: any[];
|
|
51
|
+
recentLog: any[];
|
|
52
|
+
}, mode?: DroneMode): string;
|
|
53
|
+
//# sourceMappingURL=regen-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regen-format.d.ts","sourceRoot":"","sources":["../src/regen-format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,YAAY,CAAC;AAEpD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAExC;AAwBD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,SAAwB,GAAG,MAAM,CAqCvE;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAiC,CAAC;AAE7D;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAYpD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE;IACN,IAAI,EAAE,GAAG,CAAC;IACV,IAAI,EAAE,GAAG,CAAC;IACV,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,MAAM,EAAE,GAAG,EAAE,CAAC;IACd,SAAS,EAAE,GAAG,EAAE,CAAC;CAClB,EACD,IAAI,GAAE,SAAwB,GAC7B,MAAM,CAoDR"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatting helpers used by both the MCP `borg:regen` handler in
|
|
3
|
+
* index.ts and the standalone `borg-regen` CLI in regen.ts.
|
|
4
|
+
*
|
|
5
|
+
* Lives in its own module so regen.ts can import these without pulling in
|
|
6
|
+
* index.ts's stdio MCP server bootstrap.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Read the drone mode from the BORG_MODE environment variable.
|
|
10
|
+
* Defaults to "supervised" — the typical Claude Code session where a
|
|
11
|
+
* human is available to escalate to.
|
|
12
|
+
*/
|
|
13
|
+
export function getDroneMode() {
|
|
14
|
+
return process.env.BORG_MODE === 'autonomous' ? 'autonomous' : 'supervised';
|
|
15
|
+
}
|
|
16
|
+
function operatingPrinciple(mode) {
|
|
17
|
+
if (mode === 'autonomous') {
|
|
18
|
+
return `**Default operating principle: act autonomously, never wait for the user.**
|
|
19
|
+
|
|
20
|
+
You are part of a coordinating hive, running unattended in a background shell. There is no human watching this session. When you need input, post your question to the log and continue with other actionable work — other drones will respond. Never wait for user input. If your role's playbook says to ask the user, post the question to the log instead and let a supervised drone relay it.`;
|
|
21
|
+
}
|
|
22
|
+
return `**Default operating principle: consult drones first, escalate to user if the swarm can't resolve.**
|
|
23
|
+
|
|
24
|
+
You are part of a coordinating hive with a human supervisor available. Don't burden the user with questions other drones can answer. When you need input, post your question to the log and continue with whatever else is actionable — other drones will respond. Only escalate to the user if the swarm can't agree, or if no drone has the needed knowledge, or if your role's playbook explicitly directs you to.`;
|
|
25
|
+
}
|
|
26
|
+
function stuckGuidance(mode) {
|
|
27
|
+
if (mode === 'autonomous') {
|
|
28
|
+
return `**When stuck:**
|
|
29
|
+
|
|
30
|
+
Post your question or blocker to the log per your role's conventions. Continue with other actionable work in the meantime. Never wait for user input — there is no user watching this session.`;
|
|
31
|
+
}
|
|
32
|
+
return `**When stuck:**
|
|
33
|
+
|
|
34
|
+
Post your question or blocker to the log per your role's conventions. Continue with other actionable work in the meantime. If the swarm can't resolve the issue after a reasonable wait, escalate to the user.`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the drone playbook for the given mode.
|
|
38
|
+
*
|
|
39
|
+
* The playbook is appended to every regen / cube / assimilate response.
|
|
40
|
+
* Including it on every refresh is intentional: it protects against
|
|
41
|
+
* /compact and /clear losing the procedural knowledge while state still
|
|
42
|
+
* flows through.
|
|
43
|
+
*/
|
|
44
|
+
export function getDronePlaybook(mode = 'supervised') {
|
|
45
|
+
return `## How to operate as a Drone
|
|
46
|
+
|
|
47
|
+
You're a Drone connected to a Cube. Other drones may be working in the same cube — coordinate through the shared activity log.
|
|
48
|
+
|
|
49
|
+
**Tools available to you:**
|
|
50
|
+
- \`borg:regen\` — refresh full state (cube rules, role, roster, recent log) in one call
|
|
51
|
+
- \`borg:cube\` — re-read cube ground rules and the role overview
|
|
52
|
+
- \`borg:role\` — re-read your role's detailed playbook
|
|
53
|
+
- \`borg:roster\` — see who else is connected
|
|
54
|
+
- \`borg:read-log [since] [limit]\` — read recent log entries from all drones
|
|
55
|
+
- \`borg:log <message>\` — append to the shared log
|
|
56
|
+
- \`borg:assimilate <cube>\` — switch to a different cube
|
|
57
|
+
|
|
58
|
+
**How coordination works:**
|
|
59
|
+
|
|
60
|
+
The Cube provides primitives, not workflows. Your role's detailed description (above) is your specific playbook — the conventions and signals it references come from there, not from the system. Different cubes use different conventions. The activity log is the shared coordination channel.
|
|
61
|
+
|
|
62
|
+
${operatingPrinciple(mode)}
|
|
63
|
+
|
|
64
|
+
**Your operating loop:**
|
|
65
|
+
|
|
66
|
+
Each time you receive fresh state (this regen, a tool result, or a user prompt), interpret the recent log (already included in the regen output above) through your role's conventions. Look for:
|
|
67
|
+
- Other drones' questions — answer them if you can
|
|
68
|
+
- Other drones stuck or blocked — help unblock them
|
|
69
|
+
- Pending work you can pick up — claim it per your role's conventions
|
|
70
|
+
- Recent decisions or context affecting how you'd respond
|
|
71
|
+
|
|
72
|
+
If you find an actionable signal, act on it — post the appropriate convention to the log and proceed. Don't wait to be asked.
|
|
73
|
+
|
|
74
|
+
If there's a user prompt waiting, respond to it informed by the cube context. Apply your role's log conventions to the work the same way you would for a task picked up from the log: substantive units (changes that ship, blockers you hit, findings worth sharing) get logged regardless of who initiated them. If nothing's actionable and no prompt is waiting, this iteration is done — wait for the next.
|
|
75
|
+
|
|
76
|
+
${stuckGuidance(mode)}
|
|
77
|
+
|
|
78
|
+
**Posting to the log:**
|
|
79
|
+
|
|
80
|
+
Every time you start a task, finish a task, get stuck, answer another drone, or learn something other drones should know — post to the log per your role's conventions. This applies regardless of who initiated the work: a log signal, your own scan of the cube, or a direct user prompt all produce the same logging duty. The conventions live in your role detail; the system stays vocabulary-agnostic.`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Backward-compatible export. Kept as the supervised-mode playbook for
|
|
84
|
+
* any caller that hasn't been updated to pass mode explicitly.
|
|
85
|
+
*/
|
|
86
|
+
export const DRONE_PLAYBOOK = getDronePlaybook('supervised');
|
|
87
|
+
/**
|
|
88
|
+
* Format an absolute timestamp as a coarse "Xs/Xm/Xh ago" string.
|
|
89
|
+
*/
|
|
90
|
+
export function humanAgo(date) {
|
|
91
|
+
const then = typeof date === 'string' ? new Date(date) : date;
|
|
92
|
+
const ms = Date.now() - then.getTime();
|
|
93
|
+
if (!Number.isFinite(ms) || ms < 0)
|
|
94
|
+
return 'just now';
|
|
95
|
+
const sec = Math.floor(ms / 1000);
|
|
96
|
+
if (sec < 60)
|
|
97
|
+
return `${sec}s ago`;
|
|
98
|
+
const min = Math.floor(sec / 60);
|
|
99
|
+
if (min < 60)
|
|
100
|
+
return `${min}m ago`;
|
|
101
|
+
const hr = Math.floor(min / 60);
|
|
102
|
+
if (hr < 24)
|
|
103
|
+
return `${hr}h ago`;
|
|
104
|
+
const days = Math.floor(hr / 24);
|
|
105
|
+
return `${days}d ago`;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Format a regen() composite into the markdown text shown to drones.
|
|
109
|
+
*
|
|
110
|
+
* The playbook is always appended. The token cost is bounded (~500 tokens),
|
|
111
|
+
* but the risk of a drone losing the playbook to /compact or /clear and
|
|
112
|
+
* being left with state but no procedural knowledge is unbounded. Always
|
|
113
|
+
* include — robustness wins.
|
|
114
|
+
*
|
|
115
|
+
* Mode controls which playbook variant is rendered (supervised vs
|
|
116
|
+
* autonomous). Mode is also surfaced in the header so the drone can
|
|
117
|
+
* see at a glance whether it should escalate to the user or not.
|
|
118
|
+
*/
|
|
119
|
+
export function formatRegenMarkdown(result, mode = 'supervised') {
|
|
120
|
+
const roleOverview = result.roles
|
|
121
|
+
.map((r) => `- **${r.name}**${r.is_default ? ' _(default)_' : ''} — ${r.short_description || '_(no short description)_'}`)
|
|
122
|
+
.join('\n');
|
|
123
|
+
const droneOverview = result.drones
|
|
124
|
+
.map((d) => {
|
|
125
|
+
const role = result.roles.find((r) => r.id === d.role_id);
|
|
126
|
+
return `- **${d.label}** (${role?.name ?? '?'}) — last seen ${humanAgo(new Date(d.last_seen))}`;
|
|
127
|
+
})
|
|
128
|
+
.join('\n') || '_(no drones connected)_';
|
|
129
|
+
const droneById = new Map(result.drones.map((d) => [d.id, d]));
|
|
130
|
+
const roleById = new Map(result.roles.map((r) => [r.id, r]));
|
|
131
|
+
const logEntries = result.recentLog
|
|
132
|
+
.map((e) => {
|
|
133
|
+
const d = droneById.get(e.drone_id);
|
|
134
|
+
const r = d ? roleById.get(d.role_id) : null;
|
|
135
|
+
const ts = new Date(e.created_at).toISOString();
|
|
136
|
+
return `**[${ts}]** ${d?.label ?? '?'} (${r?.name ?? '?'}): ${e.message}`;
|
|
137
|
+
})
|
|
138
|
+
.reverse()
|
|
139
|
+
.join('\n\n') || '_(no activity yet)_';
|
|
140
|
+
return [
|
|
141
|
+
`# Cube: ${result.cube.name} — ${result.drone.label}`,
|
|
142
|
+
'',
|
|
143
|
+
`**Your role:** ${result.role.name}`,
|
|
144
|
+
`**Mode:** ${mode}`,
|
|
145
|
+
'',
|
|
146
|
+
`## Ground rules`,
|
|
147
|
+
result.cube.ground_rules || '_(none)_',
|
|
148
|
+
'',
|
|
149
|
+
`## Your role: ${result.role.name}`,
|
|
150
|
+
result.role.detailed_description || '_(no detailed description set)_',
|
|
151
|
+
'',
|
|
152
|
+
`## Roles in this cube`,
|
|
153
|
+
roleOverview,
|
|
154
|
+
'',
|
|
155
|
+
`## Connected drones`,
|
|
156
|
+
droneOverview,
|
|
157
|
+
'',
|
|
158
|
+
`## Recent activity`,
|
|
159
|
+
logEntries,
|
|
160
|
+
'',
|
|
161
|
+
getDronePlaybook(mode),
|
|
162
|
+
].join('\n');
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=regen-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regen-format.js","sourceRoot":"","sources":["../src/regen-format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;AAC9E,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAe;IACzC,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO;;mYAEwX,CAAC;IAClY,CAAC;IACD,OAAO;;sZAE6Y,CAAC;AACvZ,CAAC;AAED,SAAS,aAAa,CAAC,IAAe;IACpC,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO;;+LAEoL,CAAC;IAC9L,CAAC;IACD,OAAO;;+MAEsM,CAAC;AAChN,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAkB,YAAY;IAC7D,OAAO;;;;;;;;;;;;;;;;;EAiBP,kBAAkB,CAAC,IAAI,CAAC;;;;;;;;;;;;;;EAcxB,aAAa,CAAC,IAAI,CAAC;;;;+YAI0X,CAAC;AAChZ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;AAE7D;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAmB;IAC1C,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IAClC,IAAI,GAAG,GAAG,EAAE;QAAE,OAAO,GAAG,GAAG,OAAO,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;IACjC,IAAI,GAAG,GAAG,EAAE;QAAE,OAAO,GAAG,GAAG,OAAO,CAAC;IACnC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;IAChC,IAAI,EAAE,GAAG,EAAE;QAAE,OAAO,GAAG,EAAE,OAAO,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,OAAO,GAAG,IAAI,OAAO,CAAC;AACxB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAOC,EACD,OAAkB,YAAY;IAE9B,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK;SAC9B,GAAG,CACF,CAAC,CAAM,EAAE,EAAE,CACT,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,iBAAiB,IAAI,0BAA0B,EAAE,CAChH;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,aAAa,GACjB,MAAM,CAAC,MAAM;SACV,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE;QACd,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;QAC/D,OAAO,OAAO,CAAC,CAAC,KAAK,OAAO,IAAI,EAAE,IAAI,IAAI,GAAG,iBAAiB,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;IAClG,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,IAAI,yBAAyB,CAAC;IAE7C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,UAAU,GACd,MAAM,CAAC,SAAS;SACb,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE;QACd,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAQ,CAAC;QAC3C,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAS,CAAC,CAAC,CAAC,IAAI,CAAC;QACtD,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;QAChD,OAAO,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,IAAI,GAAG,KAAK,CAAC,EAAE,IAAI,IAAI,GAAG,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;IAC5E,CAAC,CAAC;SACD,OAAO,EAAE;SACT,IAAI,CAAC,MAAM,CAAC,IAAI,qBAAqB,CAAC;IAE3C,OAAO;QACL,WAAW,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE;QACrD,EAAE;QACF,kBAAkB,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;QACpC,aAAa,IAAI,EAAE;QACnB,EAAE;QACF,iBAAiB;QACjB,MAAM,CAAC,IAAI,CAAC,YAAY,IAAI,UAAU;QACtC,EAAE;QACF,iBAAiB,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;QACnC,MAAM,CAAC,IAAI,CAAC,oBAAoB,IAAI,iCAAiC;QACrE,EAAE;QACF,uBAAuB;QACvB,YAAY;QACZ,EAAE;QACF,qBAAqB;QACrB,aAAa;QACb,EAAE;QACF,oBAAoB;QACpB,UAAU;QACV,EAAE;QACF,gBAAgB,CAAC,IAAI,CAAC;KACvB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
package/dist/regen.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* borg-regen CLI
|
|
4
|
+
*
|
|
5
|
+
* Prints a markdown-formatted regen of the active cube to stdout.
|
|
6
|
+
* Designed to be wired into a Claude Code SessionStart hook so that
|
|
7
|
+
* each new session begins fully oriented to the cube.
|
|
8
|
+
*
|
|
9
|
+
* Behavior:
|
|
10
|
+
* - No active cube: print a friendly notice to stdout, exit 0.
|
|
11
|
+
* (A SessionStart hook should not block session start over a missing
|
|
12
|
+
* cube — the user may not be using Borg in this directory.)
|
|
13
|
+
* - Active cube + success: print regen markdown to stdout, exit 0.
|
|
14
|
+
* - Active cube + HTTP/auth error: print one-line message to stderr,
|
|
15
|
+
* exit non-zero so the hook surfaces the failure but doesn't drown
|
|
16
|
+
* the session in a stack trace.
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=regen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regen.d.ts","sourceRoot":"","sources":["../src/regen.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG"}
|
package/dist/regen.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* borg-regen CLI
|
|
4
|
+
*
|
|
5
|
+
* Prints a markdown-formatted regen of the active cube to stdout.
|
|
6
|
+
* Designed to be wired into a Claude Code SessionStart hook so that
|
|
7
|
+
* each new session begins fully oriented to the cube.
|
|
8
|
+
*
|
|
9
|
+
* Behavior:
|
|
10
|
+
* - No active cube: print a friendly notice to stdout, exit 0.
|
|
11
|
+
* (A SessionStart hook should not block session start over a missing
|
|
12
|
+
* cube — the user may not be using Borg in this directory.)
|
|
13
|
+
* - Active cube + success: print regen markdown to stdout, exit 0.
|
|
14
|
+
* - Active cube + HTTP/auth error: print one-line message to stderr,
|
|
15
|
+
* exit non-zero so the hook surfaces the failure but doesn't drown
|
|
16
|
+
* the session in a stack trace.
|
|
17
|
+
*/
|
|
18
|
+
import { regen } from './remote-client.js';
|
|
19
|
+
import { getActiveCube } from './cubes.js';
|
|
20
|
+
import { formatRegenMarkdown, getDroneMode } from './regen-format.js';
|
|
21
|
+
async function main() {
|
|
22
|
+
const active = await getActiveCube();
|
|
23
|
+
if (!active) {
|
|
24
|
+
process.stdout.write('Not connected to a cube.\n');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const result = await regen(active.sessionToken, active.apiUrl);
|
|
28
|
+
process.stdout.write(formatRegenMarkdown(result, getDroneMode()) + '\n');
|
|
29
|
+
}
|
|
30
|
+
main().catch((error) => {
|
|
31
|
+
const msg = error?.message ?? String(error);
|
|
32
|
+
process.stderr.write(`borg-regen: ${msg}\n`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=regen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regen.js","sourceRoot":"","sources":["../src/regen.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtE,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAC;IACrC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3E,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAU,EAAE,EAAE;IAC1B,MAAM,GAAG,GAAG,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/remote-client.d.ts
CHANGED
|
@@ -8,14 +8,119 @@
|
|
|
8
8
|
* - Offline queue for pending operations
|
|
9
9
|
*/
|
|
10
10
|
import type { RemoteResponse } from './types.js';
|
|
11
|
+
export declare const API_URL: string;
|
|
11
12
|
/**
|
|
12
13
|
* Call remote MCP tool with retry logic
|
|
13
14
|
*/
|
|
14
15
|
export declare function callRemoteTool(toolName: string, args: Record<string, any>): Promise<RemoteResponse>;
|
|
15
16
|
/**
|
|
16
|
-
*
|
|
17
|
+
* Connect this client as a Drone to a Cube.
|
|
18
|
+
*
|
|
19
|
+
* Returns the cube definition, the drone's assigned role (with full
|
|
20
|
+
* detailed_description), the drone record, and an opaque session token
|
|
21
|
+
* the caller is expected to persist via cubes.ts.
|
|
22
|
+
*/
|
|
23
|
+
export declare function assimilate(cubeName: string, apiUrl?: string): Promise<{
|
|
24
|
+
cube: {
|
|
25
|
+
id: string;
|
|
26
|
+
owner_id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
ground_rules: string;
|
|
29
|
+
created_at: string;
|
|
30
|
+
updated_at: string;
|
|
31
|
+
};
|
|
32
|
+
role: {
|
|
33
|
+
id: string;
|
|
34
|
+
cube_id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
short_description: string;
|
|
37
|
+
detailed_description: string;
|
|
38
|
+
is_default: boolean;
|
|
39
|
+
created_at: string;
|
|
40
|
+
};
|
|
41
|
+
drone: {
|
|
42
|
+
id: string;
|
|
43
|
+
cube_id: string;
|
|
44
|
+
role_id: string;
|
|
45
|
+
label: string;
|
|
46
|
+
last_seen: string;
|
|
47
|
+
created_at: string;
|
|
48
|
+
};
|
|
49
|
+
sessionToken: string;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Get the active cube's ground rules + role registry.
|
|
53
|
+
*/
|
|
54
|
+
export declare function getCubeInfo(sessionToken: string, apiUrl: string): Promise<{
|
|
55
|
+
cube: any;
|
|
56
|
+
roles: any[];
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Get this drone's assigned role (with detailed_description).
|
|
60
|
+
*/
|
|
61
|
+
export declare function getRoleInfo(sessionToken: string, apiUrl: string): Promise<{
|
|
62
|
+
role: any;
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* List all currently-connected drones in this cube.
|
|
66
|
+
*/
|
|
67
|
+
export declare function getRoster(sessionToken: string, apiUrl: string): Promise<{
|
|
68
|
+
drones: any[];
|
|
69
|
+
roles: any[];
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Read recent log entries for the cube.
|
|
73
|
+
*/
|
|
74
|
+
export declare function readLog(sessionToken: string, apiUrl: string, opts?: {
|
|
75
|
+
since?: string;
|
|
76
|
+
limit?: number;
|
|
77
|
+
}): Promise<{
|
|
78
|
+
entries: any[];
|
|
79
|
+
drones: any[];
|
|
80
|
+
roles: any[];
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* Regen: one-shot composite of everything a drone needs to be oriented.
|
|
84
|
+
*
|
|
85
|
+
* Returns the active cube's ground rules, the drone's own role with full
|
|
86
|
+
* detailed_description, the public role registry (no detailed_description
|
|
87
|
+
* leakage for OTHER roles), the drone roster, and recent log entries.
|
|
88
|
+
* Use on session start and before each new task to stay in sync.
|
|
89
|
+
*/
|
|
90
|
+
export declare function regen(sessionToken: string, apiUrl: string): Promise<{
|
|
91
|
+
cube: any;
|
|
92
|
+
role: any;
|
|
93
|
+
drone: any;
|
|
94
|
+
roles: any[];
|
|
95
|
+
drones: any[];
|
|
96
|
+
recentLog: any[];
|
|
97
|
+
}>;
|
|
98
|
+
/**
|
|
99
|
+
* Long-poll for new activity in the active cube.
|
|
100
|
+
*
|
|
101
|
+
* The worker holds the request open for up to ~25s while polling the DB
|
|
102
|
+
* for new entries strictly after `since`. Returns immediately as soon as
|
|
103
|
+
* any new entry exists; otherwise returns an empty result on timeout so
|
|
104
|
+
* the caller can re-poll. Used by the client-side inbox poller to wake
|
|
105
|
+
* drones the moment another drone posts to the cube.
|
|
106
|
+
*/
|
|
107
|
+
export declare function waitForActivity(sessionToken: string, apiUrl: string, since?: string): Promise<{
|
|
108
|
+
entries: any[];
|
|
109
|
+
drones: any[];
|
|
110
|
+
roles: any[];
|
|
111
|
+
}>;
|
|
112
|
+
/**
|
|
113
|
+
* Append a message to the cube's shared activity log.
|
|
17
114
|
*/
|
|
18
|
-
export declare function
|
|
115
|
+
export declare function appendLog(sessionToken: string, apiUrl: string, message: string): Promise<{
|
|
116
|
+
entry: {
|
|
117
|
+
id: string;
|
|
118
|
+
cube_id: string;
|
|
119
|
+
drone_id: string;
|
|
120
|
+
message: string;
|
|
121
|
+
created_at: string;
|
|
122
|
+
};
|
|
123
|
+
}>;
|
|
19
124
|
/**
|
|
20
125
|
* Check subscription status
|
|
21
126
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-client.d.ts","sourceRoot":"","sources":["../src/remote-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"remote-client.d.ts","sourceRoot":"","sources":["../src/remote-client.ts"],"names":[],"mappings":"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"}
|