@saifymatteo/pi-extensions 0.1.3 → 0.1.5

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 (65) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/package.json +2 -1
  3. package/packages/pi-bg-bash/AGENTS.md +29 -0
  4. package/packages/pi-bg-bash/CHANGELOG.md +25 -0
  5. package/packages/pi-bg-bash/package.json +2 -1
  6. package/packages/pi-bg-bash/src/index.ts +189 -99
  7. package/packages/pi-bg-bash/src/lib/output.ts +31 -0
  8. package/packages/pi-bg-bash/src/lib/panel.ts +155 -0
  9. package/packages/pi-bg-bash/src/lib/process-control.ts +221 -0
  10. package/packages/pi-bg-bash/src/lib/windows-console.ts +169 -0
  11. package/packages/pi-bg-bash/test/job-controls.test.mjs +347 -0
  12. package/packages/pi-bg-bash/test/native-process-control.test.mjs +126 -0
  13. package/packages/pi-bg-bash/test/output.test.mjs +28 -0
  14. package/packages/pi-bg-bash/test/panel.test.mjs +146 -0
  15. package/packages/pi-bg-bash/test/process-control.test.mjs +300 -0
  16. package/packages/pi-bg-bash/test/windows-console.test.mjs +221 -0
  17. package/packages/pi-claude-usage/CHANGELOG.md +18 -0
  18. package/packages/pi-claude-usage/package.json +2 -1
  19. package/packages/pi-clipboard-image/CHANGELOG.md +18 -0
  20. package/packages/pi-clipboard-image/package.json +2 -1
  21. package/packages/pi-codeblock-borders/CHANGELOG.md +18 -0
  22. package/packages/pi-codeblock-borders/package.json +2 -1
  23. package/packages/pi-codegraph/CHANGELOG.md +25 -0
  24. package/packages/pi-codegraph/package.json +2 -1
  25. package/packages/pi-codegraph/src/index.ts +67 -27
  26. package/packages/pi-compact-tools/CHANGELOG.md +18 -0
  27. package/packages/pi-compact-tools/package.json +2 -1
  28. package/packages/pi-decisions/CHANGELOG.md +18 -0
  29. package/packages/pi-decisions/package.json +2 -1
  30. package/packages/pi-load-pi-dotenv/CHANGELOG.md +18 -0
  31. package/packages/pi-load-pi-dotenv/package.json +2 -1
  32. package/packages/pi-model-go/CHANGELOG.md +18 -0
  33. package/packages/pi-model-go/package.json +2 -1
  34. package/packages/pi-prestart-working/CHANGELOG.md +18 -0
  35. package/packages/pi-prestart-working/package.json +2 -1
  36. package/packages/pi-root-guard/CHANGELOG.md +18 -0
  37. package/packages/pi-root-guard/package.json +2 -1
  38. package/packages/pi-session-finder/CHANGELOG.md +18 -0
  39. package/packages/pi-session-finder/package.json +2 -1
  40. package/packages/pi-session-id/CHANGELOG.md +18 -0
  41. package/packages/pi-session-id/package.json +2 -1
  42. package/packages/pi-session-nav/CHANGELOG.md +18 -0
  43. package/packages/pi-session-nav/package.json +2 -1
  44. package/packages/pi-session-rename/CHANGELOG.md +18 -0
  45. package/packages/pi-session-rename/package.json +2 -1
  46. package/packages/pi-session-retention/AGENTS.md +15 -0
  47. package/packages/pi-session-retention/CHANGELOG.md +25 -0
  48. package/packages/pi-session-retention/package.json +2 -1
  49. package/packages/pi-session-retention/src/index.ts +43 -4
  50. package/packages/pi-session-retention/test/startup.test.mjs +229 -0
  51. package/packages/pi-skill-usage-log/CHANGELOG.md +18 -0
  52. package/packages/pi-skill-usage-log/package.json +2 -1
  53. package/packages/pi-tool-usage-log/CHANGELOG.md +18 -0
  54. package/packages/pi-tool-usage-log/package.json +2 -1
  55. package/packages/pi-tts/CHANGELOG.md +18 -0
  56. package/packages/pi-tts/package.json +2 -1
  57. package/packages/pi-user-image-previews/CHANGELOG.md +18 -0
  58. package/packages/pi-user-image-previews/package.json +2 -1
  59. package/packages/pi-vision/CHANGELOG.md +18 -0
  60. package/packages/pi-vision/package.json +2 -1
  61. package/packages/pi-wait/CHANGELOG.md +18 -0
  62. package/packages/pi-wait/package.json +2 -1
  63. package/packages/pi-zvec/CHANGELOG.md +25 -0
  64. package/packages/pi-zvec/package.json +2 -1
  65. package/packages/pi-zvec/src/index.ts +81 -39
