agent-tempo 1.0.1 → 1.2.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/CLAUDE.md +8 -2
- package/dashboard/dist/assets/index-D6Xyje_n.js +62 -0
- package/dashboard/dist/assets/index-D6Xyje_n.js.map +1 -0
- package/dashboard/dist/index.html +1 -1
- package/dashboard/package.json +1 -1
- package/dist/activities/claude-stop.d.ts +21 -0
- package/dist/activities/claude-stop.js +94 -0
- package/dist/cli/commands.d.ts +39 -0
- package/dist/cli/commands.js +83 -2
- package/dist/cli/legacy-migration.js +8 -2
- package/dist/cli/sa-preflight.d.ts +27 -3
- package/dist/cli/sa-preflight.js +169 -9
- package/dist/cli/startup.js +34 -8
- package/dist/client/core.js +9 -0
- package/dist/client/interface.d.ts +21 -0
- package/dist/daemon.js +1 -0
- package/dist/http/catalog.js +17 -3
- package/dist/http/event-types.d.ts +41 -0
- package/dist/http/orphans.d.ts +76 -0
- package/dist/http/orphans.js +93 -0
- package/dist/http/server.js +13 -0
- package/dist/reconcile/orphans.d.ts +37 -27
- package/dist/reconcile/orphans.js +93 -6
- package/dist/tui/index.js +1 -0
- package/dist/utils/bg-preflight.d.ts +25 -0
- package/dist/utils/bg-preflight.js +154 -0
- package/package.json +5 -4
- package/dashboard/dist/assets/index-_5jV0Znu.js +0 -62
- package/dashboard/dist/assets/index-_5jV0Znu.js.map +0 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.__resetBgPreflightCacheForTests = __resetBgPreflightCacheForTests;
|
|
37
|
+
exports.bgPreflight = bgPreflight;
|
|
38
|
+
/**
|
|
39
|
+
* #596 / ADR 0016 — permission preflight for `claude --bg`.
|
|
40
|
+
*
|
|
41
|
+
* Anthropic's per-user supervisor refuses bypass modes
|
|
42
|
+
* (`--dangerously-skip-permissions`) that were never accepted interactively
|
|
43
|
+
* in the target cwd. The bypass-consent record is NOT transparently readable
|
|
44
|
+
* on disk (not in `~/.claude/settings*.json`, not in
|
|
45
|
+
* `~/.claude/projects/<encoded-cwd>/`), so a behavioral probe is the most
|
|
46
|
+
* robust signal.
|
|
47
|
+
*
|
|
48
|
+
* **Surprise observed during live E2E** (documented for ADR follow-up):
|
|
49
|
+
* `claude --bg --dangerously-skip-permissions --help` does NOT short-circuit
|
|
50
|
+
* on `--help` — the supervisor adopts the session FIRST then processes the
|
|
51
|
+
* help flag. So a "dry-run" probe actually creates a real supervisor job
|
|
52
|
+
* (prints `backgrounded · <shortId> (idle …)` and exits 0). The probe is
|
|
53
|
+
* still our most reliable acceptance signal — we just have to immediately
|
|
54
|
+
* `claude stop <shortId>` the session we created so the probe is truly
|
|
55
|
+
* side-effect-free from the operator's perspective. Cache hits skip
|
|
56
|
+
* probe+stop entirely.
|
|
57
|
+
*
|
|
58
|
+
* Result is cached per `(host, cwd)` in an in-process `Map` for the
|
|
59
|
+
* daemon's lifetime — once a daemon has confirmed a cwd is ok, subsequent
|
|
60
|
+
* recruits in that cwd skip the probe. On failure we surface an actionable
|
|
61
|
+
* error string the recruit activity logs and rethrows.
|
|
62
|
+
*
|
|
63
|
+
* Cache invalidates on daemon restart (the user might have accepted in the
|
|
64
|
+
* intervening time) — `__resetBgPreflightCacheForTests` exists for unit
|
|
65
|
+
* coverage. Production code never invalidates the cache directly.
|
|
66
|
+
*/
|
|
67
|
+
const child_process_1 = require("child_process");
|
|
68
|
+
const os = __importStar(require("os"));
|
|
69
|
+
const spawn_1 = require("../spawn");
|
|
70
|
+
const log = (...args) => console.error('[agent-tempo:bg-preflight]', ...args);
|
|
71
|
+
const cache = new Map();
|
|
72
|
+
function cacheKey(k) {
|
|
73
|
+
return `${k.host}:::${k.cwd}`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Test hook — never call from production code. Convention per
|
|
77
|
+
* `docs/adr/0006-test-hooks-naming.md`.
|
|
78
|
+
*/
|
|
79
|
+
function __resetBgPreflightCacheForTests() {
|
|
80
|
+
cache.clear();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Probe whether `claude --bg` can spawn in the given cwd without prompting
|
|
84
|
+
* the operator for permission acceptance. First call probes; subsequent
|
|
85
|
+
* calls for the same `(host, cwd)` hit the in-process cache.
|
|
86
|
+
*
|
|
87
|
+
* Returns `{ ok: true }` when the dry-run succeeded (exit 0). On any other
|
|
88
|
+
* exit code (or spawn-side ENOENT), returns `{ ok: false, error: ... }`
|
|
89
|
+
* with an actionable message. Never throws — callers handle the result.
|
|
90
|
+
*/
|
|
91
|
+
function bgPreflight(cwd, options) {
|
|
92
|
+
const host = options?.host ?? os.hostname();
|
|
93
|
+
const key = cacheKey({ host, cwd });
|
|
94
|
+
if (cache.has(key)) {
|
|
95
|
+
return { ok: true, cached: true };
|
|
96
|
+
}
|
|
97
|
+
const claudeBin = (0, spawn_1.resolveClaudePath)(options?.claudeBin);
|
|
98
|
+
// Dry-run: `--help` exits immediately without spawning a real session.
|
|
99
|
+
// Bypass-permissions flag triggers the supervisor's accept-consent check,
|
|
100
|
+
// which is the behavior we actually want to verify.
|
|
101
|
+
let result;
|
|
102
|
+
try {
|
|
103
|
+
result = (0, child_process_1.spawnSync)(claudeBin, ['--bg', '--dangerously-skip-permissions', '--help'], {
|
|
104
|
+
cwd,
|
|
105
|
+
encoding: 'utf8',
|
|
106
|
+
timeout: 15_000,
|
|
107
|
+
shell: process.platform === 'win32',
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
112
|
+
const error = `claude --bg preflight failed to launch (${msg}). Run 'claude' once in ${cwd} and accept the permission dialog, then retry recruit.`;
|
|
113
|
+
log(error);
|
|
114
|
+
return { ok: false, error, cached: false };
|
|
115
|
+
}
|
|
116
|
+
if (result.error) {
|
|
117
|
+
const error = `claude --bg preflight failed to launch (${result.error.message}). Run 'claude' once in ${cwd} and accept the permission dialog, then retry recruit.`;
|
|
118
|
+
log(error);
|
|
119
|
+
return { ok: false, error, cached: false };
|
|
120
|
+
}
|
|
121
|
+
if (result.status === 0) {
|
|
122
|
+
// The probe spawned a real supervisor job — clean it up immediately so
|
|
123
|
+
// the operator never sees a leaked `idle` session in `claude agents`.
|
|
124
|
+
// Stdout format observed: `backgrounded · <shortId> (idle — send a prompt to start)`
|
|
125
|
+
const stdoutCombined = (result.stdout || '').toString();
|
|
126
|
+
const shortIdMatch = stdoutCombined.match(/backgrounded\s*[·•]\s*([0-9a-f]{8})/i);
|
|
127
|
+
if (shortIdMatch) {
|
|
128
|
+
const probeShortId = shortIdMatch[1];
|
|
129
|
+
try {
|
|
130
|
+
(0, child_process_1.spawnSync)(claudeBin, ['stop', probeShortId], {
|
|
131
|
+
cwd,
|
|
132
|
+
encoding: 'utf8',
|
|
133
|
+
timeout: 10_000,
|
|
134
|
+
shell: process.platform === 'win32',
|
|
135
|
+
});
|
|
136
|
+
log(`probe stopped its own session ${probeShortId} in ${cwd}`);
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
log(`probe-cleanup warning: failed to stop ${probeShortId} (${err instanceof Error ? err.message : String(err)}); operator may see an idle 'agents' row`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
log(`probe in ${cwd} exit 0 but no shortId in stdout — supervisor surface may have changed; not stopping anything`);
|
|
144
|
+
}
|
|
145
|
+
cache.set(key, true);
|
|
146
|
+
return { ok: true, cached: false };
|
|
147
|
+
}
|
|
148
|
+
const stderr = (result.stderr || '').trim();
|
|
149
|
+
const stdout = (result.stdout || '').trim();
|
|
150
|
+
const detail = stderr || stdout || `exit ${result.status}`;
|
|
151
|
+
const error = `claude --bg preflight rejected in ${cwd} (${detail}). Run 'claude' once in ${cwd} and accept the permission dialog, then retry recruit.`;
|
|
152
|
+
log(error);
|
|
153
|
+
return { ok: false, error, cached: false };
|
|
154
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-tempo",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Many agents, one tempo. Durable coordination for multi-agent work via Temporal.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -92,6 +92,8 @@
|
|
|
92
92
|
"@modelcontextprotocol/sdk": "~1.28.0",
|
|
93
93
|
"@temporalio/activity": "~1.15.0",
|
|
94
94
|
"@temporalio/client": "~1.15.0",
|
|
95
|
+
"@temporalio/common": "~1.15.0",
|
|
96
|
+
"@temporalio/proto": "~1.15.0",
|
|
95
97
|
"@temporalio/worker": "~1.15.0",
|
|
96
98
|
"@temporalio/workflow": "~1.15.0",
|
|
97
99
|
"croner": "^10.0.1",
|
|
@@ -107,7 +109,6 @@
|
|
|
107
109
|
},
|
|
108
110
|
"devDependencies": {
|
|
109
111
|
"@size-limit/preset-app": "^12.1.0",
|
|
110
|
-
"@temporalio/common": "^1.15.0",
|
|
111
112
|
"@temporalio/testing": "~1.15.0",
|
|
112
113
|
"@types/chai": "^4.3.20",
|
|
113
114
|
"@types/mocha": "^10.0.10",
|
|
@@ -160,7 +161,6 @@
|
|
|
160
161
|
"engines": {
|
|
161
162
|
"node": ">=20"
|
|
162
163
|
},
|
|
163
|
-
"packageManager": "npm@10.9.2",
|
|
164
164
|
"license": "MIT",
|
|
165
165
|
"trustedDependencies": [
|
|
166
166
|
"@swc/core",
|
|
@@ -168,5 +168,6 @@
|
|
|
168
168
|
],
|
|
169
169
|
"overrides": {
|
|
170
170
|
"rxjs": "^7.8.1"
|
|
171
|
-
}
|
|
171
|
+
},
|
|
172
|
+
"packageManager": "npm@10.9.2"
|
|
172
173
|
}
|