automata-cli 0.12.0-develop.533 → 0.12.0-develop.554

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.
Files changed (2) hide show
  1. package/dist/index.js +99 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2633,7 +2633,7 @@ function addLabel(target, name, description) {
2633
2633
  const edit = target.kind === "pr" ? "pr" : "issue";
2634
2634
  const args = [edit, "edit", String(target.number), "--add-label", name];
2635
2635
  let result = run4("gh", args);
2636
- if (result.status !== 0 && isMissingLabelError(result.stderr)) {
2636
+ if (result.status !== 0 && isMissingLabelError(result.stderr, name)) {
2637
2637
  const created = run4("gh", ["label", "create", name, "--description", description]);
2638
2638
  if (created.status !== 0 && !/already exists/i.test(created.stderr)) {
2639
2639
  throw new Error(created.stderr.trim() || `Failed to create the label ${name}.`);
@@ -2732,8 +2732,11 @@ var MISSING_LABEL_PATTERNS = [
2732
2732
  /could not resolve to a label/i,
2733
2733
  /\blabels?\b[^\n]*\b(?:not found|does not exist)\b/i
2734
2734
  ];
2735
- function isMissingLabelError(stderr) {
2736
- return MISSING_LABEL_PATTERNS.some((pattern) => pattern.test(stderr));
2735
+ function isMissingLabelError(stderr, name) {
2736
+ if (MISSING_LABEL_PATTERNS.some((pattern) => pattern.test(stderr))) {
2737
+ return true;
2738
+ }
2739
+ return name !== void 0 && stderr.includes(`'${name}' not found`);
2737
2740
  }
2738
2741
  function createDraftPullRequest(input) {
2739
2742
  const base = [
@@ -2752,7 +2755,7 @@ function createDraftPullRequest(input) {
2752
2755
  if (input.label !== void 0 && input.label.length > 0) {
2753
2756
  const labelled = run4("gh", [...base, "--label", input.label]);
2754
2757
  if (labelled.status === 0) return parseCreatedPrUrl(labelled.stdout, input.head);
2755
- if (!isMissingLabelError(labelled.stderr)) {
2758
+ if (!isMissingLabelError(labelled.stderr, input.label)) {
2756
2759
  throw new Error(
2757
2760
  labelled.stderr.trim() || `Failed to open a draft pull request for ${input.head}.`
2758
2761
  );
@@ -2966,7 +2969,7 @@ function runClaude(prompt, options = {}) {
2966
2969
  if (options.printSteps !== true) return;
2967
2970
  try {
2968
2971
  const event = JSON.parse(line);
2969
- formatEvent(event, turnCount);
2972
+ formatEvent(event, turnCount, options.echoResult !== false);
2970
2973
  if (event["type"] === "assistant") turnCount++;
2971
2974
  } catch {
2972
2975
  }
@@ -3056,7 +3059,7 @@ function formatContentBlock(block) {
3056
3059
  }
3057
3060
  return null;
3058
3061
  }
3059
- function formatResultEvent(event) {
3062
+ function formatResultEvent(event, echoResult) {
3060
3063
  const result = event["result"];
3061
3064
  const cost = event["cost_usd"];
3062
3065
  const duration = event["duration_ms"];
@@ -3070,16 +3073,16 @@ function formatResultEvent(event) {
3070
3073
  process.stderr.write(` [info] ${parts.join(" | ")}
3071
3074
  `);
3072
3075
  }
3073
- if (result) {
3076
+ if (result && echoResult) {
3074
3077
  process.stdout.write(result + "\n");
3075
3078
  }
3076
3079
  }
3077
- function formatEvent(event, turnCount) {
3080
+ function formatEvent(event, turnCount, echoResult = true) {
3078
3081
  const type = event["type"];
3079
3082
  if (type === "assistant") {
3080
3083
  formatAssistantEvent(event, turnCount);
3081
3084
  } else if (type === "result") {
3082
- formatResultEvent(event);
3085
+ formatResultEvent(event, echoResult);
3083
3086
  }
3084
3087
  }
3085
3088
  function asText(value, fallback) {
@@ -8892,6 +8895,48 @@ function withoutWatched(list, id) {
8892
8895
  return list.filter((entry) => entry !== id);
8893
8896
  }
8894
8897
 
8898
+ // src/conductor/permissionDenials.ts
8899
+ var MAX_TARGET_LENGTH = 300;
8900
+ function targetOf(input) {
8901
+ if (typeof input !== "object" || input === null) return "";
8902
+ const record = input;
8903
+ for (const key2 of ["command", "file_path", "path", "pattern"]) {
8904
+ const value = record[key2];
8905
+ if (typeof value === "string") return value;
8906
+ }
8907
+ return JSON.stringify(input);
8908
+ }
8909
+ function denialOf(entry) {
8910
+ if (typeof entry !== "object" || entry === null) return null;
8911
+ const record = entry;
8912
+ const tool = record["tool_name"];
8913
+ if (typeof tool !== "string") return null;
8914
+ return { tool, target: targetOf(record["tool_input"]) };
8915
+ }
8916
+ function parsePermissionDenials(stdout) {
8917
+ const denials = [];
8918
+ for (const line of stdout.split("\n")) {
8919
+ if (!line.trim().startsWith("{")) continue;
8920
+ try {
8921
+ const event = JSON.parse(line);
8922
+ const listed = event["type"] === "result" ? event["permission_denials"] : void 0;
8923
+ if (!Array.isArray(listed)) continue;
8924
+ for (const entry of listed) {
8925
+ const denial = denialOf(entry);
8926
+ if (denial !== null) denials.push(denial);
8927
+ }
8928
+ } catch {
8929
+ }
8930
+ }
8931
+ return denials;
8932
+ }
8933
+ function describePermissionDenials(denials) {
8934
+ return denials.map((denial) => {
8935
+ const flat = `${denial.tool} ${denial.target}`.replace(/[\u0000-\u001f\u007f-\u009f]+/g, " ").replace(/\s+/g, " ").trim();
8936
+ return flat.length <= MAX_TARGET_LENGTH ? flat : `${flat.slice(0, MAX_TARGET_LENGTH)}\u2026`;
8937
+ });
8938
+ }
8939
+
8895
8940
  // src/commands/conductor.ts
8896
8941
  function fail2(message) {
8897
8942
  process.stderr.write(`Error: ${message}
@@ -8956,7 +9001,29 @@ function readTargetMessages(target) {
8956
9001
  }
8957
9002
  function runModel(prompt, execution, replyTo, sink2) {
8958
9003
  const { owner, repo } = getRepoSlug();
8959
- return runClaude(prompt, { model: execution.model, effort: execution.effort, readOnly: true, replyTo, ghRepo: `${owner}/${repo}`, sink: sink2 });
9004
+ return runClaude(prompt, { model: execution.model, effort: execution.effort, readOnly: true, replyTo, ghRepo: `${owner}/${repo}`, sink: sink2, printSteps: verboseRun, echoResult: false });
9005
+ }
9006
+ var verboseRun = false;
9007
+ function reportDenials(stdout, label2) {
9008
+ if (!verboseRun || stdout.length === 0) return;
9009
+ const lines = describePermissionDenials(parsePermissionDenials(stdout));
9010
+ if (lines.length === 0) {
9011
+ process.stderr.write(`Conductor: the run for ${label2} reported no denied tool call.
9012
+ `);
9013
+ return;
9014
+ }
9015
+ process.stderr.write(`Conductor: the run for ${label2} was denied ${String(lines.length)} tool call(s):
9016
+ `);
9017
+ for (const line of lines) process.stderr.write(` - ${line}
9018
+ `);
9019
+ }
9020
+ function reportCommandTrace() {
9021
+ const trace = takeCommandTrace();
9022
+ if (trace === null) return;
9023
+ process.stderr.write(`Commands (${String(trace.length)})
9024
+ `);
9025
+ for (const traced of trace) process.stderr.write(` ${describeTracedCommand(traced)}
9026
+ `);
8960
9027
  }
8961
9028
  function captureStdout() {
8962
9029
  let stdout = "";
@@ -8971,8 +9038,12 @@ function captureStdout() {
8971
9038
  async function runModelForText(prompt, execution) {
8972
9039
  const { owner, repo } = getRepoSlug();
8973
9040
  const captured = captureStdout();
8974
- const options = { model: execution.model, effort: execution.effort, readOnly: true, ghRepo: `${owner}/${repo}`, sink: captured.sink };
8975
- await runClaude(prompt, options);
9041
+ const options = { model: execution.model, effort: execution.effort, readOnly: true, ghRepo: `${owner}/${repo}`, sink: captured.sink, printSteps: verboseRun, echoResult: false };
9042
+ try {
9043
+ await runClaude(prompt, options);
9044
+ } finally {
9045
+ reportDenials(captured.text(), "the dry run");
9046
+ }
8976
9047
  return extractDryRunReply(execution.executor, captured.text());
8977
9048
  }
8978
9049
  function coveredOf(watch, linkMap) {
@@ -9052,6 +9123,7 @@ async function conductItem(id, config, login2, participants, execution, dryRun,
9052
9123
  read: () => readTargetMessages(replyTo),
9053
9124
  run: () => runModel(prompt, execution, replyTo, captured.sink)
9054
9125
  });
9126
+ reportDenials(captured.text(), label2);
9055
9127
  const needsHuman = parseNeedsHuman(extractDryRunReply(execution.executor, captured.text()) ?? "");
9056
9128
  if (needsHuman !== null && outcome.kind !== "run-failed" && outcome.kind !== "unverified") {
9057
9129
  return blockItem(item, label2, needsHuman);
@@ -9300,6 +9372,17 @@ function reportHeldLock(held, suspect, staleMinutes) {
9300
9372
  return 2;
9301
9373
  }
9302
9374
  async function runConductor(options = {}) {
9375
+ verboseRun = options.verbose === true;
9376
+ if (verboseRun) startCommandTrace();
9377
+ try {
9378
+ return await runConductorTick(options);
9379
+ } finally {
9380
+ reportCommandTrace();
9381
+ verboseRun = false;
9382
+ stopCommandTrace();
9383
+ }
9384
+ }
9385
+ async function runConductorTick(options) {
9303
9386
  if (options.check === true && options.dryRun === true) {
9304
9387
  return fail2("--check and --dry-run cannot be used together.");
9305
9388
  }
@@ -9340,7 +9423,10 @@ async function runConductor(options = {}) {
9340
9423
  }
9341
9424
  var conductorCommand = new Command7("conductor").description(
9342
9425
  "Run one conductor tick as an allowed (human) account: verify the identity, take the conductor's own run lock, then act"
9343
- ).option("--check", "Report what a tick would do, including pending prunes, and change nothing; exit 1 on a problem").option("--dry-run", "Run the model for each owed reply and print it instead of posting; no lock, no prune").action(async (options) => {
9426
+ ).option("--check", "Report what a tick would do, including pending prunes, and change nothing; exit 1 on a problem").option("--dry-run", "Run the model for each owed reply and print it instead of posting; no lock, no prune").option(
9427
+ "--verbose",
9428
+ "Trace every `git` and `gh` call with its duration and exit code, show the model's steps, and list the tool calls the run was denied"
9429
+ ).action(async (options) => {
9344
9430
  exitWith(await runConductor(options));
9345
9431
  });
9346
9432
  conductorCommand.command("add <id>").description("Watch an issue or pull request and make do-work pick it up (an issue also follows its linked PR)").action((id) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "automata-cli",
3
- "version": "0.12.0-develop.533",
3
+ "version": "0.12.0-develop.554",
4
4
  "description": "Automata CLI tool",
5
5
  "type": "module",
6
6
  "engines": {