@@ -121,6 +121,9 @@ async function trashSearchText(trash: string, batch: TrashBatch): Promise<{ sear
121
121
  export default function sessionRetention(pi: ExtensionAPI, options: { guard?: () => Promise<void>; now?: () => number } = {}) {
122
122
  const now = options.now ?? Date.now;
123
123
  let started = false;
124
+ let pendingAutomatic = false;
125
+ let automaticTimer: ReturnType<typeof setTimeout> | undefined;
126
+ let automatic: Promise<void> | undefined;
124
127
  let maintaining = false;
125
128
  let lifecycle = new AbortController();
126
129
  let operation: Promise<unknown> | undefined;
@@ -159,10 +162,18 @@ export default function sessionRetention(pi: ExtensionAPI, options: { guard?: ()
159
162
  };
160
163
  pi.on("session_before_switch", preventSwitch);
161
164
  pi.on("session_before_fork", preventSwitch);
165
+ function cancelAutomatic() {
166
+ pendingAutomatic = false;
167
+ if (automaticTimer !== undefined) clearTimeout(automaticTimer);
168
+ automaticTimer = undefined;
169
+ }
162
170
  pi.on("session_shutdown", async (_event, ctx) => {
171
+ cancelAutomatic();
163
172
  status(ctx, undefined);
164
173
  lifecycle.abort();
165
174
  closeDialog?.();
175
+ // Drain the background handler as well as file work before replacing its context.
176
+ await automatic?.catch(() => {});
166
177
  // Never release a lock while a file operation can still be using it.
167
178
  await operation?.catch(() => {});
168
179
  started = false;
@@ -199,7 +210,13 @@ export default function sessionRetention(pi: ExtensionAPI, options: { guard?: ()
199
210
  ].join("\n");
200
211
  if (previewOnly) { status(ctx, "Session cleanup: preview — no changes"); await ctx.ui.confirm("Preview only — nothing will be changed", summary, { signal }); return; }
201
212
  if (!state.approved || state.paused) {
202
- if (!manual && !count && !expired.length) { state.lastRun = time; await saveState(paths.trash, state); return; }
213
+ if (!manual) {
214
+ // Background discovery must not replace the editor with an approval dialog.
215
+ if (count || expired.length) ctx.ui.notify("Session cleanup is available. Run /session-cleanup to review and enable daily automatic cleanup.", "info");
216
+ state.lastRun = time;
217
+ await saveState(paths.trash, state);
218
+ return;
219
+ }
203
220
  status(ctx, "Session cleanup: awaiting approval…");
204
221
  const approved = await ctx.ui.confirm("Enable daily session cleanup?", `${summary}\n\nApprove this cleanup and future automatic cleanup at startup (at most daily)?`, { signal });
205
222
  signal.throwIfAborted();
@@ -228,13 +245,33 @@ export default function sessionRetention(pi: ExtensionAPI, options: { guard?: ()
228
245
  });
229
246
  }
230
247
 
231
- pi.on("session_start", async (_event, ctx) => {
248
+ function scheduleAutomatic(ctx: ExtensionContext) {
249
+ if (!pendingAutomatic || automaticTimer !== undefined || automatic || maintaining) return;
250
+ const signal = lifecycle.signal;
251
+ if (signal.aborted) return;
252
+ // Yield before starting maintenance; startup never awaits this task.
253
+ automaticTimer = setTimeout(() => {
254
+ automaticTimer = undefined;
255
+ if (signal.aborted || !pendingAutomatic || !ctx.isIdle() || maintaining) return;
256
+ pendingAutomatic = false;
257
+ automatic = cleanup(ctx, false)
258
+ .catch((error) => {
259
+ if (!signal.aborted) {
260
+ try { ctx.ui.notify(message(error), "warning"); } catch { /* UI failures must not reject a detached task. */ }
261
+ }
262
+ })
263
+ .finally(() => { automatic = undefined; });
264
+ }, 0);
265
+ automaticTimer.unref();
266
+ }
267
+ pi.on("session_start", (_event, ctx) => {
232
268
  if (lifecycle.signal.aborted) lifecycle = new AbortController();
233
269
  if (started || ctx.mode !== "tui" || !ctx.sessionManager.getSessionFile()) return;
234
270
  started = true;
235
- const signal = lifecycle.signal;
236
- try { await cleanup(ctx, false); } catch (error) { if (!signal.aborted) ctx.ui.notify(message(error), "warning"); }
271
+ pendingAutomatic = true;
272
+ scheduleAutomatic(ctx);
237
273
  });
274
+ pi.on("agent_settled", (_event, ctx) => { scheduleAutomatic(ctx); });
238
275
 
239
276
  pi.registerCommand("session-cleanup", {
240
277
  description: "Clean inactive session families [preview|pause]",
@@ -250,6 +287,7 @@ export default function sessionRetention(pi: ExtensionAPI, options: { guard?: ()
250
287
  const signal = lifecycle.signal;
251
288
  const action = args.trim();
252
289
  if (!["", "preview", "pause"].includes(action)) return ctx.ui.notify("Usage: /session-cleanup [preview|pause]", "info");
290
+ cancelAutomatic();
253
291
  try {
254
292
  if (action === "pause") {
255
293
  const paths = storePaths(ctx);
@@ -265,6 +303,7 @@ export default function sessionRetention(pi: ExtensionAPI, options: { guard?: ()
265
303
  description: "Search Trash by names, first prompts, IDs or paths; restore a whole family",
266
304
  handler: async (args, ctx) => {
267
305
  if (ctx.mode !== "tui") return ctx.ui.notify("Session Trash requires interactive mode.", "warning");
306
+ cancelAutomatic();
268
307
  const signal = lifecycle.signal;
269
308
  try {
270
309
  await ctx.waitForIdle();
@@ -0,0 +1,229 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtemp, mkdir, writeFile, readFile, access, rm, realpath, utimes } from 'node:fs/promises';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { setImmediate } from 'node:timers/promises';
7
+ import { loadExtension } from '../../../test/load-extension.mjs';
8
+ import * as core from '../src/core.ts';
9
+
10
+ const deferred = () => {
11
+ let resolve;
12
+ const promise = new Promise(done => { resolve = done; });
13
+ return { promise, resolve };
14
+ };
15
+
16
+ async function harness(t, { old = false, state, holdScan = false, scanError = false } = {}) {
17
+ const dir = await mkdtemp(join(await realpath(tmpdir()), 'pi-retention-startup-'));
18
+ const root = join(dir, 'sessions');
19
+ const file = join(root, 'session.jsonl');
20
+ const now = Date.now();
21
+ const stamp = old ? now - core.RETENTION_MS - 60_000 : now;
22
+ await mkdir(root);
23
+ await writeFile(file, JSON.stringify({ type: 'session', id: 'fixture', timestamp: new Date(stamp).toISOString() }) + '\n');
24
+ await utimes(file, new Date(stamp), new Date(stamp));
25
+ const entered = deferred(), release = deferred(), finished = deferred(), notified = deferred();
26
+ const timers = new Map(), hooks = {}, commands = {}, notifications = [], confirmations = [];
27
+ let scans = 0, probes = 0, nextTimer = 0;
28
+ const extension = loadExtension(new URL('../src/index.ts', import.meta.url), {
29
+ './core.ts': {
30
+ ...core,
31
+ RetentionStore: class extends core.RetentionStore {
32
+ async scan(options) {
33
+ scans++;
34
+ entered.resolve();
35
+ if (holdScan) await release.promise;
36
+ if (scanError) throw new Error('fixture scan failed');
37
+ return super.scan(options);
38
+ }
39
+ },
40
+ },
41
+ }, {
42
+ performance,
43
+ setTimeout: callback => { const id = { id: ++nextTimer, unref() {} }; timers.set(id, callback); return id; },
44
+ clearTimeout: id => { timers.delete(id); },
45
+ });
46
+ extension.default({
47
+ on: (name, handler) => { hooks[name] = handler; },
48
+ registerCommand: (name, command) => { commands[name] = command; },
49
+ }, { now: () => now, guard: async () => { probes++; } });
50
+ const ctx = {
51
+ mode: 'tui',
52
+ idle: true,
53
+ isIdle() { return this.idle; },
54
+ sessionManager: { getSessionDir: () => root, getCwd: () => dir, getSessionFile: () => join(root, 'active.jsonl') },
55
+ waitForIdle: async () => {},
56
+ ui: {
57
+ custom: async () => undefined,
58
+ setStatus: (_key, text) => { if (text === undefined) finished.resolve(); },
59
+ notify: (text, level) => { notifications.push({ text, level }); notified.resolve(); },
60
+ confirm: async (...args) => { confirmations.push(args); return true; },
61
+ },
62
+ };
63
+ const { trash } = extension.storePaths(ctx);
64
+ if (state) {
65
+ await mkdir(trash, { recursive: true });
66
+ await writeFile(join(trash, 'settings.json'), JSON.stringify({ approved: true, paused: false, lastRun: 0, ...state }));
67
+ }
68
+ t.after(async () => {
69
+ release.resolve();
70
+ await hooks.session_shutdown({}, ctx);
71
+ await rm(dir, { recursive: true, force: true });
72
+ });
73
+ return {
74
+ ctx, hooks, commands, timers, notifications, confirmations, file, trash, now, entered, release, finished, notified,
75
+ get scans() { return scans; },
76
+ get probes() { return probes; },
77
+ runTimer() {
78
+ assert.equal(timers.size, 1);
79
+ const [id, callback] = timers.entries().next().value;
80
+ timers.delete(id);
81
+ callback();
82
+ },
83
+ };
84
+ }
85
+
86
+ test('startup returns before scanning; shutdown drains background work before releasing its lock', async t => {
87
+ const h = await harness(t, { holdScan: true });
88
+ assert.equal(h.hooks.session_start({}, h.ctx), undefined);
89
+ assert.equal(h.scans, 0);
90
+ assert.equal(h.timers.size, 1);
91
+ h.hooks.session_start({}, h.ctx);
92
+ assert.equal(h.timers.size, 1);
93
+ h.runTimer();
94
+ await h.entered.promise;
95
+ assert.equal(h.hooks.session_before_switch({}, h.ctx).cancel, true);
96
+ assert.equal(h.hooks.session_before_fork({}, h.ctx).cancel, true);
97
+ let stopped = false;
98
+ const shutdown = h.hooks.session_shutdown({}, h.ctx).then(() => { stopped = true; });
99
+ await Promise.resolve();
100
+ assert.equal(stopped, false);
101
+ await access(join(h.trash, '.maintenance.lock'));
102
+ h.release.resolve();
103
+ await shutdown;
104
+ await assert.rejects(access(join(h.trash, '.maintenance.lock')), { code: 'ENOENT' });
105
+ assert.equal(h.notifications.some(item => item.level === 'warning' && /aborted/i.test(item.text)), false);
106
+ });
107
+
108
+ test('busy startup defers until agent_settled and never schedules duplicate scans', async t => {
109
+ const h = await harness(t);
110
+ h.ctx.idle = false;
111
+ h.hooks.session_start({}, h.ctx);
112
+ h.runTimer();
113
+ assert.equal(h.scans, 0);
114
+ assert.equal(h.timers.size, 0);
115
+ h.ctx.idle = true;
116
+ h.hooks.agent_settled({}, h.ctx);
117
+ h.hooks.agent_settled({}, h.ctx);
118
+ h.runTimer();
119
+ await h.finished.promise;
120
+ assert.equal(h.scans, 1);
121
+ h.hooks.agent_settled({}, h.ctx);
122
+ assert.equal(h.timers.size, 0);
123
+ });
124
+
125
+ test('automatic discovery notifies instead of opening approval; explicit cleanup can approve', async t => {
126
+ const h = await harness(t, { old: true });
127
+ h.hooks.session_start({}, h.ctx);
128
+ h.runTimer();
129
+ await h.finished.promise;
130
+ assert.equal(h.confirmations.length, 0);
131
+ assert.ok(h.notifications.some(item => /\/session-cleanup/.test(item.text)));
132
+ await access(h.file);
133
+ assert.equal(h.probes, 0);
134
+ const state = JSON.parse(await readFile(join(h.trash, 'settings.json'), 'utf8'));
135
+ assert.equal(state.approved, false);
136
+ assert.equal(state.lastRun, h.now);
137
+ await h.commands['session-cleanup'].handler('', h.ctx);
138
+ assert.equal(h.confirmations.length, 1);
139
+ assert.deepEqual(h.notifications.filter(item => item.level === 'error'), []);
140
+ assert.ok(h.probes > 0);
141
+ await assert.rejects(access(h.file), { code: 'ENOENT' });
142
+ });
143
+
144
+ test('previously approved automatic cleanup still moves eligible sessions without a dialog', async t => {
145
+ const h = await harness(t, { old: true, state: {} });
146
+ h.hooks.session_start({}, h.ctx);
147
+ h.runTimer();
148
+ await h.finished.promise;
149
+ assert.equal(h.confirmations.length, 0);
150
+ assert.deepEqual(h.notifications.filter(item => item.level === 'warning'), []);
151
+ assert.ok(h.probes > 0);
152
+ await assert.rejects(access(h.file), { code: 'ENOENT' });
153
+ });
154
+
155
+ test('daily and paused settings still skip scans in the background', async t => {
156
+ for (const state of [{ lastRun: Date.now() }, { paused: true }]) {
157
+ await t.test(JSON.stringify(state), async t => {
158
+ const h = await harness(t, { state });
159
+ h.hooks.session_start({}, h.ctx);
160
+ h.runTimer();
161
+ await h.finished.promise;
162
+ assert.equal(h.scans, 0);
163
+ assert.equal(h.probes, 0);
164
+ });
165
+ }
166
+ });
167
+
168
+ test('shutdown cancels queued maintenance and a new session can schedule again', async t => {
169
+ const h = await harness(t);
170
+ h.hooks.session_start({}, h.ctx);
171
+ await h.hooks.session_shutdown({}, h.ctx);
172
+ assert.equal(h.timers.size, 0);
173
+ assert.equal(h.scans, 0);
174
+ h.hooks.session_start({}, h.ctx);
175
+ h.runTimer();
176
+ await h.entered.promise;
177
+ await h.hooks.session_shutdown({}, h.ctx);
178
+ assert.equal(h.scans, 1);
179
+ });
180
+
181
+ test('explicit maintenance cancels queued automatic work', async t => {
182
+ for (const [command, args] of [['session-cleanup', 'pause'], ['session-trash', '']]) {
183
+ await t.test(command, async t => {
184
+ const h = await harness(t);
185
+ h.hooks.session_start({}, h.ctx);
186
+ await h.commands[command].handler(args, h.ctx);
187
+ assert.equal(h.timers.size, 0);
188
+ h.hooks.agent_settled({}, h.ctx);
189
+ assert.equal(h.timers.size, 0);
190
+ assert.equal(h.scans, 0);
191
+ assert.deepEqual(h.notifications.filter(item => item.level === 'error'), []);
192
+ });
193
+ }
194
+ });
195
+
196
+ test('non-TUI modes and sessions without a file schedule no maintenance', async t => {
197
+ const h = await harness(t);
198
+ for (const mode of ['print', 'json', 'rpc']) {
199
+ h.ctx.mode = mode;
200
+ h.hooks.session_start({}, h.ctx);
201
+ assert.equal(h.timers.size, 0);
202
+ }
203
+ h.ctx.mode = 'tui';
204
+ h.ctx.sessionManager.getSessionFile = () => undefined;
205
+ h.hooks.session_start({}, h.ctx);
206
+ assert.equal(h.timers.size, 0);
207
+ });
208
+
209
+ test('background failures are reported and release the maintenance lock', async t => {
210
+ const h = await harness(t, { scanError: true });
211
+ h.hooks.session_start({}, h.ctx);
212
+ h.runTimer();
213
+ await h.notified.promise;
214
+ await h.hooks.session_shutdown({}, h.ctx);
215
+ assert.ok(h.notifications.some(item => /fixture scan failed/.test(item.text)));
216
+ await assert.rejects(access(join(h.trash, '.maintenance.lock')), { code: 'ENOENT' });
217
+ });
218
+
219
+ test('a failed UI notification cannot cause an unhandled background rejection', async t => {
220
+ const h = await harness(t, { scanError: true });
221
+ const notify = h.ctx.ui.notify;
222
+ h.ctx.ui.notify = (...args) => { notify(...args); throw new Error('fixture UI failed'); };
223
+ h.hooks.session_start({}, h.ctx);
224
+ h.runTimer();
225
+ await h.notified.promise;
226
+ // Give detached promise rejections a turn to surface in the test runner.
227
+ await setImmediate();
228
+ await assert.rejects(access(join(h.trash, '.maintenance.lock')), { code: 'ENOENT' });
229
+ });
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ Release notes are recorded from 0.1.3 onward.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.4]
8
+
9
+ ### Added
10
+
11
+ - Include package release notes in Pi 1.5.0's Extension Updates.
12
+
13
+ ## [0.1.3]
14
+
15
+ ### Fixed
16
+
17
+ - Classify the package as an extension in the Pi package gallery.
18
+ - Show the package screenshot as its gallery preview.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saifymatteo/pi-skill-usage-log",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "src",
12
12
  "README.md",
13
+ "CHANGELOG.md",
13
14
  "NOTICE.md",
14
15
  "LICENSE"
15
16
  ],
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ Release notes are recorded from 0.1.3 onward.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.4]
8
+
9
+ ### Added
10
+
11
+ - Include package release notes in Pi 1.5.0's Extension Updates.
12
+
13
+ ## [0.1.3]
14
+
15
+ ### Fixed
16
+
17
+ - Classify the package as an extension in the Pi package gallery.
18
+ - Show the package screenshot as its gallery preview.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saifymatteo/pi-tool-usage-log",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "src",
12
12
  "README.md",
13
+ "CHANGELOG.md",
13
14
  "NOTICE.md",
14
15
  "LICENSE"
15
16
  ],
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ Release notes are recorded from 0.1.3 onward.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.4]
8
+
9
+ ### Added
10
+
11
+ - Include package release notes in Pi 1.5.0's Extension Updates.
12
+
13
+ ## [0.1.3]
14
+
15
+ ### Fixed
16
+
17
+ - Classify the package as an extension in the Pi package gallery.
18
+ - Show the package screenshot as its gallery preview.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saifymatteo/pi-tts",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -11,6 +11,7 @@
11
11
  "src",
12
12
  "examples",
13
13
  "README.md",
14
+ "CHANGELOG.md",
14
15
  "NOTICE.md",
15
16
  "LICENSE"
16
17
  ],
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ Release notes are recorded from 0.1.3 onward.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.4]
8
+
9
+ ### Added
10
+
11
+ - Include package release notes in Pi 1.5.0's Extension Updates.
12
+
13
+ ## [0.1.3]
14
+
15
+ ### Fixed
16
+
17
+ - Classify the package as an extension in the Pi package gallery.
18
+ - Show the package screenshot as its gallery preview.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saifymatteo/pi-user-image-previews",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Adds collapsible UI-only previews for newly submitted image attachments.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -11,6 +11,7 @@
11
11
  "files": [
12
12
  "src",
13
13
  "README.md",
14
+ "CHANGELOG.md",
14
15
  "NOTICE.md",
15
16
  "LICENSE"
16
17
  ],
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ Release notes are recorded from 0.1.3 onward.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.4]
8
+
9
+ ### Added
10
+
11
+ - Include package release notes in Pi 1.5.0's Extension Updates.
12
+
13
+ ## [0.1.3]
14
+
15
+ ### Fixed
16
+
17
+ - Classify the package as both an extension and a skill package in the Pi package gallery.
18
+ - Show the package screenshot as its gallery preview.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saifymatteo/pi-vision",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -12,6 +12,7 @@
12
12
  "src",
13
13
  "examples",
14
14
  "README.md",
15
+ "CHANGELOG.md",
15
16
  "NOTICE.md",
16
17
  "LICENSE",
17
18
  "skills"
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ Release notes are recorded from 0.1.3 onward.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.4]
8
+
9
+ ### Added
10
+
11
+ - Include package release notes in Pi 1.5.0's Extension Updates.
12
+
13
+ ## [0.1.3]
14
+
15
+ ### Fixed
16
+
17
+ - Classify the package as an extension in the Pi package gallery.
18
+ - Show the package screenshot as its gallery preview.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saifymatteo/pi-wait",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -11,6 +11,7 @@
11
11
  "src",
12
12
  "examples",
13
13
  "README.md",
14
+ "CHANGELOG.md",
14
15
  "NOTICE.md",
15
16
  "LICENSE"
16
17
  ],
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ Release notes are recorded from 0.1.3 onward.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.5]
8
+
9
+ ### Added
10
+
11
+ - Include package release notes in Pi 1.5.0's Extension Updates.
12
+
13
+ ## [0.1.4]
14
+
15
+ ### Fixed
16
+
17
+ - Defer CLI checks, configuration, and index initialization until after session startup to avoid blocking Pi.
18
+ - Cancel stale initialization when the active session changes.
19
+
20
+ ## [0.1.3]
21
+
22
+ ### Fixed
23
+
24
+ - Classify the package as an extension in the Pi package gallery.
25
+ - Show the package screenshot as its gallery preview.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saifymatteo/pi-zvec",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -11,6 +11,7 @@
11
11
  "src",
12
12
  "examples",
13
13
  "README.md",
14
+ "CHANGELOG.md",
14
15
  "NOTICE.md",
15
16
  "LICENSE"
16
17
  ],