@miadi/connector 0.1.12 → 0.1.13
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 +6 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/mission-status.d.ts +121 -15
- package/dist/mission-status.js +198 -27
- package/dist/model-preflight.d.ts +144 -0
- package/dist/model-preflight.js +323 -0
- package/dist/providers.d.ts +29 -3
- package/dist/providers.js +32 -11
- package/dist/server.d.ts +5 -1
- package/dist/server.js +2 -0
- package/dist/tools.d.ts +12 -1
- package/dist/tools.js +102 -11
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/tools.js
CHANGED
|
@@ -18,8 +18,9 @@ import { CIRCLES, CIRCLE_IDS, CLAIM_CATEGORIES, DOMAINS, HANDOFF_STATES, current
|
|
|
18
18
|
import { VERSION } from "./version.js";
|
|
19
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";
|
|
21
|
+
import { discoverProviders, jevConfigOf, resolveProvider, routerPreflight, PROVIDERS } from "./providers.js";
|
|
22
|
+
import { authorizesActions, missionStatus, primaryIssueOf, resolveMissionSubject } from "./mission-status.js";
|
|
23
|
+
import { candidatesFor, CRITICALITIES, jevAdapter, modelPreflight, PREFLIGHT_CONTRACT, PREFLIGHT_VERSION, TASK_TYPES, } from "./model-preflight.js";
|
|
23
24
|
import { checkGrant, isBusy, steerAttempts, steeringGrantOf, steerSession } from "./steer.js";
|
|
24
25
|
import { join } from "node:path";
|
|
25
26
|
import { artefactVisibility, readArtefactWeave, saveResearchArtefact } from "@miadi/inquiry-weave";
|
|
@@ -84,6 +85,29 @@ const WRITE = { readOnlyHint: false, destructiveHint: false, openWorldHint: fals
|
|
|
84
85
|
const refs = z.array(z.string()).max(50).default([]).describe("References: miadi-review:<uuid>, miadi-chronicle://<n>, owner/repo#n, session:<uuid>, a record id, or a URL.");
|
|
85
86
|
const circle = z.enum(CIRCLE_IDS);
|
|
86
87
|
const claim = z.enum(CLAIM_CATEGORIES).describe("observed, hypothesis, desired_future, fiction or verified_implementation.");
|
|
88
|
+
const primaryIssue = z
|
|
89
|
+
.string()
|
|
90
|
+
.regex(/^[\w.-]+\/[\w.-]+#\d+$/)
|
|
91
|
+
.optional()
|
|
92
|
+
.describe("owner/repo#n: the one issue this mission implements. Other refs stay related. Without it, mission_status can only infer the mission from the first issue in refs (jgwill/Miadi#913).");
|
|
93
|
+
/** Refs with the declared primary issue first, never duplicated. */
|
|
94
|
+
function withPrimary(refs, primary) {
|
|
95
|
+
return primary ? [primary, ...refs.filter((r) => r !== primary)] : refs;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Why GitHub did not answer a reference (jgwill/Miadi#913 B). A 404 without a
|
|
99
|
+
* token is a private repository as often as a missing issue, so nothing here is
|
|
100
|
+
* ever reported as not found.
|
|
101
|
+
*/
|
|
102
|
+
export function githubAccess(status, hasToken) {
|
|
103
|
+
if (status === 404)
|
|
104
|
+
return hasToken ? "not_visible_to_token" : "no_github_token";
|
|
105
|
+
if (status === 401)
|
|
106
|
+
return "token_rejected";
|
|
107
|
+
if (status === 403 || status === 429)
|
|
108
|
+
return "forbidden_or_rate_limited";
|
|
109
|
+
return `github_${status}`;
|
|
110
|
+
}
|
|
87
111
|
function episodeRef(input) {
|
|
88
112
|
// miadi-chronicle://316, miadi-chronicle:316, chronicle:<folder>, a folder, or a number
|
|
89
113
|
return encodeURIComponent(input.replace(/^miadi-chronicle:(\/\/)?/, "").replace(/^chronicle:/, "").trim());
|
|
@@ -227,7 +251,7 @@ export function registerTools(server, ctx) {
|
|
|
227
251
|
signal: AbortSignal.timeout(15_000),
|
|
228
252
|
});
|
|
229
253
|
if (!res.ok)
|
|
230
|
-
return { ref: r, kind: "github_issue", state:
|
|
254
|
+
return { ref: r, kind: "github_issue", state: "unverified", access: githubAccess(res.status, Boolean(process.env.GITHUB_TOKEN)), cited_by: cited };
|
|
231
255
|
const i = await res.json();
|
|
232
256
|
return {
|
|
233
257
|
ref: r,
|
|
@@ -625,7 +649,7 @@ export function registerTools(server, ctx) {
|
|
|
625
649
|
}));
|
|
626
650
|
server.registerTool("mission_status", {
|
|
627
651
|
title: "Where a mission stands",
|
|
628
|
-
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.",
|
|
652
|
+
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. An issue or session resolves only through the request that holds it as primary; several are ambiguous_mission, citations alone are related_only, and an inference authorizes nothing (identity.authorizes_actions). Released needs a release receipt with artifact, target, production check and a fresh time; closed needs an approved session ending that cites the mission. Operator details need Miadi's write tier. jgwill/Miadi#893, #913.",
|
|
629
653
|
inputSchema: {
|
|
630
654
|
ref: z
|
|
631
655
|
.string()
|
|
@@ -667,10 +691,11 @@ export function registerTools(server, ctx) {
|
|
|
667
691
|
}
|
|
668
692
|
const res = await f(`https://api.github.com/repos/${owner}/${repo}/issues/${n}`, { headers, signal: AbortSignal.timeout(15_000) });
|
|
669
693
|
if (!res.ok)
|
|
670
|
-
return { state:
|
|
694
|
+
return { state: "unverified", access: githubAccess(res.status, Boolean(process.env.GITHUB_TOKEN)) };
|
|
671
695
|
const i = await res.json();
|
|
672
696
|
return { state: i.state, title: i.title };
|
|
673
697
|
},
|
|
698
|
+
liveVersionOf: (pkg) => (pkg === "@miadi/connector" ? VERSION : undefined),
|
|
674
699
|
});
|
|
675
700
|
}));
|
|
676
701
|
server.registerTool("provider_capabilities", {
|
|
@@ -689,6 +714,63 @@ export function registerTools(server, ctx) {
|
|
|
689
714
|
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.",
|
|
690
715
|
};
|
|
691
716
|
}));
|
|
717
|
+
server.registerTool("mission_model_preflight", {
|
|
718
|
+
title: "Which provider and model fits a mission, and how that is known",
|
|
719
|
+
description: "A typed, versioned, read-only preflight for one mission (jgwill/Miadi#913): the candidate providers with their concrete model when the host shows one, sign-in evidence (config directory only), quota unknown, policy eligibility (the approved provider is kept; Claude Code only when named), a review floor, and a recommendation or an abstention with its reasons. It says where the choice came from: static_fallback, jev or a synthetic fixture. Jev is asked only with consult_jev and a Jev key in the connector's environment; that call is charged, and it carries no task text, mission id or repository name. A reported launch on another provider than the approved one fails closed as provider_mismatch. It authorizes nothing. Needs Miadi's write tier.",
|
|
720
|
+
inputSchema: {
|
|
721
|
+
ref: z.string().min(1).describe("The mission: run_request:<id> or work_proposal:<id> (an issue or session ref resolves only through its primary relation)."),
|
|
722
|
+
task_type: z.enum(TASK_TYPES),
|
|
723
|
+
criticality: z.enum(CRITICALITIES).default("normal"),
|
|
724
|
+
consult_jev: z.boolean().default(false).describe("Ask Jev to choose among the eligible options. Charged by Jev; off by default."),
|
|
725
|
+
launch: z
|
|
726
|
+
.object({
|
|
727
|
+
provider: z.enum(["codex", "pi", "copilot", "claude"]),
|
|
728
|
+
model: z.string().max(120).optional(),
|
|
729
|
+
evidence: z.string().min(1).max(500).describe("What shows it: a process line, a pane header."),
|
|
730
|
+
})
|
|
731
|
+
.optional()
|
|
732
|
+
.describe("What actually launched, as observed. A provider other than the approved one fails closed."),
|
|
733
|
+
},
|
|
734
|
+
annotations: READ,
|
|
735
|
+
}, wrap(async (a, extra) => {
|
|
736
|
+
const { person } = who(extra);
|
|
737
|
+
requireTier(person, "write");
|
|
738
|
+
const found = resolveMissionSubject(String(a.ref).trim(), records());
|
|
739
|
+
if (!found?.record) {
|
|
740
|
+
return {
|
|
741
|
+
contract: PREFLIGHT_CONTRACT,
|
|
742
|
+
version: PREFLIGHT_VERSION,
|
|
743
|
+
state: "mission_unresolved",
|
|
744
|
+
ref: a.ref,
|
|
745
|
+
identity: found ? { resolution: found.resolution, candidates: found.candidates } : { resolution: "not_found", candidates: [] },
|
|
746
|
+
note: "Name one mission by its record id; no model is chosen for an unidentified mission.",
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
const record = found.record;
|
|
750
|
+
const body = record.body;
|
|
751
|
+
const provider = (typeof body.resolved_provider === "string" ? body.resolved_provider : typeof body.provider === "string" ? body.provider : null);
|
|
752
|
+
const basis = record.approval_state === "approved" ? "approved" : "requested";
|
|
753
|
+
const candidates = candidatesFor(discoverProviders(ctx.providersProbe), provider, ctx.modelOf, basis);
|
|
754
|
+
const jevConfig = jevConfigOf(process.env);
|
|
755
|
+
const jev = a.consult_jev ? (ctx.jevAdapter ?? (jevConfig ? jevAdapter(jevConfig, ctx.approval?.fetchImpl ?? fetch) : undefined)) : undefined;
|
|
756
|
+
const configured = Boolean(jevConfig);
|
|
757
|
+
const primary = primaryIssueOf(record);
|
|
758
|
+
return modelPreflight({
|
|
759
|
+
mission: {
|
|
760
|
+
id: record.id,
|
|
761
|
+
resolution: found.resolution,
|
|
762
|
+
authorizes_actions: authorizesActions(found),
|
|
763
|
+
...(primary ? { primary_issue: primary.ref } : {}),
|
|
764
|
+
},
|
|
765
|
+
approved_provider: provider,
|
|
766
|
+
provider_basis: basis,
|
|
767
|
+
task: a.task_type,
|
|
768
|
+
criticality: a.criticality,
|
|
769
|
+
candidates,
|
|
770
|
+
...(a.launch ? { launch: a.launch } : {}),
|
|
771
|
+
...(jev ? { adapter: jev } : { routerWhenAbsent: configured ? "not_requested" : "router_unconfigured" }),
|
|
772
|
+
});
|
|
773
|
+
}));
|
|
692
774
|
// search / fetch: the pair ChatGPT uses for connectors in search and deep research.
|
|
693
775
|
server.registerTool("search", {
|
|
694
776
|
title: "Search Miadi",
|
|
@@ -975,6 +1057,7 @@ export function registerTools(server, ctx) {
|
|
|
975
1057
|
desired_outcome: z.string().min(1).max(6000),
|
|
976
1058
|
circle,
|
|
977
1059
|
refs,
|
|
1060
|
+
primary_issue: primaryIssue,
|
|
978
1061
|
repo: z.string().max(120).optional(),
|
|
979
1062
|
...base,
|
|
980
1063
|
},
|
|
@@ -984,13 +1067,13 @@ export function registerTools(server, ctx) {
|
|
|
984
1067
|
requireContribute(auth);
|
|
985
1068
|
const r = append("work_proposal", person, auth, {
|
|
986
1069
|
circle: a.circle,
|
|
987
|
-
refs: a.refs,
|
|
1070
|
+
refs: withPrimary(a.refs, a.primary_issue),
|
|
988
1071
|
intention: a.intention,
|
|
989
1072
|
role: a.role,
|
|
990
1073
|
idempotency_key: a.idempotency_key,
|
|
991
1074
|
state: "pending",
|
|
992
1075
|
approval_state: "awaiting_approval",
|
|
993
|
-
body: { title: a.title, desired_outcome: a.desired_outcome, repo: a.repo },
|
|
1076
|
+
body: { title: a.title, desired_outcome: a.desired_outcome, repo: a.repo, ...(a.primary_issue ? { primary_issue: a.primary_issue } : {}) },
|
|
994
1077
|
});
|
|
995
1078
|
return { ...r, approval_url: approvalUrl(r.id) };
|
|
996
1079
|
}));
|
|
@@ -1027,6 +1110,11 @@ export function registerTools(server, ctx) {
|
|
|
1027
1110
|
session_id: z.string().min(8),
|
|
1028
1111
|
ending: z.enum(["exit", "complete_then_exit", "record_only"]),
|
|
1029
1112
|
reason: z.string().min(1).max(4000),
|
|
1113
|
+
mission: z
|
|
1114
|
+
.string()
|
|
1115
|
+
.regex(/^(run_request|work_proposal):[\w-]+$/)
|
|
1116
|
+
.optional()
|
|
1117
|
+
.describe("The mission this ending closes, by record id. Only an approved exit or complete_then_exit that names the mission here closes it in mission_status (jgwill/Miadi#913)."),
|
|
1030
1118
|
evidence_refs: refs,
|
|
1031
1119
|
},
|
|
1032
1120
|
annotations: WRITE,
|
|
@@ -1036,11 +1124,11 @@ export function registerTools(server, ctx) {
|
|
|
1036
1124
|
const id = a.session_id.replace(/^session:/, "");
|
|
1037
1125
|
const r = append("session_completion_proposal", person, auth, {
|
|
1038
1126
|
circle: "continuity",
|
|
1039
|
-
refs: [`session:${id}`],
|
|
1127
|
+
refs: a.mission ? [`session:${id}`, a.mission] : [`session:${id}`],
|
|
1040
1128
|
evidence_refs: a.evidence_refs,
|
|
1041
1129
|
approval_state: "awaiting_approval",
|
|
1042
|
-
idempotency_key: `${id}:${a.ending}`,
|
|
1043
|
-
body: { session_id: id, ending: a.ending, reason: a.reason },
|
|
1130
|
+
idempotency_key: a.mission ? `${id}:${a.ending}:${a.mission}` : `${id}:${a.ending}`,
|
|
1131
|
+
body: { session_id: id, ending: a.ending, reason: a.reason, ...(a.mission ? { mission: a.mission } : {}) },
|
|
1044
1132
|
});
|
|
1045
1133
|
return { ...r, approval_url: approvalUrl(r.id) };
|
|
1046
1134
|
}));
|
|
@@ -1052,6 +1140,7 @@ export function registerTools(server, ctx) {
|
|
|
1052
1140
|
task: z.string().min(1).max(12000).describe("What the session does and what it returns."),
|
|
1053
1141
|
circle,
|
|
1054
1142
|
refs,
|
|
1143
|
+
primary_issue: primaryIssue,
|
|
1055
1144
|
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."),
|
|
1056
1145
|
cwd: z.string().max(300).optional().describe("Working folder for a new session (default the Miadi checkout)."),
|
|
1057
1146
|
provider: z
|
|
@@ -1081,7 +1170,7 @@ export function registerTools(server, ctx) {
|
|
|
1081
1170
|
}
|
|
1082
1171
|
const r = append("run_request", person, auth, {
|
|
1083
1172
|
circle: a.circle,
|
|
1084
|
-
refs: a.refs,
|
|
1173
|
+
refs: withPrimary(a.refs, a.primary_issue),
|
|
1085
1174
|
intention: a.intention,
|
|
1086
1175
|
role: a.role,
|
|
1087
1176
|
idempotency_key: a.idempotency_key,
|
|
@@ -1093,6 +1182,7 @@ export function registerTools(server, ctx) {
|
|
|
1093
1182
|
cwd: a.cwd,
|
|
1094
1183
|
provider: a.provider,
|
|
1095
1184
|
resolved_provider: resolution.provider.id,
|
|
1185
|
+
...(a.primary_issue ? { primary_issue: a.primary_issue } : {}),
|
|
1096
1186
|
...(a.steering ? { steering: a.steering } : {}),
|
|
1097
1187
|
},
|
|
1098
1188
|
});
|
|
@@ -1613,6 +1703,7 @@ export const TOOL_STATUS = {
|
|
|
1613
1703
|
list_records: "live",
|
|
1614
1704
|
get_run_result: "live",
|
|
1615
1705
|
mission_status: "live (operator details need the Miadi write tier)",
|
|
1706
|
+
mission_model_preflight: "live, Miadi write tier (static policy; Jev only with consult_jev and a Jev key on the host, otherwise router_unconfigured)",
|
|
1616
1707
|
provider_capabilities: "live, Miadi write tier",
|
|
1617
1708
|
search: "live",
|
|
1618
1709
|
fetch: "live",
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.13";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.1.
|
|
1
|
+
export const VERSION = "0.1.13";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miadi/connector",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
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",
|