@dev-sergeev/datalab-kit 0.1.1 → 0.1.2

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
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2 — 2026-10-01
4
+
5
+ - Возвращён штатный диалог `@gotgenes/pi-permission-system`, включая разрешение на сессию и отказ с причиной. Собственный диалог Datalab Kit удалён.
6
+ - Удалены собственные команды `/yolo on|off|status`; YOLO остаётся в штатных настройках permission-system.
7
+ - Автоматическое разрешение чтения и todo, пользовательские правила и интеграция Plan mode сохранены.
8
+ - Сборка очищает устаревшие модули диалога и YOLO при обновлении с 0.1.1.
9
+ - Добавлены проверки штатных вариантов диалога, однократного и сессионного разрешения, смены сессии и штатного YOLO.
10
+
3
11
  ## 0.1.1 — 2026-10-01
4
12
 
5
13
  - Служебный todo и безопасные читающие цепочки с шаблонами файлов больше не требуют подтверждения по правилам набора.
package/README.md CHANGED
@@ -17,7 +17,7 @@ pi
17
17
  npm ci --ignore-scripts --legacy-peer-deps
18
18
  npm run build
19
19
  npm pack
20
- pi install ./dev-sergeev-datalab-kit-0.1.0.tgz
20
+ pi install ./dev-sergeev-datalab-kit-0.1.2.tgz
21
21
  ```
22
22
 
23
23
  Целевые системы — Linux и macOS; локальные интеграционные проверки выполнены на Linux. Проверка macOS включена в CI. Windows пока не заявляется.
@@ -48,18 +48,18 @@ pi install ./dev-sergeev-datalab-kit-0.1.0.tgz
48
48
  - `rm`, `hadoop`, `hdfs`, неизвестные команды и любой удалённый `curl` требуют подтверждения.
49
49
  - `curl` к `localhost`, `127.0.0.1` и `::1` разрешён только для GET/HEAD. Для автоматически разрешённых запросов отключаются `.curlrc` и прокси; перенаправления, вывод в файл и изменяющие запросы требуют подтверждения.
50
50
  - Составная команда проверяется целиком. `cat a > b` и `find . -delete` требуют подтверждения. Неизвестный синтаксис также требует подтверждения.
51
- - Диалог выделяет предупреждение, сначала выбирает **«Отмена»**. Enter отменяет; ↓ и Enter разрешают один запуск. Разрешений на всю сессию нет. В RPC доступны те же два варианта; обработку клавиш определяет клиент.
51
+ - Подтверждения показывает штатный диалог `@gotgenes/pi-permission-system`: разрешение одного запуска или на сессию, отказ и отказ с причиной. Настройки клавиш и повторного нажатия управляются самим расширением; собственного диалога Datalab Kit нет.
52
52
  - Одновременно работает один субагент. Инструмент `subagent` принимает одну задачу за вызов.
53
53
 
54
- Уже заданные пользователем настройки имеют приоритет, включая разрешения и число субагентов. Если пользователь явно настроил `doublePressToConfirm` или `permissionDialogKeys`, используется его исходный диалог permission-system. Значения набора действуют в памяти; существующие конфиги расширений не перезаписываются. Настройки разрешений остаются в штатных `extensions/pi-permission-system/config.json` внутри каталога агента и `.pi/extensions/pi-permission-system/config.json` внутри проекта. Субагенты используют `<agentDir>/subagents.json` и `<project>/.pi/subagents.json`.
54
+ Уже заданные пользователем настройки имеют приоритет, включая разрешения, настройки штатного диалога и число субагентов. Значения набора действуют в памяти; существующие конфиги расширений не перезаписываются. Настройки разрешений остаются в штатных `extensions/pi-permission-system/config.json` внутри каталога агента и `.pi/extensions/pi-permission-system/config.json` внутри проекта. Субагенты используют `<agentDir>/subagents.json` и `<project>/.pi/subagents.json`.
55
55
 
56
56
  В **Plan mode** допустимые инструменты и команды проверяет pi-plan-mode без дополнительных подтверждений по правилам набора. Явные пользовательские `ask` и `deny` продолжают действовать; некорректная конфигурация разрешений также не обходится. После выхода из Plan mode или перехода к реализации правила набора снова действуют. Это поведение сохраняется при восстановлении сессии и смене ветки. Plan mode допускает некоторые тесты и проверки, которые могут создавать артефакты.
57
57
 
58
58
  ## YOLO
59
59
 
60
- `/yolo on` отключает запросы подтверждения в текущей сессии; в статусе появляется `yolo`. `/yolo off` возвращает подтверждения, а `/yolo status` показывает эффективный режим. Команды не переписывают настройки; новая или повторно открытая сессия использует постоянную настройку.
60
+ YOLO управляется штатным `@gotgenes/pi-permission-system`: откройте `/permission-system` → **YOLO mode** или задайте `"yoloMode": true` в конфигурации расширения. Собственные сессионные команды `/yolo on|off|status`, добавленные в 0.1.1, удалены в 0.1.2.
61
61
 
62
- YOLO автоматически разрешает любые `ask`, включая явные пользовательские запросы и запросы из-за некорректной конфигурации. Явные `deny` и ограничения Plan mode сохраняются. Для постоянного включения откройте `/permission-system` → **YOLO mode** или задайте `"yoloMode": true` в конфигурации permission-system. Сессионный `/yolo off` временно выключает и постоянно включённый YOLO.
62
+ YOLO автоматически разрешает `ask`. Явные `deny` и ограничения Plan mode сохраняются.
63
63
 
64
64
  ## Обновление и ограничение Pi 0.85.1
65
65
 
@@ -1,5 +1,3 @@
1
- // Datalab Kit adaptation
2
- import { confirmPermission } from "../../../../../dist/confirmation.js";
3
1
  import type {
4
2
  ExtensionContext,
5
3
  ExtensionUIContext,
@@ -64,7 +62,6 @@ export interface PermissionPromptView extends PromptPreferences {
64
62
 
65
63
  /** Live prompt-behavior preferences read at prompt time (see `doublePressToConfirm`). */
66
64
  export interface PromptPreferences {
67
- kitUseUserDialog?: boolean;
68
65
  doublePressToConfirm: boolean;
69
66
  /** How much room a render has; the terminal width is added per frame. */
70
67
  budget: RenderBudget;
@@ -89,14 +86,6 @@ export async function requestPermissionDecision(
89
86
  title: string,
90
87
  payload: PromptPayload,
91
88
  options?: RequestPermissionOptions,
92
- ): Promise<PermissionPromptDecision> {
93
- if (view.kitUseUserDialog) return upstreamPermissionDecision(view, title, payload, options);
94
- const approved = await confirmPermission(view.ui, view.mode, title, payload);
95
- return attributeToHuman({ approved, state: approved ? 'approved' : 'denied' }, view.mode === 'tui' ? 'dialog' : 'select');
96
- }
97
-
98
- async function upstreamPermissionDecision(
99
- view: PermissionPromptView, title: string, payload: PromptPayload, options?: RequestPermissionOptions,
100
89
  ): Promise<PermissionPromptDecision> {
101
90
  if (view.mode === "tui") {
102
91
  return attributeToHuman(
@@ -1,5 +1,3 @@
1
- // Datalab Kit adaptation
2
-
3
1
  import {
4
2
  existsSync,
5
3
  mkdirSync,
@@ -84,8 +82,6 @@ export class ConfigStore
84
82
  {
85
83
  private config: PermissionSystemExtensionConfig;
86
84
  private configIssues: readonly string[] = [];
87
- private userDialog = false;
88
- usesUserDialog(): boolean { return this.userDialog; }
89
85
 
90
86
  constructor(private readonly deps: ConfigStoreDeps) {
91
87
  this.config = { ...DEFAULT_EXTENSION_CONFIG };
@@ -137,7 +133,6 @@ export class ConfigStore
137
133
  );
138
134
  const runtimeConfig = normalizePermissionSystemConfig(mergeResult.merged);
139
135
  this.config = runtimeConfig;
140
- this.userDialog = mergeResult.merged.doublePressToConfirm !== undefined || mergeResult.merged.permissionDialogKeys !== undefined;
141
136
 
142
137
  this.configIssues = mergeResult.issues;
143
138
 
@@ -1,7 +1,6 @@
1
1
  // Datalab Kit adaptation
2
2
  import { normalizeLocalReadCurl } from "../../../../dist/read-policy.js";
3
3
  import { isPlanModeActive } from "../../../../dist/plan-mode.js";
4
- import { registerYoloControl } from "../../../../dist/yolo.js";
5
4
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
6
5
  import { getAgentDir, getPackageDir } from "@earendil-works/pi-coding-agent";
7
6
  import { warmBashParser } from "#src/access-intent/bash/parser";
@@ -114,8 +113,7 @@ export default function piPermissionSystemExtension(pi: ExtensionAPI): void {
114
113
  // close over it; every call runs after configStore is assigned below. yolo is
115
114
  // a composition-stage ask→allow rewrite (#526) that the gate runner extends
116
115
  // to asks synthesized after resolution (#712), so both share this reader.
117
- const kitYolo = registerYoloControl(pi, () => isYoloModeEnabled(configStore.current()));
118
- const isYoloEnabled = (): boolean => kitYolo.isEnabled();
116
+ const isYoloEnabled = (): boolean => isYoloModeEnabled(configStore.current());
119
117
 
120
118
  let kitSession: ExtensionContext["sessionManager"] | undefined;
121
119
  const permissionManager = new PermissionManager({
@@ -157,7 +155,6 @@ export default function piPermissionSystemExtension(pi: ExtensionAPI): void {
157
155
  detection: subagentDetection,
158
156
  events: pi.events,
159
157
  getPromptPreferences: () => ({
160
- kitUseUserDialog: configStore.usesUserDialog(),
161
158
  doublePressToConfirm: configStore.current().doublePressToConfirm,
162
159
  budget: resolveRenderBudget(configStore.current()),
163
160
  dialogKeys: resolveDialogKeys(configStore.current()).keys,
@@ -386,22 +383,13 @@ export default function piPermissionSystemExtension(pi: ExtensionAPI): void {
386
383
  pi.on("session_start", async (event, ctx) => {
387
384
  kitSession = ctx.sessionManager;
388
385
  await lifecycle.handleSessionStart(event, ctx);
389
- kitYolo.refresh(ctx);
390
386
  });
391
387
  pi.on("resources_discover", (event, ctx) =>
392
388
  lifecycle.handleResourcesDiscover(event, ctx),
393
389
  );
394
390
  pi.on("session_shutdown", () => lifecycle.handleSessionShutdown());
395
- pi.on("before_agent_start", async (event, ctx) => {
396
- const result = await agentPrep.handle(event, ctx);
397
- kitYolo.refresh(ctx);
398
- return result;
399
- });
400
- pi.on("input", async (event, ctx) => {
401
- const result = await gates.handleInput(event, ctx);
402
- kitYolo.refresh(ctx);
403
- return result;
404
- });
391
+ pi.on("before_agent_start", (event, ctx) => agentPrep.handle(event, ctx));
392
+ pi.on("input", (event, ctx) => gates.handleInput(event, ctx));
405
393
  pi.on(
406
394
  "tool_call",
407
395
  createFailClosedToolCall(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-sergeev/datalab-kit",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "A ready-to-use collection of Pi coding agent extensions",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,33 +0,0 @@
1
- import type { ExtensionUIContext } from '@earendil-works/pi-coding-agent';
2
- type DialogTheme = {
3
- fg(color: 'warning' | 'accent' | 'muted', text: string): string;
4
- bold(text: string): string;
5
- };
6
- /** One instance represents one decision; it never remembers a session grant. */
7
- export declare class ConfirmationDialog {
8
- private readonly command;
9
- private readonly theme;
10
- private readonly done;
11
- private approve;
12
- private finished;
13
- private scroll;
14
- constructor(command: string, theme: DialogTheme, done: (approved: boolean) => void);
15
- handleInput(data: string): void;
16
- render(width: number): string[];
17
- invalidate(): void;
18
- }
19
- type PermissionPayload = {
20
- request: {
21
- value: string;
22
- toolName: string | null;
23
- surface: string;
24
- executedUnit: string | null;
25
- };
26
- evidence: readonly {
27
- label: string;
28
- text: string;
29
- detail: string | null;
30
- }[];
31
- };
32
- export declare function confirmPermission(ui: Pick<ExtensionUIContext, 'custom' | 'select'>, mode: string, title: string, payload: PermissionPayload): Promise<boolean>;
33
- export {};
@@ -1,64 +0,0 @@
1
- import { matchesKey, wrapTextWithAnsi } from '@earendil-works/pi-tui';
2
- /** One instance represents one decision; it never remembers a session grant. */
3
- export class ConfirmationDialog {
4
- command;
5
- theme;
6
- done;
7
- approve = false;
8
- finished = false;
9
- scroll = 0;
10
- constructor(command, theme, done) {
11
- this.command = command;
12
- this.theme = theme;
13
- this.done = done;
14
- }
15
- handleInput(data) {
16
- if (this.finished)
17
- return;
18
- if (matchesKey(data, 'down'))
19
- this.approve = true;
20
- else if (matchesKey(data, 'up'))
21
- this.approve = false;
22
- else if (matchesKey(data, 'pageDown'))
23
- this.scroll += 10;
24
- else if (matchesKey(data, 'pageUp'))
25
- this.scroll = Math.max(0, this.scroll - 10);
26
- else if (matchesKey(data, 'escape') || matchesKey(data, 'enter')) {
27
- this.finished = true;
28
- this.done(matchesKey(data, 'enter') && this.approve);
29
- }
30
- }
31
- render(width) {
32
- const usableWidth = Math.max(1, width - 4);
33
- const safeText = this.command.replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/g, '');
34
- const lines = safeText.split('\n').flatMap(line => wrapTextWithAnsi(line, usableWidth));
35
- this.scroll = Math.min(this.scroll, Math.max(0, lines.length - 12));
36
- const choices = ['Отмена', 'Разрешить один раз'];
37
- return [
38
- this.theme.fg('warning', this.theme.bold('ТРЕБУЕТСЯ ПОДТВЕРЖДЕНИЕ')),
39
- ...lines.slice(this.scroll, this.scroll + 12).map(line => this.theme.fg('warning', line)),
40
- ...(lines.length > 12 ? [this.theme.fg('muted', `Строки ${this.scroll + 1}–${Math.min(this.scroll + 12, lines.length)} из ${lines.length}; PgUp/PgDn — просмотр`)] : []),
41
- '',
42
- ...choices.map((label, index) => this.theme.fg(index === Number(this.approve) ? 'accent' : 'muted', `${index === Number(this.approve) ? '▶' : ' '} ${label}`)),
43
- this.theme.fg('muted', '↓ затем Enter — разрешить один раз; Enter по умолчанию / Esc — отменить'),
44
- ].flatMap(line => wrapTextWithAnsi(line, Math.max(1, width)));
45
- }
46
- invalidate() { }
47
- }
48
- export async function confirmPermission(ui, mode, title, payload) {
49
- const details = [title, `${payload.request.toolName ?? payload.request.surface}: ${payload.request.value}`,
50
- ...(payload.request.executedUnit ? [`Выполняется: ${payload.request.executedUnit}`] : []),
51
- ...payload.evidence.map(item => `${item.label}: ${item.text}${item.detail ? `\n${item.detail}` : ''}`),
52
- ].join('\n');
53
- if (mode !== 'tui') {
54
- return (await ui.select(details, ['Отмена', 'Разрешить один раз'])) === 'Разрешить один раз';
55
- }
56
- return ui.custom((tui, theme, _keys, done) => {
57
- const dialog = new ConfirmationDialog(details, theme, done);
58
- return {
59
- render: width => dialog.render(width),
60
- invalidate: () => dialog.invalidate(),
61
- handleInput: data => { dialog.handleInput(data); tui.requestRender(); },
62
- };
63
- });
64
- }
package/dist/yolo.d.ts DELETED
@@ -1,6 +0,0 @@
1
- import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';
2
- /** Session overrides stay in memory; persistent settings retain their own value. */
3
- export declare function registerYoloControl(pi: ExtensionAPI, configured: () => boolean): {
4
- isEnabled(): boolean;
5
- refresh(ctx?: ExtensionContext): void;
6
- };
package/dist/yolo.js DELETED
@@ -1,33 +0,0 @@
1
- /** Session overrides stay in memory; persistent settings retain their own value. */
2
- export function registerYoloControl(pi, configured) {
3
- let override;
4
- let context;
5
- const enabled = () => override ?? configured();
6
- const refresh = (ctx) => {
7
- if (ctx)
8
- context = ctx;
9
- context?.ui.setStatus('pi-permission-system', enabled() ? 'yolo' : undefined);
10
- };
11
- pi.on('session_start', (_event, ctx) => {
12
- override = undefined;
13
- context = ctx;
14
- });
15
- pi.registerCommand('yolo', {
16
- description: 'Set session YOLO: on, off, or status; explicit deny and Plan mode remain active',
17
- getArgumentCompletions: prefix => ['on', 'off', 'status'].filter(value => value.startsWith(prefix))
18
- .map(value => ({ value, label: value })),
19
- handler: async (args, ctx) => {
20
- context = ctx;
21
- const command = args.trim().toLowerCase() || 'status';
22
- if (!['on', 'off', 'status'].includes(command)) {
23
- ctx.ui.notify('Usage: /yolo on|off|status', 'warning');
24
- return;
25
- }
26
- if (command !== 'status')
27
- override = command === 'on';
28
- refresh();
29
- ctx.ui.notify(`YOLO ${enabled() ? 'on' : 'off'} (${override === undefined ? 'settings' : 'session'}). Explicit deny and Plan mode remain active.`, 'info');
30
- },
31
- });
32
- return { isEnabled: () => { refresh(); return enabled(); }, refresh };
33
- }