@aliou/pi-processes 0.10.4 → 0.10.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.
@@ -1,7 +1,6 @@
1
1
  export { DEFAULT_CONFIG } from "./defaults";
2
2
  export {
3
3
  configLoader,
4
- createSettingsConfigStore,
5
4
  drainImportMessages,
6
5
  loadProcessConfig,
7
6
  } from "./loader";
@@ -1,8 +1,4 @@
1
- import {
2
- ConfigLoader,
3
- type ConfigStore,
4
- type Scope,
5
- } from "@aliou/pi-utils-settings";
1
+ import { ConfigLoader } from "@aliou/pi-utils-settings";
6
2
  import { DEFAULT_CONFIG } from "./defaults";
7
3
  import { importLegacyProcessConfig, migrations } from "./migrations";
8
4
  import { PROCESS_CONFIG_SCHEMA_URL } from "./schema";
@@ -41,22 +37,3 @@ export const configLoader = new ConfigLoader<
41
37
  migrations,
42
38
  schemaUrl: PROCESS_CONFIG_SCHEMA_URL,
43
39
  });
44
-
45
- export function createSettingsConfigStore(): ConfigStore<
46
- ProcessConfig,
47
- ProcessProtocolConfig
48
- > {
49
- return {
50
- save: (scope, config) => configLoader.save(scope, config),
51
- getConfig: () => configLoader.getConfig(),
52
- getRawConfig: (scope) => configLoader.getRawConfig(scope),
53
- hasScope: (scope) => configLoader.hasScope(scope),
54
- hasConfig: (scope) => configLoader.hasConfig(scope),
55
- getEnabledScopes: () => {
56
- const enabled = new Set(configLoader.getEnabledScopes());
57
- return (["global", "local", "memory"] as Scope[]).filter((scope) =>
58
- enabled.has(scope),
59
- );
60
- },
61
- };
62
- }
@@ -95,9 +95,31 @@ function migrateDockDefaultState(
95
95
  return undefined;
96
96
  }
97
97
 
