@sjawhar/pi-envoy 10.17.4 → 10.17.6
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/dispatch.js +77 -27
- package/dist/envoy.js +26 -9
- package/dist/skills/envoy/SKILL.md +3 -1
- package/package.json +1 -1
package/dist/dispatch.js
CHANGED
|
@@ -13927,7 +13927,7 @@ function dispatchToolSchema(spec, z2, opts) {
|
|
|
13927
13927
|
const shape = spec.arguments(z2);
|
|
13928
13928
|
const strict = opts?.strict ?? spec.strict;
|
|
13929
13929
|
const schemaOptions = strict === undefined ? undefined : { strict };
|
|
13930
|
-
return spec.validation === undefined ? z2.object(shape, schemaOptions) : z2.refineObject(shape, spec.validation.check, spec.validation.message, schemaOptions);
|
|
13930
|
+
return spec.validation === undefined ? z2.object(shape, schemaOptions) : z2.refineObject(shape, spec.validation.check, spec.validation.refusal ?? spec.validation.message, schemaOptions);
|
|
13931
13931
|
}
|
|
13932
13932
|
var ISSUE_REFERENCE = "An issue is a native KEY or external owner/repo#n reference. An external reference addresses an existing Dispatch issue, including one linked to that GitHub pull request; only dispatch issue with --external creates a native issue.";
|
|
13933
13933
|
var OWNER_REFERENCE = "Exactly one of issue and project is required. An issue is a native KEY or external owner/repo#n reference; a project is a project key such as CORE and addresses an unlinked project document named by artifact.";
|
|
@@ -13969,6 +13969,23 @@ var commentValidation = {
|
|
|
13969
13969
|
},
|
|
13970
13970
|
message: `${commentOwner.message} turn requires reply_to_ask.`
|
|
13971
13971
|
};
|
|
13972
|
+
var ISSUE_UPDATE_FIELDS_RULE = "Issue update requires at least one field besides issue: status, title, labels, priority, external_links, route, parent, blocked_by, components, or repo.";
|
|
13973
|
+
var ISSUE_UPDATE_DONE_RULE = "status done requires reason, a non-empty note saying why the issue is closing, posted on the issue before it closes because a closed issue refuses messages, comments, and artifacts";
|
|
13974
|
+
var ISSUE_UPDATE_REASON_RULE = "reason goes only with status done";
|
|
13975
|
+
var ISSUE_UPDATE_RULE = `${ISSUE_UPDATE_FIELDS_RULE} ${ISSUE_UPDATE_DONE_RULE}; ${ISSUE_UPDATE_REASON_RULE}.`;
|
|
13976
|
+
function issueUpdateProblem(value) {
|
|
13977
|
+
const input = value;
|
|
13978
|
+
if (input.status === "done") {
|
|
13979
|
+
if (typeof input.reason !== "string" || input.reason.trim() === "") {
|
|
13980
|
+
return `${ISSUE_UPDATE_DONE_RULE}.`;
|
|
13981
|
+
}
|
|
13982
|
+
} else if (input.reason !== undefined) {
|
|
13983
|
+
const status = typeof input.status === "string" ? `status ${input.status}` : "an update without status done";
|
|
13984
|
+
return `${ISSUE_UPDATE_REASON_RULE}: it is the note posted on the issue as it closes, and ${status} closes nothing. Drop reason, or set status done to close the issue.`;
|
|
13985
|
+
}
|
|
13986
|
+
const changesAField = typeof input.status === "string" || typeof input.title === "string" || Array.isArray(input.labels) || typeof input.priority === "number" || input.priority === null || Array.isArray(input.external_links) || typeof input.route === "string" || typeof input.parent === "string" || Array.isArray(input.blocked_by) || typeof input.components === "object" && input.components !== null || typeof input.repo === "string";
|
|
13987
|
+
return changesAField ? undefined : ISSUE_UPDATE_FIELDS_RULE;
|
|
13988
|
+
}
|
|
13972
13989
|
var messageValidation = {
|
|
13973
13990
|
check: (value) => {
|
|
13974
13991
|
const input = value;
|
|
@@ -14070,12 +14087,9 @@ var dispatchToolSpecs = [
|
|
|
14070
14087
|
repo: z2.string().describe("The repository the issue targets, owner/name, mapped to the issue's project in Settings; an empty string clears it, so the issue inherits its parent's or the project's default again.").optional()
|
|
14071
14088
|
}),
|
|
14072
14089
|
validation: {
|
|
14073
|
-
check: (value) =>
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
return reasonFits && (typeof input.status === "string" || typeof input.title === "string" || Array.isArray(input.labels) || typeof input.priority === "number" || input.priority === null || Array.isArray(input.external_links) || typeof input.route === "string" || typeof input.parent === "string" || Array.isArray(input.blocked_by) || typeof input.components === "object" && input.components !== null || typeof input.repo === "string");
|
|
14077
|
-
},
|
|
14078
|
-
message: "Issue update requires at least one field besides issue: status, title, labels, priority, external_links, route, parent, blocked_by, components, or repo. " + "status done requires reason, a non-empty note saying why the issue is closing, posted on the issue before it closes because a closed issue refuses messages, comments, and artifacts; reason goes only with status done."
|
|
14090
|
+
check: (value) => issueUpdateProblem(value) === undefined,
|
|
14091
|
+
message: ISSUE_UPDATE_RULE,
|
|
14092
|
+
refusal: (value) => issueUpdateProblem(value) ?? ISSUE_UPDATE_RULE
|
|
14079
14093
|
},
|
|
14080
14094
|
strict: true
|
|
14081
14095
|
},
|
|
@@ -14529,7 +14543,7 @@ function zodSchemaApi(zod) {
|
|
|
14529
14543
|
let schema = api2.object(shape);
|
|
14530
14544
|
if (opts.strict)
|
|
14531
14545
|
schema = schema.strict();
|
|
14532
|
-
return schema.refine(check2, message);
|
|
14546
|
+
return schema.refine(check2, typeof message === "string" ? message : { error: (issue2) => message(issue2.input) });
|
|
14533
14547
|
}
|
|
14534
14548
|
};
|
|
14535
14549
|
}
|
|
@@ -14715,7 +14729,10 @@ function flagTable(tool, fields) {
|
|
|
14715
14729
|
}
|
|
14716
14730
|
}
|
|
14717
14731
|
add("--help", { action: "help", text: "Prints this help." });
|
|
14718
|
-
add("--dry-run", {
|
|
14732
|
+
add("--dry-run", {
|
|
14733
|
+
action: "dry-run",
|
|
14734
|
+
text: "Checks the arguments as the call would, then prints them as JSON and sends nothing."
|
|
14735
|
+
});
|
|
14719
14736
|
return flags;
|
|
14720
14737
|
}
|
|
14721
14738
|
function parseCommand(argv, io) {
|
|
@@ -14971,7 +14988,7 @@ function commandsHelp() {
|
|
|
14971
14988
|
return ` ${commandName(spec.name).padEnd(width)} ${sentence}`;
|
|
14972
14989
|
}),
|
|
14973
14990
|
"",
|
|
14974
|
-
"Run dispatch <command> --help for its flags and an example; --dry-run
|
|
14991
|
+
"Run dispatch <command> --help for its flags and an example; --dry-run checks a command's arguments as the call would and prints them as given, sending nothing.",
|
|
14975
14992
|
""
|
|
14976
14993
|
].join(`
|
|
14977
14994
|
`);
|
|
@@ -17568,6 +17585,34 @@ function withAccount(error48, account) {
|
|
|
17568
17585
|
const told = /[.!?]$/.test(message) ? `${message} ${account.charAt(0).toUpperCase()}${account.slice(1)}` : `${message}; ${account}`;
|
|
17569
17586
|
return new Error(told, { cause: error48 });
|
|
17570
17587
|
}
|
|
17588
|
+
function restatesMissingOwner(issue2) {
|
|
17589
|
+
return issue2.code === "invalid_type" && issue2.path.length === 1 && issue2.path[0] === "issue" && issue2.input === undefined || issue2.code === "custom" && issue2.path.length === 0 && (issue2.message.startsWith("Exactly one of issue and project is required") || issue2.message.startsWith("issue is required unless in_reply_to"));
|
|
17590
|
+
}
|
|
17591
|
+
function dispatchServerUrls(config2) {
|
|
17592
|
+
return config2.publicUrl === undefined ? [config2.url] : [config2.url, config2.publicUrl];
|
|
17593
|
+
}
|
|
17594
|
+
async function checkDispatchCall(input) {
|
|
17595
|
+
const { tool, args, cwd } = input;
|
|
17596
|
+
const problems = [];
|
|
17597
|
+
const owner = await resolveOwnerArguments(tool, args, cwd, input.env ?? process.env, input.exec ?? defaultExec, input.serverUrls, problems);
|
|
17598
|
+
const conflicts = issueFreeTools[tool] === true ? [] : ownerConflictProblems(tool, args, owner.ref, optionalString(owner.args, "ref"));
|
|
17599
|
+
problems.push(...conflicts);
|
|
17600
|
+
const ownerMissing = issueFreeTools[tool] !== true && (owner.owner === null || conflicts.length > 0);
|
|
17601
|
+
const schema = toolSchema(tool);
|
|
17602
|
+
const parsed = schema.safeParse(owner.args, { reportInput: true });
|
|
17603
|
+
if (!parsed.success) {
|
|
17604
|
+
const issues = ownerMissing ? parsed.error.issues.filter((issue2) => !restatesMissingOwner(issue2)) : parsed.error.issues;
|
|
17605
|
+
problems.push(...formatZodIssues(issues, schema, tool));
|
|
17606
|
+
}
|
|
17607
|
+
problems.push(...argumentProblems(tool, owner.args));
|
|
17608
|
+
const pictures = pictureSendingTools[tool] === true ? await localPictures(owner.args.images, cwd, problems) : [];
|
|
17609
|
+
return {
|
|
17610
|
+
problems,
|
|
17611
|
+
owner,
|
|
17612
|
+
args: parsed.success ? parsed.data : owner.args,
|
|
17613
|
+
pictures
|
|
17614
|
+
};
|
|
17615
|
+
}
|
|
17571
17616
|
async function executeDispatchTool(input) {
|
|
17572
17617
|
const { url: configUrl, token: configToken } = input.config;
|
|
17573
17618
|
const linkBase = input.config.publicUrl ?? configUrl;
|
|
@@ -17584,21 +17629,14 @@ async function executeDispatchTool(input) {
|
|
|
17584
17629
|
}, { preconnect: baseFetch.preconnect });
|
|
17585
17630
|
const env = input.env ?? process.env;
|
|
17586
17631
|
const exec = input.exec ?? defaultExec;
|
|
17587
|
-
const
|
|
17588
|
-
|
|
17589
|
-
|
|
17590
|
-
|
|
17591
|
-
|
|
17592
|
-
|
|
17593
|
-
const
|
|
17594
|
-
|
|
17595
|
-
const issues = parsed.error.issues.filter((issue3) => !ownerMissing || !(issue3.code === "invalid_type" && issue3.path.length === 1 && issue3.path[0] === "issue" && issue3.input === undefined || issue3.code === "custom" && issue3.path.length === 0 && (issue3.message.startsWith("Exactly one of issue and project is required") || issue3.message.startsWith("issue is required unless in_reply_to"))));
|
|
17596
|
-
problems.push(...formatZodIssues(issues, schema, input.tool));
|
|
17597
|
-
}
|
|
17598
|
-
problems.push(...argumentProblems(input.tool, ownerArguments.args));
|
|
17599
|
-
const pictures = pictureSendingTools[input.tool] === true ? await localPictures(ownerArguments.args.images, input.cwd, problems) : [];
|
|
17600
|
-
if (problems.length > 0)
|
|
17601
|
-
throw new ToolInputError(input.tool, problems);
|
|
17632
|
+
const checked = await checkDispatchCall({
|
|
17633
|
+
...input,
|
|
17634
|
+
serverUrls: dispatchServerUrls(input.config)
|
|
17635
|
+
});
|
|
17636
|
+
if (checked.problems.length > 0)
|
|
17637
|
+
throw new ToolInputError(input.tool, checked.problems);
|
|
17638
|
+
const ownerArguments = checked.owner;
|
|
17639
|
+
const pictures = checked.pictures;
|
|
17602
17640
|
const dispatchClient = () => new DispatchClient(configUrl, configToken, fetchImpl, input.signal);
|
|
17603
17641
|
if (input.tool === "dispatch_open_asks") {
|
|
17604
17642
|
const client2 = dispatchClient();
|
|
@@ -17627,7 +17665,7 @@ async function executeDispatchTool(input) {
|
|
|
17627
17665
|
details: { session: sessionId, owner: owner2, service }
|
|
17628
17666
|
};
|
|
17629
17667
|
}
|
|
17630
|
-
const args =
|
|
17668
|
+
const args = checked.args;
|
|
17631
17669
|
const actor = toolActor(await resolveOrigin(env, exec, input.cwd), input);
|
|
17632
17670
|
const client = dispatchClient();
|
|
17633
17671
|
const refDocument = ownerArguments.ref?.kind === "artifact" ? ownerArguments.ref.id : ownerArguments.ref?.artifact;
|
|
@@ -19717,11 +19755,23 @@ async function runDispatchCli(argv, rawEnv, io) {
|
|
|
19717
19755
|
print(messageFor(error48));
|
|
19718
19756
|
return USAGE;
|
|
19719
19757
|
}
|
|
19758
|
+
const file2 = (env.DISPATCH_HOST === undefined ? null : handedConfigFile(env)) ?? sessionConfigFile(host, env);
|
|
19720
19759
|
if (parsed.dryRun) {
|
|
19760
|
+
const settings = file2.path === null ? null : sessionDispatchSettings(file2, env, { cwd: io.cwd }).dispatch;
|
|
19761
|
+
const { problems: problems2 } = await checkDispatchCall({
|
|
19762
|
+
tool: parsed.tool,
|
|
19763
|
+
args: parsed.args,
|
|
19764
|
+
cwd: io.cwd,
|
|
19765
|
+
env,
|
|
19766
|
+
serverUrls: settings?.enabled === true ? dispatchServerUrls(settings) : []
|
|
19767
|
+
});
|
|
19768
|
+
if (problems2.length > 0) {
|
|
19769
|
+
print(new ToolInputError(parsed.tool, problems2).message);
|
|
19770
|
+
return REFUSED;
|
|
19771
|
+
}
|
|
19721
19772
|
print(JSON.stringify(parsed.args, null, 2));
|
|
19722
19773
|
return OK;
|
|
19723
19774
|
}
|
|
19724
|
-
const file2 = (env.DISPATCH_HOST === undefined ? null : handedConfigFile(env)) ?? sessionConfigFile(host, env);
|
|
19725
19775
|
if (file2.path === null) {
|
|
19726
19776
|
print(`dispatch: ${file2.error}`);
|
|
19727
19777
|
return USAGE;
|
package/dist/envoy.js
CHANGED
|
@@ -29914,7 +29914,7 @@ function dispatchToolSchema(spec, z2, opts) {
|
|
|
29914
29914
|
const shape = spec.arguments(z2);
|
|
29915
29915
|
const strict = opts?.strict ?? spec.strict;
|
|
29916
29916
|
const schemaOptions = strict === undefined ? undefined : { strict };
|
|
29917
|
-
return spec.validation === undefined ? z2.object(shape, schemaOptions) : z2.refineObject(shape, spec.validation.check, spec.validation.message, schemaOptions);
|
|
29917
|
+
return spec.validation === undefined ? z2.object(shape, schemaOptions) : z2.refineObject(shape, spec.validation.check, spec.validation.refusal ?? spec.validation.message, schemaOptions);
|
|
29918
29918
|
}
|
|
29919
29919
|
var ISSUE_REFERENCE = "An issue is a native KEY or external owner/repo#n reference. An external reference addresses an existing Dispatch issue, including one linked to that GitHub pull request; only dispatch issue with --external creates a native issue.";
|
|
29920
29920
|
var OWNER_REFERENCE = "Exactly one of issue and project is required. An issue is a native KEY or external owner/repo#n reference; a project is a project key such as CORE and addresses an unlinked project document named by artifact.";
|
|
@@ -29956,6 +29956,23 @@ var commentValidation = {
|
|
|
29956
29956
|
},
|
|
29957
29957
|
message: `${commentOwner.message} turn requires reply_to_ask.`
|
|
29958
29958
|
};
|
|
29959
|
+
var ISSUE_UPDATE_FIELDS_RULE = "Issue update requires at least one field besides issue: status, title, labels, priority, external_links, route, parent, blocked_by, components, or repo.";
|
|
29960
|
+
var ISSUE_UPDATE_DONE_RULE = "status done requires reason, a non-empty note saying why the issue is closing, posted on the issue before it closes because a closed issue refuses messages, comments, and artifacts";
|
|
29961
|
+
var ISSUE_UPDATE_REASON_RULE = "reason goes only with status done";
|
|
29962
|
+
var ISSUE_UPDATE_RULE = `${ISSUE_UPDATE_FIELDS_RULE} ${ISSUE_UPDATE_DONE_RULE}; ${ISSUE_UPDATE_REASON_RULE}.`;
|
|
29963
|
+
function issueUpdateProblem(value) {
|
|
29964
|
+
const input = value;
|
|
29965
|
+
if (input.status === "done") {
|
|
29966
|
+
if (typeof input.reason !== "string" || input.reason.trim() === "") {
|
|
29967
|
+
return `${ISSUE_UPDATE_DONE_RULE}.`;
|
|
29968
|
+
}
|
|
29969
|
+
} else if (input.reason !== undefined) {
|
|
29970
|
+
const status = typeof input.status === "string" ? `status ${input.status}` : "an update without status done";
|
|
29971
|
+
return `${ISSUE_UPDATE_REASON_RULE}: it is the note posted on the issue as it closes, and ${status} closes nothing. Drop reason, or set status done to close the issue.`;
|
|
29972
|
+
}
|
|
29973
|
+
const changesAField = typeof input.status === "string" || typeof input.title === "string" || Array.isArray(input.labels) || typeof input.priority === "number" || input.priority === null || Array.isArray(input.external_links) || typeof input.route === "string" || typeof input.parent === "string" || Array.isArray(input.blocked_by) || typeof input.components === "object" && input.components !== null || typeof input.repo === "string";
|
|
29974
|
+
return changesAField ? undefined : ISSUE_UPDATE_FIELDS_RULE;
|
|
29975
|
+
}
|
|
29959
29976
|
var messageValidation = {
|
|
29960
29977
|
check: (value) => {
|
|
29961
29978
|
const input = value;
|
|
@@ -30057,12 +30074,9 @@ var dispatchToolSpecs = [
|
|
|
30057
30074
|
repo: z2.string().describe("The repository the issue targets, owner/name, mapped to the issue's project in Settings; an empty string clears it, so the issue inherits its parent's or the project's default again.").optional()
|
|
30058
30075
|
}),
|
|
30059
30076
|
validation: {
|
|
30060
|
-
check: (value) =>
|
|
30061
|
-
|
|
30062
|
-
|
|
30063
|
-
return reasonFits && (typeof input.status === "string" || typeof input.title === "string" || Array.isArray(input.labels) || typeof input.priority === "number" || input.priority === null || Array.isArray(input.external_links) || typeof input.route === "string" || typeof input.parent === "string" || Array.isArray(input.blocked_by) || typeof input.components === "object" && input.components !== null || typeof input.repo === "string");
|
|
30064
|
-
},
|
|
30065
|
-
message: "Issue update requires at least one field besides issue: status, title, labels, priority, external_links, route, parent, blocked_by, components, or repo. " + "status done requires reason, a non-empty note saying why the issue is closing, posted on the issue before it closes because a closed issue refuses messages, comments, and artifacts; reason goes only with status done."
|
|
30077
|
+
check: (value) => issueUpdateProblem(value) === undefined,
|
|
30078
|
+
message: ISSUE_UPDATE_RULE,
|
|
30079
|
+
refusal: (value) => issueUpdateProblem(value) ?? ISSUE_UPDATE_RULE
|
|
30066
30080
|
},
|
|
30067
30081
|
strict: true
|
|
30068
30082
|
},
|
|
@@ -30532,7 +30546,7 @@ function zodSchemaApi(zod) {
|
|
|
30532
30546
|
let schema = api2.object(shape);
|
|
30533
30547
|
if (opts.strict)
|
|
30534
30548
|
schema = schema.strict();
|
|
30535
|
-
return schema.refine(check2, message);
|
|
30549
|
+
return schema.refine(check2, typeof message === "string" ? message : { error: (issue2) => message(issue2.input) });
|
|
30536
30550
|
}
|
|
30537
30551
|
};
|
|
30538
30552
|
}
|
|
@@ -31249,7 +31263,10 @@ function flagTable(tool, fields) {
|
|
|
31249
31263
|
}
|
|
31250
31264
|
}
|
|
31251
31265
|
add("--help", { action: "help", text: "Prints this help." });
|
|
31252
|
-
add("--dry-run", {
|
|
31266
|
+
add("--dry-run", {
|
|
31267
|
+
action: "dry-run",
|
|
31268
|
+
text: "Checks the arguments as the call would, then prints them as JSON and sends nothing."
|
|
31269
|
+
});
|
|
31253
31270
|
return flags;
|
|
31254
31271
|
}
|
|
31255
31272
|
function quoteWord(value) {
|
|
@@ -167,7 +167,9 @@ advertises.
|
|
|
167
167
|
Subscribe to `notifications.github.example-org.example-repo.pr.42.>` and end the turn. The single
|
|
168
168
|
`pr.42.checks` event whose `sha` is the current head wakes you when it settles (an earlier
|
|
169
169
|
commit's settlement can arrive first); a `pr.42` `closed` event with
|
|
170
|
-
`merged: true` tells you the PR merged. Do not create `gh` pollers.
|
|
170
|
+
`merged: true` tells you the PR merged. Do not create `gh` pollers. A Legion implementer waits this
|
|
171
|
+
way only on a re-run of a red its task names; otherwise it pushes and completes its phase, and the
|
|
172
|
+
daemon reads CI for it (`skill://legion-worker`).
|
|
171
173
|
Settlement waits for the commit to be quiet for a few seconds, every reported check run to finish,
|
|
172
174
|
and every recorded GitHub check suite to be `completed`. It covers those reported checks and suites
|
|
173
175
|
for that commit, not GitHub's required-checks set; until then, a silent subscription is normal.
|