@selesai/code 0.13.30-beta.0 β†’ 0.13.31

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/CHANGELOG.md CHANGED
@@ -2,9 +2,15 @@
2
2
 
3
3
  All notable changes to `@selesai/code` will be documented in this file.
4
4
 
5
- ## [0.13.30-beta.0] - 2026-09-23
5
+ ## [0.13.31] - 2026-09-23
6
+
7
+ ### Changed
8
+ - **Jev capability tie-breaking is now on by default.** Toggle ambiguous-tool tie-breaking in `/settings`. It requires Token-In credentials; without them, Jev is not called and Selesai prompts you to run `/tokenin add`. Deterministic routing remains the fallback.
9
+
10
+ ## [0.13.30] - 2026-09-23
6
11
 
7
12
  ### Added
13
+ - **Four default skills from `addyosmani/agent-skills`.** `planning-and-task-breakdown`, `incremental-implementation`, `code-review-and-quality`, and `code-simplification` now ship as bundled skills and seed into the agent directory like the rest. Their shared reference files (`definition-of-done.md`, `security-checklist.md`, `performance-checklist.md`) ship in `src/skills/references/` with the upstream MIT license, and the links in the skills that cite them were rebased to that location.
8
14
  - **Jev advisory routing (opt-in beta).** The new bundled `jev-advisory-routing` extension can make a bounded, read-only durable-memory lookup after an explicit memory cue, and suggest one discovered skill/workflow or a proportionate verification level. Both routes are disabled by default; neither writes memory, loads a skill, starts a workflow, runs a command, or weakens required checks.
9
15
  - **Jev capability tie-breaking (opt-in beta).** The capability gateway can use Jev only to break an ambiguous lexical hint between two or three optional tools. It never receives the full catalog, tool schemas, or conversation history; unavailable, malformed, low-confidence, and `none` decisions preserve deterministic behavior.
10
16
 
package/README.md CHANGED
@@ -13,13 +13,13 @@
13
13
 
14
14
  </div>
15
15
 
