@achieveai/hitl-mcp-server 2.9.6 → 2.11.2
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/dist/cli.d.ts +31 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +133 -5
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/git-context.d.ts +53 -2
- package/dist/git-context.d.ts.map +1 -1
- package/dist/git-context.js +118 -18
- package/dist/git-context.js.map +1 -1
- package/dist/host-settings.d.ts +68 -0
- package/dist/host-settings.d.ts.map +1 -0
- package/dist/host-settings.js +136 -0
- package/dist/host-settings.js.map +1 -0
- package/dist/identity.d.ts +20 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +35 -0
- package/dist/identity.js.map +1 -0
- package/dist/mcp-server.d.ts +65 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +446 -65
- package/dist/mcp-server.js.map +1 -1
- package/dist/ntfy-transport.d.ts +293 -13
- package/dist/ntfy-transport.d.ts.map +1 -1
- package/dist/ntfy-transport.js +765 -88
- package/dist/ntfy-transport.js.map +1 -1
- package/dist/payload.d.ts +80 -0
- package/dist/payload.d.ts.map +1 -0
- package/dist/payload.js +135 -0
- package/dist/payload.js.map +1 -0
- package/dist/plan-diff.d.ts +29 -0
- package/dist/plan-diff.d.ts.map +1 -0
- package/dist/plan-diff.js +138 -0
- package/dist/plan-diff.js.map +1 -0
- package/dist/plan-file.d.ts +24 -0
- package/dist/plan-file.d.ts.map +1 -0
- package/dist/plan-file.js +98 -0
- package/dist/plan-file.js.map +1 -0
- package/dist/plan-review.d.ts +54 -0
- package/dist/plan-review.d.ts.map +1 -0
- package/dist/plan-review.js +110 -0
- package/dist/plan-review.js.map +1 -0
- package/dist/setup.d.ts +22 -5
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +52 -15
- package/dist/setup.js.map +1 -1
- package/dist/snapshot-store.d.ts +104 -0
- package/dist/snapshot-store.d.ts.map +1 -0
- package/dist/snapshot-store.js +209 -0
- package/dist/snapshot-store.js.map +1 -0
- package/dist/types.d.ts +144 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +13 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +15 -0
- package/dist/version.js.map +1 -0
- package/package.json +64 -61
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'crypto';
|
|
2
|
+
import { mkdirSync, readFileSync, writeFileSync, renameSync, existsSync, unlinkSync } from 'fs';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { resolveRepoRoot, normalizePath, toRepoRelative } from './git-context.js';
|
|
6
|
+
/** Root of the snapshot store. Overridable so tests never touch a real home dir. */
|
|
7
|
+
export function getPlansRoot() {
|
|
8
|
+
return path.join(process.env.HITL_HOME ?? path.join(homedir(), '.hitl'), 'plans');
|
|
9
|
+
}
|
|
10
|
+
const DIR_MODE = 0o700;
|
|
11
|
+
const FILE_MODE = 0o600;
|
|
12
|
+
function sha256Hex(value) {
|
|
13
|
+
return createHash('sha256').update(value, 'utf8').digest('hex');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Locate a plan file's history directory and its display name.
|
|
17
|
+
*
|
|
18
|
+
* Identity is keyed on the repo root when there is one, else on the containing
|
|
19
|
+
* directory — so the same relative path in two different repos gets two
|
|
20
|
+
* identities (B-7), while two spellings of one Windows path collapse to one
|
|
21
|
+
* (B-10). Git is resolved from the plan's own directory, never `process.cwd()`,
|
|
22
|
+
* because the plan usually lives in a sibling repo (B-6).
|
|
23
|
+
*/
|
|
24
|
+
export function resolvePlanIdentity(resolvedPath) {
|
|
25
|
+
const normalizedPath = normalizePath(resolvedPath);
|
|
26
|
+
const dirName = path.dirname(resolvedPath);
|
|
27
|
+
const repoRoot = resolveRepoRoot(dirName);
|
|
28
|
+
const identityKey = repoRoot ?? normalizePath(dirName);
|
|
29
|
+
const identityHash = sha256Hex(identityKey);
|
|
30
|
+
const pathHash = sha256Hex(normalizedPath);
|
|
31
|
+
return {
|
|
32
|
+
planId: sha256Hex(`${identityHash}:${pathHash}`),
|
|
33
|
+
dir: path.join(getPlansRoot(), identityHash, pathHash),
|
|
34
|
+
displayPath: repoRoot ? toRepoRelative(repoRoot, resolvedPath) : path.basename(resolvedPath),
|
|
35
|
+
repoRoot,
|
|
36
|
+
resolvedPath,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Validate a raw `latest.json` body before anything trusts it.
|
|
41
|
+
*
|
|
42
|
+
* Returns null — never a partially-trusted object — when the digest is not 64
|
|
43
|
+
* lowercase hex, the revision is not a positive integer, `createdAt` is zero,
|
|
44
|
+
* or the recorded `displayPath` names a different file than the one being
|
|
45
|
+
* reviewed. A rejected pointer degrades to "no history", which restarts the
|
|
46
|
+
* revision count rather than diffing against something unverified.
|
|
47
|
+
*/
|
|
48
|
+
export function parseLatest(raw, expectedDisplayPath) {
|
|
49
|
+
let parsed;
|
|
50
|
+
try {
|
|
51
|
+
parsed = JSON.parse(raw);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
57
|
+
return null;
|
|
58
|
+
const { displayPath, digest, revision, createdAt } = parsed;
|
|
59
|
+
if (typeof digest !== 'string' || !/^[0-9a-f]{64}$/.test(digest))
|
|
60
|
+
return null;
|
|
61
|
+
if (typeof revision !== 'number' || !Number.isInteger(revision) || revision < 1)
|
|
62
|
+
return null;
|
|
63
|
+
if (typeof createdAt !== 'number' || createdAt <= 0)
|
|
64
|
+
return null;
|
|
65
|
+
if (typeof displayPath !== 'string' || displayPath !== expectedDisplayPath)
|
|
66
|
+
return null;
|
|
67
|
+
return { displayPath, digest, revision, createdAt };
|
|
68
|
+
}
|
|
69
|
+
/** Read and validate `latest.json`, or null when absent or untrustworthy. */
|
|
70
|
+
export function readLatest(identity) {
|
|
71
|
+
const file = path.join(identity.dir, 'latest.json');
|
|
72
|
+
if (!existsSync(file))
|
|
73
|
+
return null;
|
|
74
|
+
try {
|
|
75
|
+
return parseLatest(readFileSync(file, 'utf8'), identity.displayPath);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Read a stored revision by digest, or null when the object is missing. */
|
|
82
|
+
export function readObject(identity, digest) {
|
|
83
|
+
const file = path.join(identity.dir, 'objects', digest);
|
|
84
|
+
if (!existsSync(file))
|
|
85
|
+
return null;
|
|
86
|
+
try {
|
|
87
|
+
return readFileSync(file, 'utf8');
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Stage `content` as the next revision of this plan.
|
|
95
|
+
*
|
|
96
|
+
* Byte-identical content still advances the revision: a resubmit is a distinct
|
|
97
|
+
* review event, and the human must still be able to select every line of an
|
|
98
|
+
* unchanged plan (B-3).
|
|
99
|
+
*
|
|
100
|
+
* The pointer flip is deliberately a separate step. `latest.json` is what the
|
|
101
|
+
* next review diffs against, so writing it before the plan has actually reached
|
|
102
|
+
* the human means a failed publish silently rebases the next review onto a
|
|
103
|
+
* revision nobody ever saw — the change the human was meant to review vanishes
|
|
104
|
+
* from the diff (M6). Callers commit once the revision is out the door.
|
|
105
|
+
*
|
|
106
|
+
* The object is written either way; it is content-addressed and immutable, so
|
|
107
|
+
* an uncommitted one costs a few KB of orphaned disk and nothing else.
|
|
108
|
+
*/
|
|
109
|
+
export function prepareRevision(identity, content) {
|
|
110
|
+
mkdirSync(path.join(identity.dir, 'objects'), { recursive: true, mode: DIR_MODE });
|
|
111
|
+
// The client writes drafts here; the directory is part of the layout either way.
|
|
112
|
+
mkdirSync(path.join(identity.dir, 'drafts'), { recursive: true, mode: DIR_MODE });
|
|
113
|
+
const previous = readLatest(identity);
|
|
114
|
+
const previousContent = previous ? readObject(identity, previous.digest) : null;
|
|
115
|
+
const digest = sha256Hex(content);
|
|
116
|
+
const objectFile = path.join(identity.dir, 'objects', digest);
|
|
117
|
+
if (!existsSync(objectFile)) {
|
|
118
|
+
writeAtomic(objectFile, content);
|
|
119
|
+
}
|
|
120
|
+
const record = {
|
|
121
|
+
revision: (previous?.revision ?? 0) + 1,
|
|
122
|
+
digest,
|
|
123
|
+
isNewPlan: previous === null,
|
|
124
|
+
previous,
|
|
125
|
+
previousContent,
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
...record,
|
|
129
|
+
commit() {
|
|
130
|
+
const meta = {
|
|
131
|
+
displayPath: identity.displayPath,
|
|
132
|
+
digest,
|
|
133
|
+
revision: record.revision,
|
|
134
|
+
createdAt: Date.now(),
|
|
135
|
+
};
|
|
136
|
+
writeAtomic(path.join(identity.dir, 'latest.json'), JSON.stringify(meta, null, 2) + '\n');
|
|
137
|
+
return record;
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Write via a temp file in the same directory, then rename over the target.
|
|
143
|
+
*
|
|
144
|
+
* `renameSync` maps to MoveFileEx with MOVEFILE_REPLACE_EXISTING on Windows, so
|
|
145
|
+
* replacing an existing destination is atomic there too. The temp file is
|
|
146
|
+
* removed on failure so a full disk cannot leave debris behind.
|
|
147
|
+
*
|
|
148
|
+
* The temp name must be unique per write, not per target. A shared name lets a
|
|
149
|
+
* second writer append into the first one's half-written file and then rename
|
|
150
|
+
* the torn result into place — which is precisely the corruption this function
|
|
151
|
+
* claims to prevent, and it is reproducible with two concurrent writers.
|
|
152
|
+
*
|
|
153
|
+
* Rename can also fail with EPERM on Windows when another process has the
|
|
154
|
+
* destination open for reading, which is ordinary here: every ReviewPlan reads
|
|
155
|
+
* `latest.json`. That is transient, so `renameWithRetry` absorbs it.
|
|
156
|
+
*/
|
|
157
|
+
function writeAtomic(file, contents) {
|
|
158
|
+
const tmp = `${file}.${process.pid}.${randomBytes(6).toString('hex')}.tmp`;
|
|
159
|
+
try {
|
|
160
|
+
writeFileSync(tmp, contents, { encoding: 'utf8', mode: FILE_MODE });
|
|
161
|
+
renameWithRetry(tmp, file);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
try {
|
|
165
|
+
unlinkSync(tmp);
|
|
166
|
+
}
|
|
167
|
+
catch { /* nothing to clean up */ }
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Rename, tolerating Windows sharing violations.
|
|
173
|
+
*
|
|
174
|
+
* `MoveFileEx` fails with ERROR_ACCESS_DENIED (EPERM) while another process
|
|
175
|
+
* holds the destination open, and every ReviewPlan reads `latest.json`, so this
|
|
176
|
+
* collides in ordinary use rather than only under stress. It is transient, so
|
|
177
|
+
* it is retried with jitter — without the jitter two writers that collided once
|
|
178
|
+
* retry in lockstep and collide again. Anything that is not a sharing violation
|
|
179
|
+
* is a real failure and is raised immediately.
|
|
180
|
+
*/
|
|
181
|
+
const RENAME_RETRY_BUDGET_MS = 5_000;
|
|
182
|
+
function renameWithRetry(from, to) {
|
|
183
|
+
const started = Date.now();
|
|
184
|
+
let delay = 2;
|
|
185
|
+
for (;;) {
|
|
186
|
+
try {
|
|
187
|
+
renameSync(from, to);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
const code = err.code;
|
|
192
|
+
const transient = code === 'EPERM' || code === 'EACCES' || code === 'EBUSY';
|
|
193
|
+
if (!transient || Date.now() - started >= RENAME_RETRY_BUDGET_MS)
|
|
194
|
+
throw err;
|
|
195
|
+
sleepSync(delay + Math.floor(Math.random() * delay));
|
|
196
|
+
delay = Math.min(delay * 2, 250);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Block for `ms`, without an event-loop turn.
|
|
202
|
+
*
|
|
203
|
+
* The whole store is synchronous so that a snapshot is durable before the
|
|
204
|
+
* caller can act on it; a promise here would let a second write interleave.
|
|
205
|
+
*/
|
|
206
|
+
function sleepSync(ms) {
|
|
207
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=snapshot-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-store.js","sourceRoot":"","sources":["../src/snapshot-store.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -41,6 +41,14 @@ export interface RepoContext {
|
|
|
41
41
|
/** Remote origin URL (if available) */
|
|
42
42
|
remoteUrl?: string;
|
|
43
43
|
}
|
|
44
|
+
/** Which resolution tier produced a `SenderIdentity` label. */
|
|
45
|
+
export type SenderIdentitySource = 'session' | 'worktree' | 'path';
|
|
46
|
+
/** Resolved, display-ready sender identity for a machine/session sending a message. */
|
|
47
|
+
export interface SenderIdentity {
|
|
48
|
+
/** Display label, e.g. "Kay9 - work-item/1-reviewplan". Never an absolute path (F-9). */
|
|
49
|
+
label: string;
|
|
50
|
+
source: SenderIdentitySource;
|
|
51
|
+
}
|
|
44
52
|
/** Base fields present on every message over the ntfy channel. */
|
|
45
53
|
interface BaseMessage {
|
|
46
54
|
/** Discriminated union tag */
|
|
@@ -49,7 +57,21 @@ interface BaseMessage {
|
|
|
49
57
|
messageId: string;
|
|
50
58
|
/** Unix-epoch millis when the message was created */
|
|
51
59
|
timestamp: number;
|
|
60
|
+
/**
|
|
61
|
+
* Wire-shape version. Absent ⇒ 1.
|
|
62
|
+
*
|
|
63
|
+
* Emitted ONLY on plan_review / plan_review_response / plan_review_ack /
|
|
64
|
+
* cancel_review. The four shipping types (question, answer, notification,
|
|
65
|
+
* dismiss_notification) must keep a byte-identical wire format so a new
|
|
66
|
+
* server never breaks an already-installed client.
|
|
67
|
+
*
|
|
68
|
+
* Increment only when the wire shape changes — NEVER derive it from the
|
|
69
|
+
* package version.
|
|
70
|
+
*/
|
|
71
|
+
protocolVersion?: number;
|
|
52
72
|
}
|
|
73
|
+
/** Current wire-shape version. See BaseMessage.protocolVersion. */
|
|
74
|
+
export declare const PROTOCOL_VERSION = 2;
|
|
53
75
|
/** Published by MCP server when the LLM calls ask_human. */
|
|
54
76
|
export interface QuestionMessage extends BaseMessage {
|
|
55
77
|
type: 'question';
|
|
@@ -86,7 +108,10 @@ export interface AnswerMessage extends BaseMessage {
|
|
|
86
108
|
/** Per-question answers for batch questions */
|
|
87
109
|
subAnswers?: SubAnswer[];
|
|
88
110
|
}
|
|
89
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* Union of the four message types that predate `protocolVersion`.
|
|
113
|
+
* Their wire format is frozen — see BaseMessage.protocolVersion.
|
|
114
|
+
*/
|
|
90
115
|
export type HitlMessage = QuestionMessage | AnswerMessage | NotificationMessage | DismissNotificationMessage;
|
|
91
116
|
/** Published by MCP server for fire-and-forget progress notifications. */
|
|
92
117
|
export interface NotificationMessage extends BaseMessage {
|
|
@@ -106,6 +131,24 @@ export interface DismissNotificationMessage extends BaseMessage {
|
|
|
106
131
|
/** Device that dismissed it */
|
|
107
132
|
dismissedFrom: string;
|
|
108
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Decorates a question or notification with the sender's resolved identity.
|
|
136
|
+
*
|
|
137
|
+
* Deliberately NOT part of the `HitlMessage` union and does not extend
|
|
138
|
+
* `BaseMessage` — this carries no identity of its own, only a pointer back to
|
|
139
|
+
* the message it decorates. Published once, right after that message, by a
|
|
140
|
+
* sibling of `publishPlan`. Delivery order versus the message it decorates is
|
|
141
|
+
* not guaranteed; a client that cannot match `forMessageId` to an open or
|
|
142
|
+
* soon-to-open window drops it silently — sender identity is decoration only,
|
|
143
|
+
* never required.
|
|
144
|
+
*/
|
|
145
|
+
export interface SenderIdentityMessage {
|
|
146
|
+
type: 'sender_identity';
|
|
147
|
+
/** messageId of the question/notification this decorates. */
|
|
148
|
+
forMessageId: string;
|
|
149
|
+
forType: 'question' | 'notification';
|
|
150
|
+
sender: SenderIdentity;
|
|
151
|
+
}
|
|
109
152
|
/**
|
|
110
153
|
* A fragment of an oversized message body, published as its own ntfy message.
|
|
111
154
|
* Not part of the `HitlMessage` union — it's a transport wrapper that never
|
|
@@ -122,6 +165,104 @@ export interface ChunkMessage extends BaseMessage {
|
|
|
122
165
|
/** Slice of the base64-encoded original body */
|
|
123
166
|
data: string;
|
|
124
167
|
}
|
|
168
|
+
export type PlanVerdict = 'approved' | 'changes_requested' | 'rejected' | 'skipped' | 'cancelled';
|
|
169
|
+
/**
|
|
170
|
+
* ntfy-event-level attachment metadata, parsed off the raw ntfy JSON event.
|
|
171
|
+
* NEVER carried inside our own message — the URL only exists after the PUT.
|
|
172
|
+
* This is plaintext metadata outside our encryption, which is why `name` must
|
|
173
|
+
* be random hex and never a real path (F-9).
|
|
174
|
+
*/
|
|
175
|
+
export interface AttachmentRef {
|
|
176
|
+
name: string;
|
|
177
|
+
url: string;
|
|
178
|
+
type?: string;
|
|
179
|
+
size?: number;
|
|
180
|
+
/** Unix seconds. ntfy expires attachments after 3 h — messages after 12 h. */
|
|
181
|
+
expires?: number;
|
|
182
|
+
}
|
|
183
|
+
/** Where a plan-review body lives, and how to verify it once fetched. */
|
|
184
|
+
export interface PlanPayloadRef {
|
|
185
|
+
kind: 'inline' | 'attachment';
|
|
186
|
+
/** inline only: the encrypted-envelope JSON string produced by crypto.encrypt() */
|
|
187
|
+
data?: string;
|
|
188
|
+
/** sha256 hex of the payload plaintext (the base64(gzip(bodyJson)) string) */
|
|
189
|
+
contentHash: string;
|
|
190
|
+
/** utf-8 byte length of that same payload plaintext */
|
|
191
|
+
contentLength: number;
|
|
192
|
+
}
|
|
193
|
+
/** The gzipped body of a plan_review message. */
|
|
194
|
+
export interface PlanReviewBody {
|
|
195
|
+
content: string;
|
|
196
|
+
diff: string;
|
|
197
|
+
}
|
|
198
|
+
/** Published by the MCP server when the agent calls ReviewPlan. */
|
|
199
|
+
export interface PlanReviewMessage extends BaseMessage {
|
|
200
|
+
type: 'plan_review';
|
|
201
|
+
protocolVersion: number;
|
|
202
|
+
repo: RepoContext | null;
|
|
203
|
+
context: string;
|
|
204
|
+
/** '' when absent — never undefined */
|
|
205
|
+
summary: string;
|
|
206
|
+
/** repo-relative ONLY, never an absolute path (F-9) */
|
|
207
|
+
displayPath: string;
|
|
208
|
+
/** identity hash of the plan file location; keys drafts across revisions */
|
|
209
|
+
planId: string;
|
|
210
|
+
revision: number;
|
|
211
|
+
isNewPlan: boolean;
|
|
212
|
+
/** 'sha256:<hex>' of the plan file content */
|
|
213
|
+
snapshotHash: string;
|
|
214
|
+
body: PlanPayloadRef;
|
|
215
|
+
/** Resolved from `path.dirname(plan.resolvedPath)`; absent when identityEnabled is false. */
|
|
216
|
+
sender?: SenderIdentity;
|
|
217
|
+
}
|
|
218
|
+
/** A single line-anchored comment, in source-line space. */
|
|
219
|
+
export interface InlineComment {
|
|
220
|
+
path: string;
|
|
221
|
+
startLine: number;
|
|
222
|
+
endLine: number;
|
|
223
|
+
side: 'old' | 'new';
|
|
224
|
+
comment: string;
|
|
225
|
+
}
|
|
226
|
+
/** The gzipped body of a plan_review_response message. */
|
|
227
|
+
export interface PlanReviewResponseBody {
|
|
228
|
+
overallFeedback: string;
|
|
229
|
+
inlineComments: InlineComment[];
|
|
230
|
+
}
|
|
231
|
+
/** Published by a client when the human finishes reviewing. */
|
|
232
|
+
export interface PlanReviewResponseMessage extends BaseMessage {
|
|
233
|
+
type: 'plan_review_response';
|
|
234
|
+
protocolVersion: number;
|
|
235
|
+
/** messageId of the plan_review being answered */
|
|
236
|
+
reviewId: string;
|
|
237
|
+
respondedFrom: string;
|
|
238
|
+
verdict: PlanVerdict;
|
|
239
|
+
snapshotHash: string;
|
|
240
|
+
body: PlanPayloadRef;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Published by the server once it has actually read a response body. Without
|
|
244
|
+
* it the client shows "submitted" at click time even when the response
|
|
245
|
+
* attachment later 404s (attachments expire in 3 h, messages in 12 h).
|
|
246
|
+
*/
|
|
247
|
+
export interface PlanReviewAckMessage extends BaseMessage {
|
|
248
|
+
type: 'plan_review_ack';
|
|
249
|
+
protocolVersion: number;
|
|
250
|
+
reviewId: string;
|
|
251
|
+
responseId: string;
|
|
252
|
+
status: 'received' | 'lost';
|
|
253
|
+
reason?: string;
|
|
254
|
+
}
|
|
255
|
+
/** Published by the server when an outstanding review will never be read. */
|
|
256
|
+
export interface CancelReviewMessage extends BaseMessage {
|
|
257
|
+
type: 'cancel_review';
|
|
258
|
+
protocolVersion: number;
|
|
259
|
+
reviewId: string;
|
|
260
|
+
reason: 'agent_exited' | 'cancelled' | 'superseded';
|
|
261
|
+
}
|
|
262
|
+
/** Union of the plan-review message types. These never chunk. */
|
|
263
|
+
export type PlanMessage = PlanReviewMessage | PlanReviewResponseMessage | PlanReviewAckMessage | CancelReviewMessage;
|
|
264
|
+
/** Anything that can arrive on the topic (excluding the transport-only chunk wrapper). */
|
|
265
|
+
export type AnyHitlMessage = HitlMessage | PlanMessage;
|
|
125
266
|
export interface HitlConfig {
|
|
126
267
|
/** ntfy topic ID — a UUID used as the shared channel */
|
|
127
268
|
topicId: string;
|
|
@@ -133,6 +274,8 @@ export interface HitlConfig {
|
|
|
133
274
|
soundEnabled: boolean;
|
|
134
275
|
/** Optional AES-256-GCM encryption key (64-char hex string) for encrypting messages */
|
|
135
276
|
encryptionKey?: string;
|
|
277
|
+
/** Whether this device publishes its own sender identity (default: true) */
|
|
278
|
+
identityEnabled?: boolean;
|
|
136
279
|
}
|
|
137
280
|
export declare const DEFAULT_NTFY_URL = "https://ntfy.sh";
|
|
138
281
|
export declare const DEFAULT_CONFIG: Omit<HitlConfig, 'topicId'>;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,+DAA+D;AAC/D,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,WAAW,GAAG,wBAAwB,GAAG,cAAc,GAAG,SAAS,GAAG,MAAM,CAAC;IAC3F,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,8DAA8D;AAC9D,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,kEAAkE;AAClE,UAAU,WAAW;IACnB,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// ============================================================
|
|
2
2
|
// @hitl/shared — Protocol types for HITL MCP cross-machine messaging
|
|
3
3
|
// ============================================================
|
|
4
|
+
/** Current wire-shape version. See BaseMessage.protocolVersion. */
|
|
5
|
+
export const PROTOCOL_VERSION = 2;
|
|
4
6
|
export const DEFAULT_NTFY_URL = 'https://ntfy.sh';
|
|
5
7
|
export const DEFAULT_CONFIG = {
|
|
6
8
|
ntfyUrl: DEFAULT_NTFY_URL,
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,qEAAqE;AACrE,+DAA+D;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,qEAAqE;AACrE,+DAA+D;AAqF/D,mEAAmE;AACnE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAuPlC,MAAM,CAAC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAElD,MAAM,CAAC,MAAM,cAAc,GAAgC;IACzD,OAAO,EAAE,gBAAgB;IACzB,UAAU,EAAE,EAAE;IACd,YAAY,EAAE,IAAI;CACnB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single source of truth for the server's version — read from package.json
|
|
3
|
+
* rather than duplicated as a literal, which had already drifted five ways
|
|
4
|
+
* (root 2.0.0 / server 2.9.6 / client 2.6.0 / shared 2.0.0 / Cargo 2.9.6).
|
|
5
|
+
*
|
|
6
|
+
* Resolves identically from `src/` (ts-jest) and from `dist/` (compiled): both
|
|
7
|
+
* sit one directory below the package root.
|
|
8
|
+
*
|
|
9
|
+
* This is NOT the wire protocol version — see PROTOCOL_VERSION in types.ts,
|
|
10
|
+
* which is a small integer bumped only when the message shape changes.
|
|
11
|
+
*/
|
|
12
|
+
export declare const SERVER_VERSION: string;
|
|
13
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,EAAE,MAAoE,CAAC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
/**
|
|
4
|
+
* The single source of truth for the server's version — read from package.json
|
|
5
|
+
* rather than duplicated as a literal, which had already drifted five ways
|
|
6
|
+
* (root 2.0.0 / server 2.9.6 / client 2.6.0 / shared 2.0.0 / Cargo 2.9.6).
|
|
7
|
+
*
|
|
8
|
+
* Resolves identically from `src/` (ts-jest) and from `dist/` (compiled): both
|
|
9
|
+
* sit one directory below the package root.
|
|
10
|
+
*
|
|
11
|
+
* This is NOT the wire protocol version — see PROTOCOL_VERSION in types.ts,
|
|
12
|
+
* which is a small integer bumped only when the message shape changes.
|
|
13
|
+
*/
|
|
14
|
+
export const SERVER_VERSION = require('../package.json').version;
|
|
15
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAEvC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,cAAc,GAAY,OAAO,CAAC,iBAAiB,CAAyB,CAAC,OAAO,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,61 +1,64 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@achieveai/hitl-mcp-server",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Human-in-the-Loop MCP Server — enables LLM agents to ask questions across all your devices via ntfy.sh",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/mcp-server.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"hitl": "dist/cli.js",
|
|
9
|
-
"hitl-mcp-server": "dist/mcp-server.js"
|
|
10
|
-
},
|
|
11
|
-
"files": [
|
|
12
|
-
"dist/**/*.js",
|
|
13
|
-
"dist/**/*.d.ts",
|
|
14
|
-
"dist/**/*.map",
|
|
15
|
-
"dist/bin/**/*",
|
|
16
|
-
"scripts/postinstall.js",
|
|
17
|
-
"README.md"
|
|
18
|
-
],
|
|
19
|
-
"keywords": [
|
|
20
|
-
"mcp",
|
|
21
|
-
"llm",
|
|
22
|
-
"human-in-the-loop",
|
|
23
|
-
"hitl",
|
|
24
|
-
"dialog",
|
|
25
|
-
"interactive",
|
|
26
|
-
"model-context-protocol",
|
|
27
|
-
"ntfy",
|
|
28
|
-
"notifications"
|
|
29
|
-
],
|
|
30
|
-
"repository": {
|
|
31
|
-
"type": "git",
|
|
32
|
-
"url": "git+https://github.com/achieveai/HumanInTheLoop.git"
|
|
33
|
-
},
|
|
34
|
-
"license": "
|
|
35
|
-
"scripts": {
|
|
36
|
-
"build": "tsc",
|
|
37
|
-
"start": "node dist/mcp-server.js",
|
|
38
|
-
"dev": "tsx src/index.ts",
|
|
39
|
-
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.js",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"@
|
|
53
|
-
"@types/
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@achieveai/hitl-mcp-server",
|
|
3
|
+
"version": "2.11.2",
|
|
4
|
+
"description": "Human-in-the-Loop MCP Server — enables LLM agents to ask questions across all your devices via ntfy.sh",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/mcp-server.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"hitl": "dist/cli.js",
|
|
9
|
+
"hitl-mcp-server": "dist/mcp-server.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/**/*.js",
|
|
13
|
+
"dist/**/*.d.ts",
|
|
14
|
+
"dist/**/*.map",
|
|
15
|
+
"dist/bin/**/*",
|
|
16
|
+
"scripts/postinstall.js",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"llm",
|
|
22
|
+
"human-in-the-loop",
|
|
23
|
+
"hitl",
|
|
24
|
+
"dialog",
|
|
25
|
+
"interactive",
|
|
26
|
+
"model-context-protocol",
|
|
27
|
+
"ntfy",
|
|
28
|
+
"notifications"
|
|
29
|
+
],
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/achieveai/HumanInTheLoop.git"
|
|
33
|
+
},
|
|
34
|
+
"license": "GPL-3.0",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc",
|
|
37
|
+
"start": "node dist/mcp-server.js",
|
|
38
|
+
"dev": "tsx src/index.ts",
|
|
39
|
+
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.js",
|
|
40
|
+
"fixture:payload": "tsx scripts/gen-payload-fixture.ts",
|
|
41
|
+
"clean": "rimraf dist",
|
|
42
|
+
"postinstall": "node scripts/postinstall.js",
|
|
43
|
+
"prepublishOnly": "npm run build"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
47
|
+
"diff": "^5.2.2",
|
|
48
|
+
"eventsource": "^2.0.2",
|
|
49
|
+
"uuid": "^9.0.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@jest/globals": "^29.7.0",
|
|
53
|
+
"@types/diff": "^5.2.3",
|
|
54
|
+
"@types/eventsource": "^1.1.15",
|
|
55
|
+
"@types/node": "^20.0.0",
|
|
56
|
+
"@types/uuid": "^9.0.0",
|
|
57
|
+
"cross-env": "^10.1.0",
|
|
58
|
+
"jest": "^29.7.0",
|
|
59
|
+
"rimraf": "^5.0.0",
|
|
60
|
+
"ts-jest": "^29.1.0",
|
|
61
|
+
"tsx": "^4.0.0",
|
|
62
|
+
"typescript": "^5.3.0"
|
|
63
|
+
}
|
|
64
|
+
}
|