@sweny-ai/core 0.1.200 → 0.1.202

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.
@@ -1,10 +1,11 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import { hasCodexLogin } from "../agent-env.js";
3
+ import { registerDeprecatedFlags } from "./deprecated-flags.js";
3
4
  import { parseAcpAgent, unsupportedAgentError } from "../harness/agents.js";
4
5
  export function registerTriageCommand(program) {
5
6
  // NOTE: File-eligible options omit Commander defaults so parseCliInputs() can
6
7
  // distinguish "user passed flag" from "not passed" and fall through to .sweny.yml.
7
- return program
8
+ const cmd = program
8
9
  .command("triage")
9
10
  .description("Run the SWEny triage workflow")
10
11
  .option("--agent <provider>", "Coding agent: claude (default), codex, pi (experimental), or acp:<command> for any ACP agent (experimental)")
@@ -55,6 +56,7 @@ export function registerTriageCommand(program) {
55
56
  .option("--workspace-tools <tools>", "Comma-separated workspace tool integrations to enable (slack, notion, pagerduty, monday)")
56
57
  .option("--offline", "Skip URL Sources and fail fast if any are referenced", false)
57
58
  .option("--file-root [dir]", "Sandbox file: Sources to this directory tree (defaults to the working directory when the flag is given without a value)");
59
+ return registerDeprecatedFlags(cmd);
58
60
  }
59
61
  export function parseCliInputs(options, fileConfig = {}) {
60
62
  const env = process.env;
@@ -615,7 +617,7 @@ function parseObservabilityCredentials(provider, options, fileConfig = {}) {
615
617
  }
616
618
  }
617
619
  export function registerImplementCommand(program) {
618
- return program
620
+ const cmd = program
619
621
  .command("implement <issueId>")
620
622
  .description("Implement a fix for a specific issue and open a PR")
621
623
  .option("--agent <provider>", "Coding agent: claude (default), codex, pi (experimental), or acp:<command> for any ACP agent (experimental)")
@@ -634,6 +636,7 @@ export function registerImplementCommand(program) {
634
636
  .option("--verbose", "Print each tool call's input and output inline (human-readable, truncated). Use --stream for full untruncated NDJSON.", false)
635
637
  .option("--offline", "Skip URL Sources and fail fast if any are referenced", false)
636
638
  .option("--file-root [dir]", "Sandbox file: Sources to this directory tree (defaults to the working directory when the flag is given without a value)");
639
+ return registerDeprecatedFlags(cmd);
637
640
  }
638
641
  /**
639
642
  * Parse a JSON string into MCP server configs.
@@ -0,0 +1,35 @@
1
+ import { type Command } from "commander";
2
+ /**
3
+ * CLI flags that sweny parsed but never read, removed in #528 and restored
4
+ * here as deprecated no-ops so existing callers (the swenyai/triage action
5
+ * passes most of them) keep working through a deprecation period.
6
+ *
7
+ * Each one is accepted, hidden from `--help`, changes nothing, and prints one
8
+ * stderr warning per run. This table is the only place the list lives;
9
+ * `registerDeprecatedFlags` is the only place it is wired in, once per command.
10
+ *
11
+ * Env vars and `.sweny.yml` keys for the same settings are not parsed at all
12
+ * and are never rejected, so they need no handling.
13
+ *
14
+ * Remove an entry (and its command wiring) in a minor release after the
15
+ * deprecation period; the docs-cloud-positioning test keeps these out of
16
+ * `--help` and out of the supported-option docs tables.
17
+ */
18
+ export interface DeprecatedFlag {
19
+ /** Commander flag spec, e.g. "--cache-dir <path>". */
20
+ flag: string;
21
+ /** Commands that accepted this flag before it was removed. */
22
+ commands: readonly string[];
23
+ /** Why it has no effect (kept for maintainers; not printed). */
24
+ note: string;
25
+ }
26
+ export declare const DEPRECATED_FLAGS: readonly DeprecatedFlag[];
27
+ /** `--cache-dir <path>` -> `--cache-dir`. */
28
+ export declare function deprecatedFlagName(spec: string): string;
29
+ export declare function deprecationWarning(flags: readonly string[]): string;
30
+ /**
31
+ * Accept every deprecated flag that `cmd` used to have. Hidden from help, no
32
+ * effect, and exactly one stderr warning per run naming the flags that were
33
+ * passed.
34
+ */
35
+ export declare function registerDeprecatedFlags(cmd: Command): Command;
@@ -0,0 +1,44 @@
1
+ import { Option } from "commander";
2
+ const TRIAGE_AND_IMPLEMENT = ["triage", "implement"];
3
+ const TRIAGE_ONLY = ["triage"];
4
+ export const DEPRECATED_FLAGS = [
5
+ { flag: "--cache-dir <path>", commands: TRIAGE_ONLY, note: "no step cache exists" },
6
+ { flag: "--cache-ttl <seconds>", commands: TRIAGE_ONLY, note: "no step cache exists" },
7
+ { flag: "--no-cache", commands: TRIAGE_ONLY, note: "no step cache exists" },
8
+ { flag: "--output-dir <path>", commands: TRIAGE_AND_IMPLEMENT, note: "file providers do not read it" },
9
+ { flag: "--service-map-path <path>", commands: TRIAGE_ONLY, note: "service maps are not read" },
10
+ { flag: "--gitlab-base-url <url>", commands: TRIAGE_ONLY, note: "the GitLab provider reads GITLAB_URL" },
11
+ { flag: "--linear-team-id <id>", commands: TRIAGE_AND_IMPLEMENT, note: "the agent gets team ids from the node" },
12
+ { flag: "--linear-bug-label-id <id>", commands: TRIAGE_ONLY, note: "never read" },
13
+ { flag: "--linear-triage-label-id <id>", commands: TRIAGE_ONLY, note: "never read" },
14
+ { flag: "--linear-state-backlog <name>", commands: TRIAGE_ONLY, note: "never read" },
15
+ { flag: "--linear-state-in-progress <name>", commands: TRIAGE_AND_IMPLEMENT, note: "never read" },
16
+ { flag: "--linear-state-peer-review <name>", commands: TRIAGE_AND_IMPLEMENT, note: "never read" },
17
+ ];
18
+ /** `--cache-dir <path>` -> `--cache-dir`. */
19
+ export function deprecatedFlagName(spec) {
20
+ return spec.split(/[ ,]/)[0];
21
+ }
22
+ export function deprecationWarning(flags) {
23
+ const list = flags.join(", ");
24
+ const subject = flags.length === 1 ? `${list} is deprecated` : `${list} are deprecated`;
25
+ return `warning: ${subject}, has no effect and will be removed in a future minor version.\n`;
26
+ }
27
+ /**
28
+ * Accept every deprecated flag that `cmd` used to have. Hidden from help, no
29
+ * effect, and exactly one stderr warning per run naming the flags that were
30
+ * passed.
31
+ */
32
+ export function registerDeprecatedFlags(cmd) {
33
+ const options = DEPRECATED_FLAGS.filter((d) => d.commands.includes(cmd.name())).map((d) => new Option(d.flag).hideHelp());
34
+ for (const option of options)
35
+ cmd.addOption(option);
36
+ cmd.hook("preAction", (_thisCommand, actionCommand) => {
37
+ const used = options
38
+ .filter((o) => actionCommand.getOptionValueSource(o.attributeName()) === "cli")
39
+ .map((o) => o.long);
40
+ if (used.length > 0)
41
+ process.stderr.write(deprecationWarning(used));
42
+ });
43
+ return cmd;
44
+ }
package/dist/journal.d.ts CHANGED
@@ -653,4 +653,57 @@ export declare class RunJournal implements ExecutionJournal {
653
653
  private probe;
654
654
  private wrapTool;
655
655
  }
656
+ /**
657
+ * How the journal treats each `NodeResult` field (#581). `Record<keyof NodeResult, ...>` makes a
658
+ * field added to the type fail the build until it is listed here as journaled or excluded, so a
659
+ * new field cannot silently vanish on resume replay.
660
+ *
661
+ * - `verbatim`: copied as is when present (secrets are redacted by `clean` on append).
662
+ * - `reduced`: journaled in a smaller form, see {@link journalResult}.
663
+ * - `excluded`: never journaled; the reason is part of the schema.
664
+ *
665
+ * Fields stay optional on read: a journal written before a field was journaled just replays
666
+ * without it. Adding a journaled field needs no record version bump.
667
+ */
668
+ export declare const NODE_RESULT_JOURNAL: {
669
+ readonly status: {
670
+ readonly journal: "verbatim";
671
+ };
672
+ readonly data: {
673
+ readonly journal: "verbatim";
674
+ };
675
+ readonly toolCalls: {
676
+ readonly journal: "reduced";
677
+ };
678
+ readonly evals: {
679
+ readonly journal: "verbatim";
680
+ };
681
+ readonly usage: {
682
+ readonly journal: "verbatim";
683
+ };
684
+ readonly skippedWrites: {
685
+ readonly journal: "verbatim";
686
+ };
687
+ readonly harness: {
688
+ readonly journal: "verbatim";
689
+ };
690
+ readonly degraded: {
691
+ readonly journal: "verbatim";
692
+ };
693
+ readonly policy: {
694
+ readonly journal: "verbatim";
695
+ };
696
+ readonly outputs: {
697
+ readonly journal: "verbatim";
698
+ };
699
+ readonly budget: {
700
+ readonly journal: "verbatim";
701
+ };
702
+ readonly contained: {
703
+ readonly journal: "excluded";
704
+ readonly reason: string;
705
+ };
706
+ };
707
+ /** What a node result needs to continue a run. Tool call inputs and outputs are dropped. */
708
+ export declare function journalResult(r: NodeResult): NodeResult;
656
709
  export {};
package/dist/journal.js CHANGED
@@ -2108,9 +2108,39 @@ function namesProduced(o, depth = 0) {
2108
2108
  return o.some((v) => namesProduced(v, depth + 1));
2109
2109
  return Object.entries(o).some(([k, v]) => (PRODUCED_KEYS.has(k) && v !== undefined && v !== null) || namesProduced(v, depth + 1));
2110
2110
  }
2111
+ /**
2112
+ * How the journal treats each `NodeResult` field (#581). `Record<keyof NodeResult, ...>` makes a
2113
+ * field added to the type fail the build until it is listed here as journaled or excluded, so a
2114
+ * new field cannot silently vanish on resume replay.
2115
+ *
2116
+ * - `verbatim`: copied as is when present (secrets are redacted by `clean` on append).
2117
+ * - `reduced`: journaled in a smaller form, see {@link journalResult}.
2118
+ * - `excluded`: never journaled; the reason is part of the schema.
2119
+ *
2120
+ * Fields stay optional on read: a journal written before a field was journaled just replays
2121
+ * without it. Adding a journaled field needs no record version bump.
2122
+ */
2123
+ export const NODE_RESULT_JOURNAL = {
2124
+ status: { journal: "verbatim" },
2125
+ data: { journal: "verbatim" },
2126
+ toolCalls: { journal: "reduced" }, // tool names and statuses; inputs and outputs are large and may hold secrets
2127
+ evals: { journal: "verbatim" },
2128
+ usage: { journal: "verbatim" },
2129
+ skippedWrites: { journal: "verbatim" },
2130
+ harness: { journal: "verbatim" },
2131
+ degraded: { journal: "verbatim" },
2132
+ policy: { journal: "verbatim" }, // booleans and a mode; the run receipt reads it for replayed nodes
2133
+ outputs: { journal: "verbatim" },
2134
+ budget: { journal: "verbatim" }, // a replayed node that crossed a budget must still be the node that stopped the run
2135
+ contained: {
2136
+ journal: "excluded",
2137
+ reason: "containment is journaled per visit as an agent:unsandboxed record; a replayed result must not assert that " +
2138
+ "an earlier attempt was contained, and an absent flag already reads as not contained",
2139
+ },
2140
+ };
2111
2141
  /** What a node result needs to continue a run. Tool call inputs and outputs are dropped. */
2112
- function journalResult(r) {
2113
- return {
2142
+ export function journalResult(r) {
2143
+ const out = {
2114
2144
  status: r.status,
2115
2145
  data: r.data ?? {},
2116
2146
  toolCalls: (r.toolCalls ?? []).map((t) => ({
@@ -2118,11 +2148,13 @@ function journalResult(r) {
2118
2148
  input: null,
2119
2149
  ...(t.status ? { status: t.status } : {}),
2120
2150
  })),
2121
- ...(r.evals ? { evals: r.evals } : {}),
2122
- ...(r.usage ? { usage: r.usage } : {}),
2123
- ...(r.skippedWrites ? { skippedWrites: r.skippedWrites } : {}),
2124
- ...(r.harness ? { harness: r.harness } : {}),
2125
- ...(r.degraded ? { degraded: r.degraded } : {}),
2126
- ...(r.outputs ? { outputs: r.outputs } : {}),
2127
2151
  };
2152
+ const source = r;
2153
+ for (const [field, rule] of Object.entries(NODE_RESULT_JOURNAL)) {
2154
+ if (rule.journal !== "verbatim" || field in out)
2155
+ continue;
2156
+ if (source[field] !== undefined)
2157
+ out[field] = source[field];
2158
+ }
2159
+ return out;
2128
2160
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sweny-ai/core",
3
- "version": "0.1.200",
3
+ "version": "0.1.202",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sweny": "./dist/cli/main.js"