98
+ /** Config version this migration brings the config to. */
99
+ export const CONFIG_VERSION_V0100 = "0.10.0";
100
+
101
+ function compareSemver(a: string, b: string): number {
102
+ const left = a.split(".");
103
+ const right = b.split(".");
104
+
105
+ for (let i = 0; i < 3; i++) {
106
+ const diff = (Number(left[i]) || 0) - (Number(right[i]) || 0);
107
+ if (diff !== 0) return diff;
108
+ }
109
+
110
+ return 0;
111
+ }
112
+
98
113
  export function needsConfigV094ToV0100Migration(
99
114
  config: ProcessConfig,
115
+ fromVersion: number | string = "0.0.0",
100
116
  ): boolean {
117
+ // Gate on content and version: the v0.9.4 projection drops keys added
118
+ // after v0.10.0, so it must never touch an already-stamped config.
119
+ if (compareSemver(String(fromVersion), CONFIG_VERSION_V0100) >= 0) {
120
+ return false;
121
+ }
122
+
101
123
  const root = config as Record<string, unknown>;
102
124
  const widget = isRecord(root.widget) ? root.widget : undefined;
103
125
 
@@ -177,7 +199,9 @@ function setNonEmpty<K extends keyof ConfigV0100>(
177
199
 
178
200
  export const configV094ToV0100Migration: Migration<ProcessConfig> = {
179
201
  name: "001-v0-9-4-to-v0-10-0-config",
180
- shouldRun: (config) => needsConfigV094ToV0100Migration(config),
202
+ version: CONFIG_VERSION_V0100,
203
+ shouldRun: (config, ctx) =>
204
+ needsConfigV094ToV0100Migration(config, ctx.fromVersion),
181
205
  run: (config) => migrateConfigV094ToV0100(config as ConfigV094),
182
206
  message:
183
207
  "Migrated pi-processes settings to the current schema. Mapped the dock hidden state to closed.",
@@ -0,0 +1,24 @@
1
+ import type { Migration } from "@aliou/pi-utils-settings";
2
+
3
+ import type { ProcessConfig } from "../types";
4
+
5
+ /**
6
+ * Current config version stamped on every settings file.
7
+ *
8
+ * Keep this in sync with the `--version` flag of the `gen:schema` and
9
+ * `check:schema` scripts in package.json.
10
+ */
11
+ export const PROCESS_CONFIG_VERSION = "0.10.6";
12
+
13
+ /**
14
+ * Terminal migration: converge every config on the current version.
15
+ *
16
+ * The config is left untouched; the loader stamps `version` after the run.
17
+ * Configs stamped by earlier migrations (or already current) are skipped by
18
+ * the default version comparison.
19
+ */
20
+ export const configVersionStampMigration: Migration<ProcessConfig> = {
21
+ name: "002-stamp-config-version",
22
+ version: PROCESS_CONFIG_VERSION,
23
+ run: (config) => config,
24
+ };
@@ -2,7 +2,7 @@ import type { Migration } from "@aliou/pi-utils-settings";
2
2
 
3
3
  import type { ProcessConfig } from "../types";
4
4
  import { configV094ToV0100Migration } from "./001-v0-9-4-to-v0-10-0-config";
5
- import { configVersionStampMigration } from "./002-stamp-v0-10-0-config-version";
5
+ import { configVersionStampMigration } from "./002-stamp-config-version";
6
6
 
7
7
  export { importLegacyProcessConfig } from "./000-import-legacy-process-config";
8
8
  export {
@@ -14,10 +14,8 @@ export {
14
14
  } from "./001-v0-9-4-to-v0-10-0-config";
15
15
  export {
16
16
  configVersionStampMigration,
17
- needsConfigVersionStamp,
18
17
  PROCESS_CONFIG_VERSION,
19
- stampConfigVersion,
20
- } from "./002-stamp-v0-10-0-config-version";
18
+ } from "./002-stamp-config-version";
21
19
 
22
20
  export const migrations: Migration<ProcessConfig>[] = [
23
21
  configV094ToV0100Migration,
@@ -49,12 +49,13 @@ export interface WidgetConfig {
49
49
  dockHeight?: number;
50
50
  }
51
51
 
52
- /** User-facing pi-processes settings stored on disk. */
52
+ /**
53
+ * User-facing pi-processes settings stored on disk.
54
+ *
55
+ * The reserved `$schema` and `version` keys are owned by the config loader
56
+ * and injected into schema.json by `pi-settings-schema`.
57
+ */
53
58
  export interface ProcessConfig {
54
- /** JSON Schema URL used by editors for validation and autocomplete. */
55
- $schema?: string;
56
- /** Config migration marker written after v0.10.0 settings migration. */
57
- version?: string;
58
59
  /** Process execution settings. */
59
60
  execution?: ExecutionConfig;
60
61
  /** Shell-command interception settings. */
@@ -2,11 +2,17 @@ import type {
2
2
  ExtensionAPI,
3
3
  MessageRenderOptions,
4
4
  Theme,
5
+ ThemeColor,
5
6
  } from "@earendil-works/pi-coding-agent";
6
7
  import { type Component, Container, Text } from "@earendil-works/pi-tui";
7
8
  import { truncateForDisplay } from "../shared/display-text";
8
9
  import { MESSAGE_TYPE_PROCESS_NOTIFICATION } from "./constants";
9
- import type { ProcessNotificationDetails } from "./notifications/types";
10
+ import type {
11
+ Attention,
12
+ ProcessNotificationDetails,
13
+ ProcessNotificationKind,
14
+ } from "./notifications/types";
15
+ import { formatPatternForDisplay, quoteFilter } from "./tools/components";
10
16
 
11
17
  export function registerProcessNotificationRenderer(pi: ExtensionAPI): void {
12
18
  pi.registerMessageRenderer<ProcessNotificationDetails>(
@@ -25,11 +31,17 @@ export function renderProcessNotificationMessage(
25
31
  return undefined;
26
32
  }
27
33
 
34
+ // outputPad is only populated on Pi 0.82.1+ (see MessageRenderOptions);
35
+ // fall back to 0 so this renderer doesn't break on older Pi builds.
36
+ const outputPad = options.outputPad ?? 0;
37
+
28
38
  const container = new Container();
29
- container.addChild(new Text(formatSummary(details, theme), 0, 0));
39
+ container.addChild(new Text(formatSummary(details, theme), outputPad, 0));
30
40
 
31
41
  if (options.expanded) {
32
- container.addChild(new Text(formatDetailLine(details, theme), 0, 1));
42
+ container.addChild(
43
+ new Text(formatDetailLine(details, theme), outputPad, 0),
44
+ );
33
45
  }
34
46
 
35
47
  return container;
@@ -66,17 +78,100 @@ function formatDetailLine(
66
78
  details: ProcessNotificationDetails,
67
79
  theme: Theme,
68
80
  ): string {
69
- const parts = [
70
- `id: ${details.processId}`,
71
- `attention: ${details.attention}`,
72
- details.status ? `status: ${details.status}` : null,
73
- details.exitCode === undefined || details.exitCode === null
74
- ? null
75
- : `exit: ${details.exitCode}`,
76
- details.endReason ? `reason: ${details.endReason}` : null,
77
- ].filter(Boolean);
78
-
79
- return theme.fg("muted", parts.join(" "));
81
+ const parts: string[] = [
82
+ field("id", details.processId, theme),
83
+ field("notify", formatAttention(details.attention, theme), theme),
84
+ ];
85
+
86
+ if (details.logMatch) {
87
+ const pattern = quoteFilter(
88
+ formatPatternForDisplay(details.logMatch.pattern),
89
+ details.logMatch.mode,
90
+ );
91
+ parts.push(
92
+ field("pattern", theme.fg("accent", pattern), theme),
93
+ field("stream", theme.fg("muted", `[${details.logMatch.stream}]`), theme),
94
+ );
95
+ } else {
96
+ if (details.status) {
97
+ parts.push(
98
+ field(
99
+ "status",
100
+ theme.fg(statusTone(details.kind), details.status),
101
+ theme,
102
+ ),
103
+ );
104
+ }
105
+
106
+ if (details.exitCode !== undefined && details.exitCode !== null) {
107
+ parts.push(
108
+ field(
109
+ "exit",
110
+ theme.fg(statusTone(details.kind), String(details.exitCode)),
111
+ theme,
112
+ ),
113
+ );
114
+ }
115
+
116
+ if (details.endReason) {
117
+ parts.push(field("reason", theme.fg("muted", details.endReason), theme));
118
+ }
119
+
120
+ if (details.signal) {
121
+ const number =
122
+ details.signal.number === null
123
+ ? ""
124
+ : ` (${details.signal.number}, ${details.signal.description})`;
125
+ parts.push(
126
+ field(
127
+ "signal",
128
+ theme.fg("muted", `${details.signal.name}${number}`),
129
+ theme,
130
+ ),
131
+ );
132
+ }
133
+ }
134
+
135
+ return parts.join(" ");
136
+ }
137
+
138
+ /** `label:` in muted, matching `buildField` in tools/utils.ts. */
139
+ function field(label: string, value: string, theme: Theme): string {
140
+ return `${theme.fg("muted", `${label}:`)} ${value}`;
141
+ }
142
+
143
+ /**
144
+ * Plain-language attention level, reusing the tone mapping from
145
+ * `attentionTone` in tools/components/watch.ts (turn/context keep their
146
+ * color; ignore switches from muted to dim to read as "quieter").
147
+ */
148
+ function formatAttention(attention: Attention, theme: Theme): string {
149
+ switch (attention) {
150
+ case "turn":
151
+ return theme.bold(theme.fg("warning", "now"));
152
+ case "context":
153
+ return theme.bold(theme.fg("success", "next turn"));
154
+ default:
155
+ return theme.bold(theme.fg("dim", "silent"));
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Same tone family as `statusColor` in shared/ui.ts: success for a clean
161
+ * exit, error for failure/crash, dim for killed.
162
+ */
163
+ function statusTone(kind: ProcessNotificationKind): ThemeColor {
164
+ switch (kind) {
165
+ case "success":
166
+ return "success";
167
+ case "failure":
168
+ case "crash":
169
+ return "error";
170
+ case "killed":
171
+ return "dim";
172
+ default:
173
+ return "muted";
174
+ }
80
175
  }
81
176
 
82
177
  function summaryVerb(details: ProcessNotificationDetails): string {
@@ -6,18 +6,21 @@
6
6
  */
7
7
 
8
8
  import {
9
+ createConfigStore,
9
10
  registerSettingsCommand,
10
11
  type SettingsSection,
11
12
  } from "@aliou/pi-utils-settings";
12
13
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
13
14
 
14
15
  import type { ProcessConfig, ProcessProtocolConfig } from "../config";
15
- import { createSettingsConfigStore } from "../config";
16
+ import { configLoader } from "../config";
16
17
  import { applySettingChange } from "./apply-setting-change";
17
18
  import { buildSections } from "./build-sections";
18
19
 
19
20
  export function registerProcessSettings(pi: ExtensionAPI): void {
20
- const configStore = createSettingsConfigStore();
21
+ const configStore = createConfigStore(configLoader, {
22
+ scopes: ["global", "local", "memory"],
23
+ });
21
24
 
22
25
  registerSettingsCommand<ProcessConfig, ProcessProtocolConfig>(pi, {
23
26
  commandName: "ps:settings",
@@ -1,4 +1,8 @@
1
1
  export { ProcessActionHeader } from "./process-action-header";
2
2
  export { ProcessActionTitle } from "./process-action-title";
3
3
  export { ToolLayout } from "./tool-layout";
4
- export { buildMatcherLine, formatPatternForDisplay } from "./watch";
4
+ export {
5
+ buildMatcherLine,
6
+ formatPatternForDisplay,
7
+ quoteFilter,
8
+ } from "./watch";
@@ -15,6 +15,8 @@ export function buildMatcherLine(
15
15
  const attentionTone =
16
16
  on === "turn" ? "warning" : on === "context" ? "success" : "muted";
17
17
 
18
+ const pattern = quoteFilter(formatPatternForDisplay(matcher.pattern), mode);
19
+
18
20
  return new Text(
19
21
  [
20
22
  prefix,
@@ -22,13 +24,22 @@ export function buildMatcherLine(
22
24
  " ",
23
25
  theme.bold(theme.fg(attentionTone, `${on}${repeat}`)),
24
26
  " ",
25
- theme.fg("accent", formatPatternForDisplay(matcher.pattern)),
27
+ theme.fg("accent", pattern),
26
28
  ].join(""),
27
29
  0,
28
30
  0,
29
31
  );
30
32
  }
31
33
 
34
+ export function quoteFilter(
35
+ pattern: string,
36
+ mode: "literal" | "regex",
37
+ ): string {
38
+ if (mode === "regex") return `/${pattern}/`;
39
+ if (pattern.includes('"')) return `'${pattern}'`;
40
+ return `"${pattern}"`;
41
+ }
42
+
32
43
  export function formatPatternForDisplay(pattern: string): string {
33
44
  let formatted = "";
34
45
 
@@ -3,7 +3,8 @@ import {
3
3
  defineTool,
4
4
  type ExtensionAPI,
5
5
  type ExtensionContext,
6
- type Theme,
6
+ Theme,
7
+ type ToolDefinition,
7
8
  } from "@earendil-works/pi-coding-agent";
8
9
  import { type Component, Container, Text } from "@earendil-works/pi-tui";
9
10
 
@@ -105,11 +106,32 @@ async function execute(
105
106
  }
106
107
  }
107
108
 
109
+ /** pi's declared renderCall signature, per its public ToolDefinition type. */
110
+ type RenderCallFn = NonNullable<ToolDefinition["renderCall"]>;
111
+ /** pi's third renderCall argument (ToolRenderContext — not root-exported). */
112
+ type RenderCallFnContext = Parameters<RenderCallFn>[2];
113
+
114
+ /**
115
+ * pi invokes renderCall as (args, theme, context) where theme is pi's Theme
116
+ * class instance. Detecting that exact class distinguishes pi's argument
117
+ * order from OMP's (args, options, theme), where the second argument is a
118
+ * plain options object.
119
+ */
120
+ function isPiTheme(value: unknown): value is Theme {
121
+ return value instanceof Theme;
122
+ }
123
+
108
124
  function renderProcessCall(
109
125
  args: ProcessesParamsType,
110
- theme: Theme,
111
- context?: { expanded?: boolean },
126
+ second: Theme | RenderCallFnContext,
127
+ third?: RenderCallFnContext | Theme,
112
128
  ): Component {
129
+ const usesPiOrder = isPiTheme(second);
130
+ const theme = usesPiOrder ? second : (third as Theme);
131
+ const context = (usesPiOrder ? third : second) as
132
+ | RenderCallFnContext
133
+ | undefined;
134
+
113
135
  switch (args.action) {
114
136
  case "start":
115
137
  return new ToolLayout().setHeader(
@@ -2,7 +2,8 @@ import type { Theme } from "@earendil-works/pi-coding-agent";
2
2
  import { Container, Spacer, Text } from "@earendil-works/pi-tui";
3
3
 
4
4
  import { sanitizeForDisplay } from "../../../shared/display-text";
5
- import { ProcessActionHeader } from "../components";
5
+ import { truncateToWidth } from "../../../shared/truncate";
6
+ import { ProcessActionHeader, quoteFilter } from "../components";
6
7
  import type { ProcessesParamsType } from "../schema";
7
8
  import { buildField } from "../utils";
8
9
  import type { OutputDetails } from ".";
@@ -73,9 +74,23 @@ export function buildCollapsed(
73
74
  ),
74
75
  );
75
76
 
77
+ if (details.pattern) {
78
+ const quoted = quoteFilter(details.pattern, details.mode);
79
+ const value = truncateToWidth(sanitizeForDisplay(quoted), 80);
80
+ container.addChild(
81
+ new Text(
82
+ `${theme.fg("muted", "filter:")} ${theme.fg("accent", value)}`,
83
+ 0,
84
+ 0,
85
+ ),
86
+ );
87
+ }
88
+
76
89
  const bodyLines = extractOutputBody(contentText, details);
77
90
  const preview = bodyLines.slice(-2).map(sanitizeForDisplay).join("\n");
78
91
 
92
+ container.addChild(new Spacer(1));
93
+
79
94
  if (preview) {
80
95
  container.addChild(new Text(theme.fg("muted", preview), 0, 0));
81
96
  } else {
@@ -119,9 +134,8 @@ function buildOutputMeta(details: OutputDetails, theme: Theme): Container {
119
134
  container.addChild(buildField("stream", details.stream, theme));
120
135
 
121
136
  if (details.pattern) {
122
- const modeTag = details.mode === "regex" ? " (regex)" : "";
123
137
  container.addChild(
124
- buildField("filter", `${details.pattern}${modeTag}`, theme),
138
+ buildField("filter", quoteFilter(details.pattern, details.mode), theme),
125
139
  );
126
140
  }
127
141
 
@@ -3,9 +3,9 @@ import type { Theme } from "@earendil-works/pi-coding-agent";
3
3
  import { type Component, visibleWidth } from "@earendil-works/pi-tui";
4
4
  import type { ProcessInfo } from "../../../src/types";
5
5
  import { LIVE_STATUSES } from "../../../src/types";
6
- import { renderProcessTab } from "../../process-tabs";
7
6
  import { sanitizeForDisplay } from "../../shared/display-text";
8
7
  import { displayTextOf, renderLogLine } from "../../shared/log-line";
8
+ import { renderProcessTab } from "../../shared/process-tabs";
9
9
  import { truncateToWidth } from "../../shared/truncate";
10
10
  import {
11
11
  clampNameColumn,
@@ -17,8 +17,8 @@ import {
17
17
  import { LIVE_STATUSES, type ProcessInfo } from "../../../src/types";
18
18
  import { formatRuntime } from "../../../src/utils/format";
19
19
  import { isRecord } from "../../../src/utils/is-record";
20
- import { renderProcessTab } from "../../process-tabs";
21
20
  import { truncateForDisplay } from "../../shared/display-text";
21
+ import { renderProcessTab } from "../../shared/process-tabs";
22
22
  import { truncateToWidth } from "../../shared/truncate";
23
23
  import { LineComponent, LinesComponent, RuleComponent } from "../../shared/ui";
24
24
  import { requestProcessList } from "../client";
@@ -1,8 +1,8 @@
1
1
  import type { Theme } from "@earendil-works/pi-coding-agent";
2
2
 
3
- import type { ProcessInfo } from "../src/types";
4
- import { truncateForDisplay } from "./shared/display-text";
5
- import { MAX_TAB_NAME, statusDot } from "./shared/ui";
3
+ import type { ProcessInfo } from "../../src/types";
4
+ import { truncateForDisplay } from "./display-text";
5
+ import { MAX_TAB_NAME, statusDot } from "./ui";
6
6
 
7
7
  export { MAX_TAB_NAME, statusDot as renderProcessTabDot };
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aliou/pi-processes",
3
- "version": "0.10.4",
3
+ "version": "0.10.6",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "private": false,
@@ -23,7 +23,8 @@
23
23
  "skills": [
24
24
  "./skills/pi-processes"
25
25
  ],
26
- "video": "https://assets.aliou.me/pi-extensions/demos/pi-processes.mp4"
26
+ "image": "https://assets.aliou.me/github/aliou/pi-processes/banner-v0.10.x.png",
27
+ "video": "https://assets.aliou.me/pi-extensions/demos/processes/v0.10.0/agent-starts-processes.mp4"
27
28
  },
28
29
  "publishConfig": {
29
30
  "access": "public"
@@ -42,7 +43,7 @@
42
43
  "CONTRIBUTING.md"
43
44
  ],
44
45
  "dependencies": {
45
- "@aliou/pi-utils-settings": "^0.18.0",
46
+ "@aliou/pi-utils-settings": "^0.19.1",
46
47
  "@aliou/pi-utils-ui": "^0.5.0",
47
48
  "@aliou/sh": "^0.1.0"
48
49
  },
@@ -56,9 +57,9 @@
56
57
  "@aliou/biome-plugins": "^0.8.1",
57
58
  "@biomejs/biome": "^2.4.15",
58
59
  "@changesets/cli": "^2.27.11",
59
- "@earendil-works/pi-ai": "0.80.3",
60
- "@earendil-works/pi-coding-agent": "0.80.3",
61
- "@earendil-works/pi-tui": "0.80.3",
60
+ "@earendil-works/pi-ai": "0.84.1",
61
+ "@earendil-works/pi-coding-agent": "0.84.1",
62
+ "@earendil-works/pi-tui": "0.84.1",
62
63
  "@golevelup/ts-vitest": "^4.0.0",
63
64
  "@types/node": "^25.0.10",
64
65
  "husky": "^9.1.7",
@@ -66,20 +67,24 @@
66
67
  "ts-json-schema-generator": "^2.9.0",
67
68
  "typebox": "1.1.38",
68
69
  "typescript": "^5.9.3",
69
- "vitest": "^4.1.5"
70
+ "vitest": "^4.1.5",
71
+ "vitest-evals": "0.15.0"
70
72
  },
71
73
  "scripts": {
72
74
  "typecheck": "tsc --noEmit",
75
+ "typecheck:evals": "tsc --noEmit -p tests/evals/tsconfig.json",
73
76
  "lint": "biome check",
74
77
  "format": "biome check --write",
75
- "gen:schema": "ts-json-schema-generator --path extensions/processes/config/types.ts --type ProcessConfig --no-type-check -o schema.json",
76
- "check:schema": "ts-json-schema-generator --path extensions/processes/config/types.ts --type ProcessConfig --no-type-check -o /tmp/pi-processes-schema-check.json && diff -q schema.json /tmp/pi-processes-schema-check.json",
78
+ "gen:schema": "pi-settings-schema -p extensions/processes/config/types.ts -t ProcessConfig -o schema.json --version 0.10.6",
79
+ "check:schema": "pi-settings-schema -p extensions/processes/config/types.ts -t ProcessConfig -o schema.json --version 0.10.6 --check",
80
+ "check:changesets": "node scripts/check-changesets.ts",
77
81
  "check:lockfile": "pnpm install --frozen-lockfile --ignore-scripts",
78
82
  "prepare": "[ -d .git ] && husky || true",
79
83
  "changeset": "changeset",
80
84
  "version": "changeset version",
81
85
  "test": "vitest run",
82
86
  "test:e2e": "vitest run --config vitest.e2e.config.ts",
87
+ "test:evals": "vitest run --config tests/evals/vitest.config.ts",
83
88
  "release": "pnpm changeset publish"
84
89
  },
85
90
  "packageManager": "pnpm@11.5.1",
package/schema.json CHANGED
@@ -1,134 +1,142 @@
1
1
  {
2
- "$ref": "#/definitions/ProcessConfig",
3
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$ref": "#/definitions/ProcessConfig",
4
4
  "definitions": {
5
- "ExecutionConfig": {
6
- "additionalProperties": false,
5
+ "ProcessConfig": {
6
+ "type": "object",
7
7
  "properties": {
8
- "shellPath": {
9
- "description": "Absolute shell executable used to run process commands.",
8
+ "execution": {
9
+ "$ref": "#/definitions/ExecutionConfig",
10
+ "description": "Process execution settings."
11
+ },
12
+ "interception": {
13
+ "$ref": "#/definitions/InterceptionConfig",
14
+ "description": "Shell-command interception settings."
15
+ },
16
+ "processList": {
17
+ "$ref": "#/definitions/ProcessListConfig",
18
+ "description": "Process overview and log viewport settings."
19
+ },
20
+ "output": {
21
+ "$ref": "#/definitions/OutputConfig",
22
+ "description": "Process output retention settings."
23
+ },
24
+ "follow": {
25
+ "$ref": "#/definitions/FollowConfig",
26
+ "description": "Live log follow behavior."
27
+ },
28
+ "widget": {
29
+ "$ref": "#/definitions/WidgetConfig",
30
+ "description": "Dock and status widget settings."
31
+ },
32
+ "$schema": {
10
33
  "type": "string"
34
+ },
35
+ "version": {
36
+ "anyOf": [
37
+ {
38
+ "type": "integer",
39
+ "minimum": 0
40
+ },
41
+ {
42
+ "type": "string",
43
+ "pattern": "^\\d{1,15}(\\.\\d{1,15})?(\\.\\d{1,15})?$"
44
+ }
45
+ ],
46
+ "description": "Config schema version, stamped by migrations. Current version: 0.10.6."
11
47
  }
12
48
  },
13
- "type": "object"
14
- },
15
- "FollowConfig": {
16
49
  "additionalProperties": false,
50
+ "description": "User-facing pi-processes settings stored on disk.\n\nThe reserved `$schema` and `version` keys are owned by the config loader and injected into schema.json by `pi-settings-schema`."
51
+ },
52
+ "ExecutionConfig": {
53
+ "type": "object",
17
54
  "properties": {
18
- "autoHideOnFinish": {
19
- "description": "Hide process log interfaces when all managed processes finish.",
20
- "type": "boolean"
21
- },
22
- "enabledByDefault": {
23
- "description": "Open process log interfaces in follow mode by default.",
24
- "type": "boolean"
55
+ "shellPath": {
56
+ "type": "string",
57
+ "description": "Absolute shell executable used to run process commands."
25
58
  }
26
59
  },
27
- "type": "object"
60
+ "additionalProperties": false
28
61
  },
29
62
  "InterceptionConfig": {
30
- "additionalProperties": false,
63
+ "type": "object",
31
64
  "properties": {
32
65
  "blockBackgroundCommands": {
33
- "description": "Block shell background patterns and redirect the agent to the process tool.",
34
- "type": "boolean"
66
+ "type": "boolean",
67
+ "description": "Block shell background patterns and redirect the agent to the process tool."
35
68
  }
36
69
  },
37
- "type": "object"
70
+ "additionalProperties": false
38
71
  },
39
- "OutputConfig": {
40
- "additionalProperties": false,
72
+ "ProcessListConfig": {
73
+ "type": "object",
41
74
  "properties": {
42
- "defaultTailLines": {
43
- "description": "Default number of recent lines returned by the process output action.",
44
- "type": "number"
45
- },
46
- "maxOutputBytes": {
47
- "description": "Maximum bytes retained by each process log interface.",
48
- "type": "number"
75
+ "maxPreviewLines": {
76
+ "type": "number",
77
+ "description": "Maximum log rows displayed in the overview preview and logs overlay."
49
78
  },
50
- "maxOutputLines": {
51
- "description": "Maximum lines retained by process log interfaces.",
52
- "type": "number"
79
+ "maxVisibleProcesses": {
80
+ "type": "number",
81
+ "description": "Maximum process rows displayed in the overview before scrolling."
53
82
  }
54
83
  },
55
- "type": "object"
84
+ "additionalProperties": false
56
85
  },
57
- "ProcessConfig": {
58
- "additionalProperties": false,
59
- "description": "User-facing pi-processes settings stored on disk.",
86
+ "OutputConfig": {
87
+ "type": "object",
60
88
  "properties": {
61
- "$schema": {
62
- "description": "JSON Schema URL used by editors for validation and autocomplete.",
63
- "type": "string"
64
- },
65
- "execution": {
66
- "$ref": "#/definitions/ExecutionConfig",
67
- "description": "Process execution settings."
68
- },
69
- "follow": {
70
- "$ref": "#/definitions/FollowConfig",
71
- "description": "Live log follow behavior."
72
- },
73
- "interception": {
74
- "$ref": "#/definitions/InterceptionConfig",
75
- "description": "Shell-command interception settings."
76
- },
77
- "output": {
78
- "$ref": "#/definitions/OutputConfig",
79
- "description": "Process output retention settings."
80
- },
81
- "processList": {
82
- "$ref": "#/definitions/ProcessListConfig",
83
- "description": "Process overview and log viewport settings."
89
+ "defaultTailLines": {
90
+ "type": "number",
91
+ "description": "Default number of recent lines returned by the process output action."
84
92
  },
85
- "version": {
86
- "description": "Config migration marker written after v0.10.0 settings migration.",
87
- "type": "string"
93
+ "maxOutputLines": {
94
+ "type": "number",
95
+ "description": "Maximum lines retained by process log interfaces."
88
96
  },
89
- "widget": {
90
- "$ref": "#/definitions/WidgetConfig",
91
- "description": "Dock and status widget settings."
97
+ "maxOutputBytes": {
98
+ "type": "number",
99
+ "description": "Maximum bytes retained by each process log interface."
92
100
  }
93
101
  },
94
- "type": "object"
102
+ "additionalProperties": false
95
103
  },
96
- "ProcessListConfig": {
97
- "additionalProperties": false,
104
+ "FollowConfig": {
105
+ "type": "object",
98
106
  "properties": {
99
- "maxPreviewLines": {
100
- "description": "Maximum log rows displayed in the overview preview and logs overlay.",
101
- "type": "number"
107
+ "enabledByDefault": {
108
+ "type": "boolean",
109
+ "description": "Open process log interfaces in follow mode by default."
102
110
  },
103
- "maxVisibleProcesses": {
104
- "description": "Maximum process rows displayed in the overview before scrolling.",
105
- "type": "number"
111
+ "autoHideOnFinish": {
112
+ "type": "boolean",
113
+ "description": "Hide process log interfaces when all managed processes finish."
106
114
  }
107
115
  },
108
- "type": "object"
116
+ "additionalProperties": false
109
117
  },
110
118
  "WidgetConfig": {
111
- "additionalProperties": false,
119
+ "type": "object",
112
120
  "properties": {
121
+ "showStatusWidget": {
122
+ "type": "boolean",
123
+ "description": "Show a one-line process summary below the editor."
124
+ },
113
125
  "dockDefaultState": {
114
- "description": "Initial visibility of the process dock.",
126
+ "type": "string",
115
127
  "enum": [
116
128
  "closed",
117
129
  "collapsed",
118
130
  "expanded"
119
131
  ],
120
- "type": "string"
132
+ "description": "Initial visibility of the process dock."
121
133
  },
122
134
  "dockHeight": {
123
- "description": "Number of log rows displayed in the expanded process dock.",
124
- "type": "number"
125
- },
126
- "showStatusWidget": {
127
- "description": "Show a one-line process summary below the editor.",
128
- "type": "boolean"
135
+ "type": "number",
136
+ "description": "Number of log rows displayed in the expanded process dock."
129
137
  }
130
138
  },
131
- "type": "object"
139
+ "additionalProperties": false
132
140
  }
133
141
  }
134
- }
142
+ }
@@ -1,21 +0,0 @@
1
- import type { Migration } from "@aliou/pi-utils-settings";
2
-
3
- import type { ProcessConfig } from "../types";
4
-
5
- export const PROCESS_CONFIG_VERSION = "0.10.0";
6
-
7
- export function needsConfigVersionStamp(config: ProcessConfig): boolean {
8
- return (config.version ?? "") < PROCESS_CONFIG_VERSION;
9
- }
10
-
11
- export function stampConfigVersion(config: ProcessConfig): ProcessConfig {
12
- return { ...config, version: PROCESS_CONFIG_VERSION };
13
- }
14
-
15
- export const configVersionStampMigration: Migration<ProcessConfig> = {
16
- name: "002-stamp-v0-10-0-config-version",
17
- shouldRun: needsConfigVersionStamp,
18
- run: (config) => stampConfigVersion(config),
19
- message:
20
- "Updated pi-processes settings for v0.10.0. This release rewrites the package into separate process, logs, and dock extensions while preserving your existing settings. Release notes are available at https://github.com/aliou/pi-processes/releases/tag/v0.10.0.",
21
- };