@miadi/connector 0.1.8 → 0.1.10
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 +12 -2
- package/dist/approve.d.ts +18 -14
- package/dist/approve.js +95 -50
- package/dist/decisions.d.ts +1 -1
- package/dist/decisions.js +42 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/mission-status.d.ts +87 -0
- package/dist/mission-status.js +144 -0
- package/dist/providers.d.ts +61 -0
- package/dist/providers.js +120 -0
- package/dist/queue-state.d.ts +15 -0
- package/dist/queue-state.js +24 -0
- package/dist/records.d.ts +4 -1
- package/dist/records.js +3 -0
- package/dist/request-state.d.ts +69 -0
- package/dist/request-state.js +180 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +16 -1
- package/dist/steer.d.ts +71 -0
- package/dist/steer.js +229 -0
- package/dist/tools.d.ts +9 -0
- package/dist/tools.js +218 -16
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/tools.js
CHANGED
|
@@ -16,8 +16,11 @@ import { reviewIdOf, videoIdOf } from "./reviews.js";
|
|
|
16
16
|
import { SCOPE_APPROVE, SCOPE_CONTRIBUTE } from "./oauth.js";
|
|
17
17
|
import { CIRCLES, CIRCLE_IDS, CLAIM_CATEGORIES, DOMAINS, HANDOFF_STATES, current, newRecordId, } from "./records.js";
|
|
18
18
|
import { VERSION } from "./version.js";
|
|
19
|
-
import { AlreadyDecided, DECISIONS, KIND_LABELS, consequenceOf, decide, isApprovable, readQueueState } from "./approve.js";
|
|
19
|
+
import { AlreadyDecided, DECISIONS, KIND_LABELS, consequenceOf, decide, isApprovable, readQueueState, requestProjection } from "./approve.js";
|
|
20
20
|
import { DECISIONS_CARD_HTML, DECISIONS_CARD_URI, DECISION_TOKENS_META } from "./decisions.js";
|
|
21
|
+
import { discoverProviders, resolveProvider, routerPreflight, PROVIDERS } from "./providers.js";
|
|
22
|
+
import { missionStatus } from "./mission-status.js";
|
|
23
|
+
import { checkGrant, isBusy, steerAttempts, steeringGrantOf, steerSession } from "./steer.js";
|
|
21
24
|
import { join } from "node:path";
|
|
22
25
|
import { artefactVisibility, readArtefactWeave, saveResearchArtefact } from "@miadi/inquiry-weave";
|
|
23
26
|
import { ResearchUploads, UploadRefusal } from "./uploads.js";
|
|
@@ -461,11 +464,79 @@ export function registerTools(server, ctx) {
|
|
|
461
464
|
record: r,
|
|
462
465
|
approval_url: r.approval_state === "awaiting_approval" ? approvalUrl(r.id) : undefined,
|
|
463
466
|
queue: r.kind === "run_request" || r.kind === "work_proposal" ? readQueueState(r, ctx.factoryDir) : undefined,
|
|
467
|
+
// Where the request stands, in the words every surface uses (jgwill/Miadi#889).
|
|
468
|
+
projection: requestProjection(r, { reviewBase: ctx.approval?.config.reviewUrl, factoryDir: ctx.factoryDir }),
|
|
464
469
|
...(r.approval_state === "revision_requested"
|
|
465
470
|
? { revision: { instructions: r.completion_receipt?.instructions, next: `Submit a revised request that cites ${r.id} in refs.` } }
|
|
466
471
|
: {}),
|
|
467
472
|
};
|
|
468
473
|
}));
|
|
474
|
+
server.registerTool("mission_status", {
|
|
475
|
+
title: "Where a mission stands",
|
|
476
|
+
description: "One mission, joined and verified: its source request and decision, the sessions bound to it (live or not), its issues and PRs, what is approved, queued, delivered, running, merged, released or closed — each by its evidence, never inferred from an idle pane — and the next authorized action. Operator details need Miadi's write tier. jgwill/Miadi#893.",
|
|
477
|
+
inputSchema: {
|
|
478
|
+
ref: z
|
|
479
|
+
.string()
|
|
480
|
+
.min(1)
|
|
481
|
+
.describe("run_request:<id>, work_proposal:<id>, another record id, session:<uuid>, or owner/repo#n the mission cites."),
|
|
482
|
+
},
|
|
483
|
+
annotations: READ,
|
|
484
|
+
}, wrap(async ({ ref }, extra) => {
|
|
485
|
+
const { person } = who(extra);
|
|
486
|
+
const writeTier = person.api_tier === "write";
|
|
487
|
+
return missionStatus(ref.trim(), records(), {
|
|
488
|
+
projectOf: (r) => requestProjection(r, { reviewBase: ctx.approval?.config.reviewUrl, factoryDir: ctx.factoryDir }),
|
|
489
|
+
queueOf: (r) => (r.kind === "run_request" || r.kind === "work_proposal" ? readQueueState(r, ctx.factoryDir) : undefined),
|
|
490
|
+
tmuxSessions: writeTier ? (ctx.tmuxSessions ?? (() => [])) : undefined,
|
|
491
|
+
paneBusy: writeTier && ctx.tmux
|
|
492
|
+
? (session) => {
|
|
493
|
+
try {
|
|
494
|
+
const pane = ctx.tmux.listPanes(session)[0];
|
|
495
|
+
if (!pane)
|
|
496
|
+
return "unknown";
|
|
497
|
+
return isBusy(ctx.tmux.capture(`${session}:${pane.window}.${pane.pane}`)) ? "busy" : "idle";
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
return "unknown";
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
: undefined,
|
|
504
|
+
sessionOf: writeTier ? (id) => miadi.get(person.token, `/api/session/${encodeURIComponent(id)}`) : undefined,
|
|
505
|
+
issueOf: async (owner, repo, n) => {
|
|
506
|
+
const f = ctx.approval?.fetchImpl ?? fetch;
|
|
507
|
+
const headers = {
|
|
508
|
+
accept: "application/vnd.github+json",
|
|
509
|
+
...(process.env.GITHUB_TOKEN ? { authorization: "Bearer " + process.env.GITHUB_TOKEN } : {}),
|
|
510
|
+
};
|
|
511
|
+
const pr = await f(`https://api.github.com/repos/${owner}/${repo}/pulls/${n}`, { headers, signal: AbortSignal.timeout(15_000) });
|
|
512
|
+
if (pr.ok) {
|
|
513
|
+
const p = await pr.json();
|
|
514
|
+
return { state: p.state, title: p.title, merged: Boolean(p.merged_at) };
|
|
515
|
+
}
|
|
516
|
+
const res = await f(`https://api.github.com/repos/${owner}/${repo}/issues/${n}`, { headers, signal: AbortSignal.timeout(15_000) });
|
|
517
|
+
if (!res.ok)
|
|
518
|
+
return { state: res.status === 404 ? "not_found_or_private" : `github_${res.status}` };
|
|
519
|
+
const i = await res.json();
|
|
520
|
+
return { state: i.state, title: i.title };
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
}));
|
|
524
|
+
server.registerTool("provider_capabilities", {
|
|
525
|
+
title: "Which agent providers this host can launch",
|
|
526
|
+
description: "The provider reality of the connector host (jgwill/Miadi#893): which agent CLIs are installed, their versions, whether sign-in evidence exists, the preference order (Codex, Pi, Copilot; Claude Code only on explicit request), and the read-only Jev routing preflight. No token is read or shown. Needs Miadi's write tier: this is host truth.",
|
|
527
|
+
inputSchema: {},
|
|
528
|
+
annotations: READ,
|
|
529
|
+
}, wrap(async (_args, extra) => {
|
|
530
|
+
const { person } = who(extra);
|
|
531
|
+
requireTier(person, "write");
|
|
532
|
+
return {
|
|
533
|
+
preference_order: PROVIDERS.map((p) => p.id),
|
|
534
|
+
explicit_only: PROVIDERS.filter((p) => !p.selectable_by_default).map((p) => p.id),
|
|
535
|
+
providers: discoverProviders(ctx.providersProbe),
|
|
536
|
+
router: await routerPreflight(process.env, ctx.approval?.fetchImpl ?? fetch),
|
|
537
|
+
note: "A provider name in a task's text selects nothing; request_authorized_run's provider field is verified against this list, and an unavailable provider leaves the mission unstarted.",
|
|
538
|
+
};
|
|
539
|
+
}));
|
|
469
540
|
// search / fetch: the pair ChatGPT uses for connectors in search and deep research.
|
|
470
541
|
server.registerTool("search", {
|
|
471
542
|
title: "Search Miadi",
|
|
@@ -813,12 +884,31 @@ export function registerTools(server, ctx) {
|
|
|
813
884
|
refs,
|
|
814
885
|
session: z.string().regex(/^[A-Za-z0-9._-]{3,80}$/).optional().describe("An existing tmux session to hand it to, or a name for a new one."),
|
|
815
886
|
cwd: z.string().max(300).optional().describe("Working folder for a new session (default the Miadi checkout)."),
|
|
887
|
+
provider: z
|
|
888
|
+
.enum(["codex", "pi", "copilot", "claude"])
|
|
889
|
+
.optional()
|
|
890
|
+
.describe("The provider the run should launch with, verified installed on the connector host. Claude Code runs only when named explicitly. Unknown or unavailable leaves the mission unstarted."),
|
|
891
|
+
steering: z
|
|
892
|
+
.object({
|
|
893
|
+
max_attempts: z.number().int().min(1).max(20).describe("How many authorized follow-up steers this approval covers."),
|
|
894
|
+
expires_at: z.string().optional().describe("ISO time after which no steer runs under this grant."),
|
|
895
|
+
pane: z.string().regex(/^\d+\.\d+$/).optional().describe("The pane the seat lives in (window.pane); default the session's first pane."),
|
|
896
|
+
})
|
|
897
|
+
.optional()
|
|
898
|
+
.describe("The steering grant the approver covers with this run: bounded follow-ups to the same session through request_session_steer."),
|
|
816
899
|
...base,
|
|
817
900
|
},
|
|
818
901
|
annotations: WRITE,
|
|
819
902
|
}, wrap(async (a, extra) => {
|
|
820
903
|
const { person, auth } = who(extra);
|
|
821
904
|
requireContribute(auth);
|
|
905
|
+
const found = discoverProviders(ctx.providersProbe);
|
|
906
|
+
const resolution = resolveProvider(a.provider, found);
|
|
907
|
+
if (resolution.state === "provider_unknown")
|
|
908
|
+
throw new ToolRefusal("invalid_request", resolution.message, { available: resolution.available });
|
|
909
|
+
if (resolution.state !== "ok") {
|
|
910
|
+
return { state: resolution.state, message: resolution.message, available: resolution.available, note: "Nothing was recorded or queued; the mission is unstarted." };
|
|
911
|
+
}
|
|
822
912
|
const r = append("run_request", person, auth, {
|
|
823
913
|
circle: a.circle,
|
|
824
914
|
refs: a.refs,
|
|
@@ -827,9 +917,100 @@ export function registerTools(server, ctx) {
|
|
|
827
917
|
idempotency_key: a.idempotency_key,
|
|
828
918
|
approval_state: "awaiting_approval",
|
|
829
919
|
state: "pending",
|
|
830
|
-
body: {
|
|
920
|
+
body: {
|
|
921
|
+
task: a.task,
|
|
922
|
+
session: a.session,
|
|
923
|
+
cwd: a.cwd,
|
|
924
|
+
provider: a.provider,
|
|
925
|
+
resolved_provider: resolution.provider.id,
|
|
926
|
+
...(a.steering ? { steering: a.steering } : {}),
|
|
927
|
+
},
|
|
831
928
|
});
|
|
832
|
-
return {
|
|
929
|
+
return {
|
|
930
|
+
...r,
|
|
931
|
+
provider: { requested: a.provider ?? null, resolved: resolution.provider.id, explicit: resolution.explicit, version: resolution.provider.version },
|
|
932
|
+
approval_url: approvalUrl(r.id),
|
|
933
|
+
};
|
|
934
|
+
}));
|
|
935
|
+
server.registerTool("request_session_steer", {
|
|
936
|
+
title: "Send one authorized follow-up to a running agent",
|
|
937
|
+
description: "Steer one existing live agent session within an approved run's steering grant (jgwill/Miadi#893): the exact instruction is typed into the mission's bound pane — never whichever pane is active — after a peek, and a re-peek verifies the agent accepted it. When the approved run carries no steering grant covering this, the steer waits for one explicit scoped human decision on the returned approval_url. Every attempt leaves a durable artifact with its hash and both captures.",
|
|
938
|
+
inputSchema: {
|
|
939
|
+
run_request: z.string().min(1).describe("The approved run_request or work_proposal whose steering grant covers this steer."),
|
|
940
|
+
instruction: z.string().min(1).max(4000).describe("The exact instruction typed into the session. It is material within the approved mission's scope, not new authority."),
|
|
941
|
+
session: z.string().regex(/^[A-Za-z0-9._-]{3,80}$/).optional().describe("The session to steer; must be the one the grant binds."),
|
|
942
|
+
pane: z.string().regex(/^\d+\.\d+$/).optional().describe("The pane (window.pane); default the grant's pane, else the session's first pane. The active pane is never used."),
|
|
943
|
+
refs,
|
|
944
|
+
...base,
|
|
945
|
+
},
|
|
946
|
+
annotations: WRITE,
|
|
947
|
+
}, wrap(async (a, extra) => {
|
|
948
|
+
const { person, auth } = who(extra);
|
|
949
|
+
requireContribute(auth);
|
|
950
|
+
requireTier(person, "write");
|
|
951
|
+
if (!ctx.tmux)
|
|
952
|
+
throw new ToolRefusal("unavailable", "The connector host has no steering surface; the steer is unstarted.");
|
|
953
|
+
const grantRecord = all().find((r) => r.id === a.run_request);
|
|
954
|
+
if (!grantRecord || (grantRecord.kind !== "run_request" && grantRecord.kind !== "work_proposal")) {
|
|
955
|
+
throw new ToolRefusal("invalid_ref", "Give the id of the approved run_request or work_proposal this steer belongs to.");
|
|
956
|
+
}
|
|
957
|
+
if (grantRecord.approval_state !== "approved") {
|
|
958
|
+
throw new ToolRefusal("not_approved", `${grantRecord.id} is ${grantRecord.approval_state ?? "not approved"}; a steer needs an approved run's grant or its own human decision.`);
|
|
959
|
+
}
|
|
960
|
+
const grant = steeringGrantOf(grantRecord);
|
|
961
|
+
const priorAttempts = steerAttempts(all(), grantRecord.id);
|
|
962
|
+
const covered = checkGrant(grant, priorAttempts) === "ok";
|
|
963
|
+
const body = {
|
|
964
|
+
instruction: a.instruction,
|
|
965
|
+
session: a.session ?? grantRecord.body.session,
|
|
966
|
+
pane: a.pane ?? grant?.pane,
|
|
967
|
+
};
|
|
968
|
+
const fields = {
|
|
969
|
+
circle: grantRecord.circle,
|
|
970
|
+
refs: [grantRecord.id, ...a.refs],
|
|
971
|
+
intention: a.intention,
|
|
972
|
+
role: a.role,
|
|
973
|
+
idempotency_key: a.idempotency_key,
|
|
974
|
+
body,
|
|
975
|
+
};
|
|
976
|
+
if (!covered) {
|
|
977
|
+
// One explicit scoped human decision (jgwill/Miadi#893): the record waits
|
|
978
|
+
// on the approval page; approving it runs exactly this instruction once.
|
|
979
|
+
const r = append("session_steer_request", person, auth, { ...fields, approval_state: "awaiting_approval", state: "pending" });
|
|
980
|
+
return {
|
|
981
|
+
...r,
|
|
982
|
+
approval_url: approvalUrl(r.id),
|
|
983
|
+
state: "awaiting_approval",
|
|
984
|
+
reason: !grant ? "no_grant" : checkGrant(grant, priorAttempts),
|
|
985
|
+
message: "The approved run's steering grant does not cover this steer; a person's decision is requested, once, for exactly this instruction.",
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
const r = append("session_steer_request", person, auth, { ...fields, approval_state: "not_required" });
|
|
989
|
+
const result = await steerSession({ tmux: ctx.tmux, stateDir: config.stateDir, ...(ctx.steerSettleMs !== undefined ? { settleMs: ctx.steerSettleMs } : {}) }, { record: r, grantRecord, priorAttempts });
|
|
990
|
+
const delivered = result.status === "accepted" || result.status === "submitted";
|
|
991
|
+
ledger.append({
|
|
992
|
+
id: newRecordId(r.kind),
|
|
993
|
+
kind: r.kind,
|
|
994
|
+
created_at: new Date().toISOString(),
|
|
995
|
+
actor: r.actor,
|
|
996
|
+
refs: r.refs,
|
|
997
|
+
evidence_refs: [],
|
|
998
|
+
supersedes: r.id,
|
|
999
|
+
approval_state: "not_required",
|
|
1000
|
+
state: delivered ? "completed" : "blocked",
|
|
1001
|
+
completion_receipt: {
|
|
1002
|
+
decision: "covered_by_grant",
|
|
1003
|
+
decided_by: { person_id: person.id, name: person.name },
|
|
1004
|
+
decided_at: new Date().toISOString(),
|
|
1005
|
+
outcome: delivered ? result.status : "failed",
|
|
1006
|
+
steer_status: result.status,
|
|
1007
|
+
message: result.message,
|
|
1008
|
+
...(result.target ? { target: result.target } : {}),
|
|
1009
|
+
...(result.artifact ? { artifact: result.artifact } : {}),
|
|
1010
|
+
},
|
|
1011
|
+
body: r.body,
|
|
1012
|
+
});
|
|
1013
|
+
return records().find((x) => x.id === r.id) ?? r;
|
|
833
1014
|
}));
|
|
834
1015
|
server.registerTool("request_review_operation", {
|
|
835
1016
|
title: "Request a review operation",
|
|
@@ -1083,9 +1264,9 @@ export function registerTools(server, ctx) {
|
|
|
1083
1264
|
const { person, auth } = who(extra);
|
|
1084
1265
|
const writer = person.api_tier === "write";
|
|
1085
1266
|
const waiting = all()
|
|
1086
|
-
.filter((r) =>
|
|
1267
|
+
.filter((r) => isApprovable(r))
|
|
1087
1268
|
.filter((r) => writer || r.actor.person_id === person.id)
|
|
1088
|
-
.filter((r) =>
|
|
1269
|
+
.filter((r) => record_id ? r.id === record_id : r.approval_state === "awaiting_approval")
|
|
1089
1270
|
.slice(-20)
|
|
1090
1271
|
.reverse();
|
|
1091
1272
|
const canDecide = writer && auth.scopes.includes(SCOPE_APPROVE) && Boolean(ctx.decisionTokens);
|
|
@@ -1107,17 +1288,20 @@ export function registerTools(server, ctx) {
|
|
|
1107
1288
|
consequence: consequenceOf(r),
|
|
1108
1289
|
detail: detailOf(r),
|
|
1109
1290
|
approval_url: approvalUrl(r.id),
|
|
1291
|
+
projection: requestProjection(r, { reviewBase: ctx.approval?.config.reviewUrl, factoryDir: ctx.factoryDir }),
|
|
1110
1292
|
}));
|
|
1111
|
-
const
|
|
1293
|
+
const actionable = decisions.filter((d) => d.projection?.stage === "awaiting_decision");
|
|
1294
|
+
const tokens = canDecide ? Object.fromEntries(actionable.map((r) => [r.id, ctx.decisionTokens.issue(r.id, person.id, auth.clientId)])) : {};
|
|
1112
1295
|
const structured = {
|
|
1113
1296
|
decisions,
|
|
1114
1297
|
count: decisions.length,
|
|
1298
|
+
awaiting_count: actionable.length,
|
|
1115
1299
|
can_decide_here: canDecide,
|
|
1116
1300
|
...(reason ? { reason } : {}),
|
|
1117
1301
|
...(decisions.length ? {} : { message: record_id ? "That request is not awaiting a decision." : "No request is waiting for a decision." }),
|
|
1118
1302
|
};
|
|
1119
1303
|
const text = decisions.length
|
|
1120
|
-
? `${decisions.length} request(s)
|
|
1304
|
+
? `${decisions.length} request(s) shown as cards; ${actionable.length} await a decision. ${canDecide ? "The person decides an awaiting request on its card; do not decide or claim a decision for them." : reason}`
|
|
1121
1305
|
: structured.message;
|
|
1122
1306
|
return { structuredContent: structured, content: [{ type: "text", text }], _meta: { [DECISION_TOKENS_META]: tokens } };
|
|
1123
1307
|
}
|
|
@@ -1153,28 +1337,43 @@ export function registerTools(server, ctx) {
|
|
|
1153
1337
|
const check = ctx.decisionTokens.verify(a.decision_token, r.id, person.id, auth.clientId);
|
|
1154
1338
|
if (check !== "ok")
|
|
1155
1339
|
throw new ToolRefusal(check === "expired" ? "token_expired" : "invalid_token", check === "expired" ? "This card is too old; show the requests again." : "This decision did not come from the person's card.");
|
|
1156
|
-
|
|
1157
|
-
|
|
1340
|
+
// A stale card or a second client gets where the request stands, not a bare refusal (jgwill/Miadi#889).
|
|
1341
|
+
const projectionNow = () => requestProjection(all().find((x) => x.id === r.id) ?? r, { reviewBase: ctx.approval?.config.reviewUrl, factoryDir: ctx.factoryDir });
|
|
1342
|
+
if (r.approval_state !== "awaiting_approval") {
|
|
1343
|
+
throw new ToolRefusal("already_decided", `This request is already ${r.approval_state}.`, { projection: projectionNow() });
|
|
1344
|
+
}
|
|
1158
1345
|
const instructions = a.instructions?.trim() || undefined;
|
|
1159
1346
|
if ((a.decision === "approve_with_changes" || a.decision === "request_revision") && !instructions) {
|
|
1160
1347
|
throw new ToolRefusal("instructions_required", a.decision === "request_revision" ? "Say what to revise." : "Write the changes to apply.");
|
|
1161
1348
|
}
|
|
1162
1349
|
const client = ctx.oauthState.read().clients[auth.clientId];
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1350
|
+
let decided;
|
|
1351
|
+
try {
|
|
1352
|
+
decided = await decide(r, person, a.decision, ctx.approval, {
|
|
1353
|
+
instructions,
|
|
1354
|
+
via: `card:${String(client?.client_name ?? auth.clientId).slice(0, 50)}`,
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
catch (error) {
|
|
1358
|
+
// A decision recorded a moment earlier, by another client, is reported with where it stands.
|
|
1359
|
+
if (error instanceof AlreadyDecided)
|
|
1360
|
+
throw new ToolRefusal("already_decided", error.message, { projection: projectionNow() });
|
|
1361
|
+
throw error;
|
|
1362
|
+
}
|
|
1363
|
+
const { decision, state, receipt } = decided;
|
|
1364
|
+
const projection = projectionNow();
|
|
1167
1365
|
const summary = decision === "approved"
|
|
1168
1366
|
? `Approved by ${person.name}. ${receipt.outcome === "failed" ? "Running it failed; see the receipt." : `Outcome: ${String(receipt.outcome ?? "recorded").replace(/_/g, " ")}.`}`
|
|
1169
1367
|
: decision === "revision_requested"
|
|
1170
1368
|
? `Sent back for revision by ${person.name}.`
|
|
1171
1369
|
: `Declined by ${person.name}.`;
|
|
1172
|
-
const out = { record_id: r.id, decision, state, summary, receipt };
|
|
1370
|
+
const out = { record_id: r.id, decision, state, summary, receipt, projection };
|
|
1173
1371
|
return { structuredContent: out, content: [{ type: "text", text: JSON.stringify(out, null, 2) }] };
|
|
1174
1372
|
}
|
|
1175
1373
|
catch (error) {
|
|
1176
1374
|
if (error instanceof ToolRefusal || error instanceof AlreadyDecided) {
|
|
1177
|
-
const
|
|
1375
|
+
const detail = error instanceof ToolRefusal ? error.detail : undefined;
|
|
1376
|
+
const out = error instanceof AlreadyDecided ? { error: "already_decided", message: error.message } : { error: error.code, message: error.message, ...detail };
|
|
1178
1377
|
return { isError: true, structuredContent: out, content: [{ type: "text", text: JSON.stringify(out, null, 2) }] };
|
|
1179
1378
|
}
|
|
1180
1379
|
return fail({ error: "failed", message: error instanceof Error ? error.message : String(error) });
|
|
@@ -1242,6 +1441,8 @@ export const TOOL_STATUS = {
|
|
|
1242
1441
|
handoff_status: "live",
|
|
1243
1442
|
list_records: "live",
|
|
1244
1443
|
get_run_result: "live",
|
|
1444
|
+
mission_status: "live (operator details need the Miadi write tier)",
|
|
1445
|
+
provider_capabilities: "live, Miadi write tier",
|
|
1245
1446
|
search: "live",
|
|
1246
1447
|
fetch: "live",
|
|
1247
1448
|
append_observation: "live, contribute",
|
|
@@ -1255,7 +1456,8 @@ export const TOOL_STATUS = {
|
|
|
1255
1456
|
propose_work: "live, contribute, needs_approval (approving starts the work as a factory run)",
|
|
1256
1457
|
prepare_calendar_event: "live, contribute (draft and .ics only)",
|
|
1257
1458
|
propose_session_completion: "live, contribute, needs_approval (decision recorded, nothing closed)",
|
|
1258
|
-
request_authorized_run: "live, contribute, needs_approval (queues a factory brief once approved)",
|
|
1459
|
+
request_authorized_run: "live, contribute, needs_approval (queues a factory brief once approved; may name a verified provider and a bounded steering grant)",
|
|
1460
|
+
request_session_steer: "live, contribute, write tier (runs inside an approved run's steering grant, else one scoped human decision)",
|
|
1259
1461
|
request_review_operation: "live, contribute, needs_approval",
|
|
1260
1462
|
request_deep_diver: "live, contribute, needs_approval",
|
|
1261
1463
|
link_review_to_episode: "live, contribute, needs_approval",
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.10";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.1.
|
|
1
|
+
export const VERSION = "0.1.10";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miadi/connector",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "The Miadi connector: one remote MCP service through which a person signed in with their Miadi person token, from ChatGPT or any MCP client, reads sessions, reviews, episodes and circles and records observations, inquiries, handoffs and proposals with their name on each record.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Miadi",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"README.md"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@miadi/inquiry-weave": "0.18.
|
|
29
|
+
"@miadi/inquiry-weave": "0.18.5",
|
|
30
30
|
"@miadi/node-service-kit": "0.1.2",
|
|
31
31
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
32
32
|
"express": "^5.2.1",
|