16
- Selesai is a terminal-first **AI coding agent** that takes software tasks from prompt to verified result. It is a maintained, extension-first fork of the [Pi coding agent](https://github.com/earendil-works/pi), with subagents, adaptive workflows, live research, recovery tools, a richer TUI, and **28 built-in skills** shipped together in one install.
16
+ Selesai is a terminal-first **AI coding agent** that takes software tasks from prompt to verified result. It is a maintained, extension-first fork of the [Pi coding agent](https://github.com/earendil-works/pi), with subagents, adaptive workflows, live research, recovery tools, a richer TUI, and **32 built-in skills** shipped together in one install.
17
17
 
18
18
  Use your preferred model provider, connect a local or OpenAI-compatible endpoint, or get a ready-to-use token from **[token.in](https://token.selesai.in)**. Selesai keeps Pi's small, hackable core while reducing the setup and extension work needed before an agent can be productive.
19
19
 
20
20
  | | |
21
21
  | --- | --- |
22
- | **Ready out of the box** | One package bundles coordinated extensions, tools, themes, and 28 skills across 9 meaningful categories. |
22
+ | **Ready out of the box** | One package bundles coordinated extensions, tools, themes, and 32 skills across 9 meaningful categories. |
23
23
  | **Delegates and parallelizes** | Focused subagents can research, review, build, or run independent workstreams with foreground, background, parallel, and chained execution. |
24
24
  | **Adapts to the task** | The workflow chooses the smallest useful pathβ€”from a direct edit to reconnaissance, implementation, review, fixes, and validation. |
25
25
  | **Researches with current sources** | Built-in web research, public GitHub code search, and interactive questions help the agent resolve uncertainty before it acts. |
@@ -113,6 +113,8 @@ Skills ship inside `@selesai/code` and are discovered when Selesai starts. Invok
113
113
 
114
114
  ### πŸ“‹ Planning & orchestration
115
115
 
116
+ - `planning-and-task-breakdown` β€” turn a spec into ordered, implementable tasks with acceptance criteria.
117
+ - `incremental-implementation` β€” land work in thin, verifiable slices with per-increment checks.
116
118
  - `pi-subagents` β€” delegation patterns for parallel, asynchronous, and chained work.
117
119
 
118
120
  ### 🧹 Code simplicity β€” the ponytail family
@@ -127,6 +129,8 @@ Skills ship inside `@selesai/code` and are discovered when Selesai starts. Invok
127
129
  ### πŸ› οΈ Codebase quality
128
130
 
129
131
  - `improve-codebase` β€” inspect and improve architecture, maintainability, and overall codebase quality.
132
+ - `code-review-and-quality` β€” five-axis review, severity labels, and change sizing before merge.
133
+ - `code-simplification` β€” remove accumulated complexity without changing behavior.
130
134
 
131
135
  ### βœ… Completion & output discipline
132
136
 
@@ -146,6 +150,8 @@ Skills ship inside `@selesai/code` and are discovered when Selesai starts. Invok
146
150
 
147
151
  - `agent-browser` β€” browser and Electron automation, scraping, and QA workflows.
148
152
 
153
+ `planning-and-task-breakdown`, `incremental-implementation`, `code-review-and-quality`, and `code-simplification` are adapted from [addyosmani/agent-skills](https://github.com/addyosmani/agent-skills) (MIT). Their shared reference material ships in `src/skills/references/`, with the upstream license alongside it.
154
+
149
155
  ---
150
156
 
151
157
  ## What Selesai adds to Pi
@@ -39,4 +39,15 @@ describe("auto handoff settings", () => {
39
39
  await manager.flush();
40
40
  expect(manager.getAutoHandoffThresholdTokens()).toBe(128_500);
41
41
  });
42
+ it("defaults Jev capability routing on and persists the /settings toggle", async () => {
43
+ const manager = SettingsManager.inMemory();
44
+ expect(manager.getCapabilityGatewayJevEnabled()).toBe(true);
45
+ manager.setCapabilityGatewayJevEnabled(false);
46
+ await manager.flush();
47
+ expect(manager.getCapabilityGatewayJevEnabled()).toBe(false);
48
+ expect(manager.getGlobalSettings().capabilityGateway?.routing?.jev?.enabled).toBe(false);
49
+ manager.setCapabilityGatewayJevEnabled(true);
50
+ await manager.flush();
51
+ expect(manager.getCapabilityGatewayJevEnabled()).toBe(true);
52
+ });
42
53
  });
@@ -64,6 +64,13 @@ export interface AutoHandoffSettings {
64
64
  enabled?: boolean;
65
65
  thresholdTokens?: number;
66
66
  }
67
+ export interface CapabilityGatewaySettings {
68
+ routing?: {
69
+ jev?: {
70
+ enabled?: boolean;
71
+ };
72
+ };
73
+ }
67
74
  export type DefaultProjectTrust = "ask" | "always" | "never";
68
75
  export type TransportSetting = Transport;
69
76
  /**
@@ -130,6 +137,7 @@ export interface Settings {
130
137
  markdown?: MarkdownSettings;
131
138
  warnings?: WarningSettings;
132
139
  autoHandoff?: AutoHandoffSettings;
140
+ capabilityGateway?: CapabilityGatewaySettings;
133
141
  sessionDir?: string;
134
142
  extensionHost?: Record<string, "selesai" | "pi">;
135
143
  httpProxy?: string;
@@ -361,6 +369,8 @@ export declare class SettingsManager {
361
369
  getWarnings(): WarningSettings;
362
370
  setWarnings(warnings: WarningSettings): void;
363
371
  getAutoHandoffEnabled(): boolean;
372
+ getCapabilityGatewayJevEnabled(): boolean;
373
+ setCapabilityGatewayJevEnabled(enabled: boolean): void;
364
374
  setAutoHandoffEnabled(enabled: boolean): void;
365
375
  getAutoHandoffThresholdTokens(): number;
366
376
  setAutoHandoffThresholdTokens(tokens: number): void;
@@ -1087,6 +1087,12 @@ export class SettingsManager {
1087
1087
  getAutoHandoffEnabled() {
1088
1088
  return this.settings.autoHandoff?.enabled ?? DEFAULT_AUTO_HANDOFF_SETTINGS.enabled;
1089
1089
  }
1090
+ getCapabilityGatewayJevEnabled() {
1091
+ return this.settings.capabilityGateway?.routing?.jev?.enabled ?? true;
1092
+ }
1093
+ setCapabilityGatewayJevEnabled(enabled) {
1094
+ this.setGlobalSettings({ capabilityGateway: { routing: { jev: { enabled } } } });
1095
+ }
1090
1096
  setAutoHandoffEnabled(enabled) {
1091
1097
  if (!this.globalSettings.autoHandoff) {
1092
1098
  this.globalSettings.autoHandoff = {};
@@ -11,6 +11,11 @@
11
11
  "recommendations": { "enabled": false }
12
12
  }
13
13
  },
14
+ "capabilityGateway": {
15
+ "routing": {
16
+ "jev": { "enabled": true }
17
+ }
18
+ },
14
19
  "collapseChangelog": true,
15
20
  "compaction": {
16
21
  "enabled": true,
@@ -16,7 +16,7 @@
16
16
  * - A deterministic router activates a uniquely matched tool before the run.
17
17
  * Skills and ambiguous matches remain discoverable through the catalog
18
18
  * without injecting fuzzy hints into the model context.
19
- * - Opt-in Jev-assisted routing (capabilityGateway.routing.jev in settings.json)
19
+ * - Default-on Jev-assisted routing (capabilityGateway.routing.jev in settings.json)
20
20
  * is only a bounded tie-breaker: when the deterministic router returns an
21
21
  * ambiguous lexical hint among optional tools, the gateway offers just those
22
22
  * hinted tools (two or three) and the current prompt to the Jev decisions
@@ -24,8 +24,9 @@
24
24
  * hinted canonical tool name; the gateway revalidates the choice against the
25
25
  * live catalog and activates it for the current run only. No hint, a unique
26
26
  * activation, a skill match, or an already-activated tool never reaches Jev.
27
- * Every Jev failure is an ordinary abstention that leaves the deterministic
28
- * behavior in place, so a missing Token-In subscription is invisible.
27
+ * Every Jev failure is an ordinary abstention that leaves deterministic
28
+ * behavior in place. Without Token-In credentials, no Jev request is sent and
29
+ * the user is prompted to add an account with `/tokenin add`.
29
30
  * - Temporary activations reset at agent_settled, restoring the baseline
30
31
  * active-tool set; a tool_execution_start for one of them records whether the
31
32
  * activation was actually used (content-free tool name + source only).
@@ -146,6 +147,7 @@ export default function capabilityGatewayExtension(pi: ExtensionAPI): void {
146
147
  // Tools this gateway activated for the current run, and whether they were invoked.
147
148
  // Cleared at agent_settled with the activations themselves.
148
149
  const activations = new Map<string, { source: ActivationSource; used: boolean }>();
150
+ let tokenInSetupPrompted = false;
149
151
 
150
152
  /** Activate one tool for the current run, keeping the rest of the loadout untouched. */
151
153
  function activateTool(name: string, source: ActivationSource): void {
@@ -313,7 +315,7 @@ export default function capabilityGatewayExtension(pi: ExtensionAPI): void {
313
315
  });
314
316
 
315
317
  // ------------------------------------------------------------------
316
- // Routing: the deterministic catalog router first; opt-in Jev routing is
318
+ // Routing: the deterministic catalog router first; default-on Jev routing is
317
319
  // only a bounded tie-breaker for its ambiguous/hint result.
318
320
  // ------------------------------------------------------------------
319
321
  pi.on("before_agent_start", async (event, ctx) => {
@@ -344,6 +346,17 @@ export default function capabilityGatewayExtension(pi: ExtensionAPI): void {
344
346
  emitTelemetry(pi, "route", { source: "jev", outcome: "attempt", candidates: candidates.length });
345
347
  const jevRoute = await routeToJevTool(candidates, event.prompt, ctx, config);
346
348
  if (!jevRoute.selected) {
349
+ if (
350
+ !tokenInSetupPrompted &&
351
+ config.provider === "tokenin" &&
352
+ (jevRoute.reason === "no-credential" || jevRoute.reason === "no-template")
353
+ ) {
354
+ tokenInSetupPrompted = true;
355
+ ctx.ui.notify(
356
+ "Jev tool tie-breaking needs a Token-In account. Add one with /tokenin add; deterministic routing will keep working meanwhile.",
357
+ "warning",
358
+ );
359
+ }
347
360
  emitTelemetry(pi, "route", {
348
361
  source: "jev",
349
362
  outcome: JEV_UNAVAILABLE_REASONS.has(jevRoute.reason) ? "unavailable" : "abstained",
@@ -333,7 +333,7 @@ describe("capability gateway integration", () => {
333
333
  });
334
334
 
335
335
  // ---------------------------------------------------------------------------
336
- // Jev-assisted routing (opt-in): capabilityGateway.routing.jev.
336
+ // Default-on Jev-assisted routing: capabilityGateway.routing.jev.
337
337
  // ---------------------------------------------------------------------------
338
338
 
339
339
  describe("capability gateway Jev routing", () => {
@@ -518,14 +518,37 @@ describe("capability gateway Jev routing", () => {
518
518
  );
519
519
  });
520
520
 
521
- it("leaves routing deterministic when the Jev route is not configured", async () => {
521
+ it("tries Jev by default but abstains safely without Token-In", async () => {
522
522
  allowNetwork();
523
- const disabled = stubJev("grep_app_search");
523
+ const unavailable = stubJev("grep_app_search");
524
524
  const h = await createGatewaySession({ enabled: true, extensions: [GATEWAY_DIR, GREP_APP_DIR] });
525
525
  harnesses.push(h);
526
526
 
527
527
  await route(h, HINT_PROMPT);
528
528
 
529
+ expect(unavailable.fetchMock).not.toHaveBeenCalled();
530
+ expect(h.session.getActiveToolNames()).not.toContain("grep_app_search");
531
+ expect(routeEvents(h)).toContainEqual(expect.objectContaining({ source: "jev", outcome: "attempt" }));
532
+ expect(routeEvents(h)).toContainEqual(
533
+ expect.objectContaining({
534
+ source: "jev",
535
+ outcome: "unavailable",
536
+ reason: expect.stringMatching(/^no-(template|credential)$/),
537
+ }),
538
+ );
539
+ });
540
+
541
+ it("does not attempt Jev when explicitly disabled", async () => {
542
+ const disabled = stubJev("grep_app_search");
543
+ const h = await createGatewaySession({
544
+ enabled: true,
545
+ extensions: [GATEWAY_DIR, GREP_APP_DIR],
546
+ jev: { enabled: false },
547
+ });
548
+ harnesses.push(h);
549
+
550
+ await route(h, HINT_PROMPT);
551
+
529
552
  expect(disabled.fetchMock).not.toHaveBeenCalled();
530
553
  expect(h.session.getActiveToolNames()).not.toContain("grep_app_search");
531
554
  expect(routeEvents(h)).toEqual([]);
@@ -115,10 +115,10 @@ describe("gateway Jev configuration", () => {
115
115
  return path;
116
116
  }
117
117
 
118
- it("stays disabled with its own short pre-turn defaults when settings are missing or malformed", () => {
118
+ it("defaults Jev routing on with short pre-turn settings when settings are missing or malformed", () => {
119
119
  expect(readGatewayJevConfig(join(settingsDir, "absent.json"))).toEqual(DEFAULT_GATEWAY_JEV_CONFIG);
120
120
  expect(DEFAULT_GATEWAY_JEV_CONFIG).toMatchObject({
121
- enabled: false,
121
+ enabled: true,
122
122
  provider: "tokenin",
123
123
  model: "jev-1.13",
124
124
  timeoutMs: DEFAULT_GATEWAY_JEV_TIMEOUT_MS,
@@ -133,7 +133,7 @@ describe("gateway Jev configuration", () => {
133
133
  );
134
134
  });
135
135
 
136
- it("reads the opt-in route settings over the gateway defaults", () => {
136
+ it("reads explicit route settings over the default-on gateway config", () => {
137
137
  const path = write({
138
138
  capabilityGateway: {
139
139
  routing: {
@@ -174,7 +174,7 @@ describe("gateway Jev configuration", () => {
174
174
  expect(read).not.toHaveProperty("contextChars");
175
175
  });
176
176
 
177
- it("rejects wrong types and never enables the route implicitly", () => {
177
+ it("rejects wrong types while allowing an omitted enabled flag to inherit true", () => {
178
178
  const path = write({
179
179
  capabilityGateway: {
180
180
  routing: {
@@ -190,7 +190,13 @@ describe("gateway Jev configuration", () => {
190
190
  },
191
191
  },
192
192
  });
193
- expect(readGatewayJevConfig(path)).toEqual(DEFAULT_GATEWAY_JEV_CONFIG);
193
+ expect(readGatewayJevConfig(path)).toEqual({ ...DEFAULT_GATEWAY_JEV_CONFIG, enabled: false });
194
+
195
+ const omittedEnabled = write({ capabilityGateway: { routing: { jev: { timeoutMs: 500 } } } });
196
+ expect(readGatewayJevConfig(omittedEnabled).enabled).toBe(true);
197
+
198
+ const disabled = write({ capabilityGateway: { routing: { jev: { enabled: false } } } });
199
+ expect(readGatewayJevConfig(disabled).enabled).toBe(false);
194
200
  });
195
201
 
196
202
  it("derives the shared connection settings and hard-caps the pre-turn timeout", () => {
@@ -12,9 +12,9 @@
12
12
  * an abstention that leaves the deterministic behavior in place. The transport and validation half
13
13
  * lives in the shared `../jev/decisions.ts` client.
14
14
  *
15
- * Configuration (opt-in, disabled by default). The gateway reads its own settings area β€” it does
16
- * not inherit `jevAdvisory` route policy; only the Jev provider/model identity is shared so every
17
- * Jev consumer defaults to the same deployment:
15
+ * Configuration (enabled by default, but requires Token-In credentials). The gateway reads its
16
+ * own settings area β€” it does not inherit `jevAdvisory` route policy; only the Jev provider/model
17
+ * identity is shared so every Jev consumer defaults to the same deployment:
18
18
  *
19
19
  * "capabilityGateway": {
20
20
  * "routing": { "jev": { "enabled": true, "timeoutMs": 1000, "minConfidence": 0.6 } }
@@ -68,7 +68,7 @@ export interface GatewayJevConfig {
68
68
  }
69
69
 
70
70
  export const DEFAULT_GATEWAY_JEV_CONFIG: GatewayJevConfig = {
71
- enabled: false,
71
+ enabled: true,
72
72
  // The Jev deployment identity, shared with every other Jev consumer.
73
73
  provider: DEFAULT_JEV_ADVISORY_CONFIG.provider,
74
74
  model: DEFAULT_JEV_ADVISORY_CONFIG.model,
@@ -99,13 +99,13 @@ export function readGatewayJevConfig(settingsPath: string = getSettingsPath()):
99
99
  if (isRecord(jev)) raw = jev;
100
100
  }
101
101
  } catch {
102
- // Missing or malformed settings: the feature stays disabled.
102
+ // Missing or malformed settings: use the default-on route preference.
103
103
  }
104
104
  if (!raw) return DEFAULT_GATEWAY_JEV_CONFIG;
105
105
 
106
106
  const baseUrl = raw.baseUrl;
107
107
  return {
108
- enabled: raw.enabled === true,
108
+ enabled: raw.enabled === undefined ? DEFAULT_GATEWAY_JEV_CONFIG.enabled : raw.enabled === true,
109
109
  provider: stringOr(raw.provider, DEFAULT_GATEWAY_JEV_CONFIG.provider),
110
110
  model: stringOr(raw.model, DEFAULT_GATEWAY_JEV_CONFIG.model),
111
111
  baseUrl: typeof baseUrl === "string" && baseUrl.trim() !== "" ? baseUrl : undefined,
@@ -15,6 +15,7 @@ export interface SettingsConfig {
15
15
  autoCompact: boolean;
16
16
  autoHandoffEnabled: boolean;
17
17
  autoHandoffThresholdTokens: number;
18
+ capabilityGatewayJevEnabled: boolean;
18
19
  showImages: boolean;
19
20
  imageWidthCells: number;
20
21
  autoResizeImages: boolean;
@@ -62,6 +63,7 @@ export interface SettingsCallbacks {
62
63
  onAutoCompactChange: (enabled: boolean) => void;
63
64
  onAutoHandoffEnabledChange: (enabled: boolean) => void;
64
65
  onAutoHandoffThresholdTokensChange: (tokens: number) => void;
66
+ onCapabilityGatewayJevChange: (enabled: boolean) => boolean;
65
67
  onShowImagesChange: (enabled: boolean) => void;
66
68
  onImageWidthCellsChange: (width: number) => void;
67
69
  onAutoResizeImagesChange: (enabled: boolean) => void;
@@ -363,6 +363,13 @@ export class SettingsSelectorComponent extends Container {
363
363
  currentValue: String(config.autoHandoffThresholdTokens),
364
364
  values: ["64000", "96000", "128000", "160000", "192000", "256000", "512000"],
365
365
  },
366
+ {
367
+ id: "capability-gateway-jev",
368
+ label: "Jev tool tie-breaking",
369
+ description: "Use Token-In Jev only for ambiguous optional-tool matches. Requires Token-In credentials; add one with /tokenin add.",
370
+ currentValue: config.capabilityGatewayJevEnabled ? "true" : "false",
371
+ values: ["true", "false"],
372
+ },
366
373
  {
367
374
  id: "steering-mode",
368
375
  label: "Steering mode",
@@ -731,6 +738,11 @@ export class SettingsSelectorComponent extends Container {
731
738
  case "auto-handoff-threshold":
732
739
  callbacks.onAutoHandoffThresholdTokensChange(parseInt(newValue, 10));
733
740
  break;
741
+ case "capability-gateway-jev":
742
+ if (!callbacks.onCapabilityGatewayJevChange(newValue === "true")) {
743
+ this.settingsList.updateValue(id, config.capabilityGatewayJevEnabled ? "true" : "false");
744
+ }
745
+ break;
734
746
  case "show-images":
735
747
  callbacks.onShowImagesChange(newValue === "true");
736
748
  break;
@@ -3785,6 +3785,7 @@ export class InteractiveMode {
3785
3785
  autoCompact: this.session.autoCompactionEnabled,
3786
3786
  autoHandoffEnabled: this.settingsManager.getAutoHandoffEnabled(),
3787
3787
  autoHandoffThresholdTokens: this.settingsManager.getAutoHandoffThresholdTokens(),
3788
+ capabilityGatewayJevEnabled: this.settingsManager.getCapabilityGatewayJevEnabled(),
3788
3789
  defaultModel: (() => {
3789
3790
  const defaultProvider = this.settingsManager.getDefaultProvider();
3790
3791
  const defaultModelId = this.settingsManager.getDefaultModel();
@@ -3850,6 +3851,23 @@ export class InteractiveMode {
3850
3851
  onAutoHandoffThresholdTokensChange: (tokens) => {
3851
3852
  this.settingsManager.setAutoHandoffThresholdTokens(tokens);
3852
3853
  },
3854
+ onCapabilityGatewayJevChange: (enabled) => {
3855
+ if (enabled && !this.session.modelRuntime.getProviderAuthStatus("tokenin").configured) {
3856
+ this.showStatus("Token-In is required for Jev routing; starting /tokenin add");
3857
+ done();
3858
+ void this.session
3859
+ .prompt("/tokenin add")
3860
+ .then(() => {
3861
+ if (this.session.modelRuntime.getProviderAuthStatus("tokenin").configured) {
3862
+ this.settingsManager.setCapabilityGatewayJevEnabled(true);
3863
+ }
3864
+ })
3865
+ .catch((error) => this.showError(`Could not start Token-In setup: ${String(error)}`));
3866
+ return false;
3867
+ }
3868
+ this.settingsManager.setCapabilityGatewayJevEnabled(enabled);
3869
+ return true;
3870
+ },
3853
3871
  onShowImagesChange: (enabled) => {
3854
3872
  this.settingsManager.setShowImages(enabled);
3855
3873
  for (const child of this.chatContainer.children) {