@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 +8 -0
- package/README.md +5 -5
- package/node_modules/@gotgenes/pi-permission-system/src/authority/permission-prompt-component.ts +0 -11
- package/node_modules/@gotgenes/pi-permission-system/src/config/config-store.ts +0 -5
- package/node_modules/@gotgenes/pi-permission-system/src/index.ts +3 -15
- package/package.json +1 -1
- package/dist/confirmation.d.ts +0 -33
- package/dist/confirmation.js +0 -64
- package/dist/yolo.d.ts +0 -6
- package/dist/yolo.js +0 -33
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.
|
|
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
|
-
-
|
|
51
|
+
- Подтверждения показывает штатный диалог `@gotgenes/pi-permission-system`: разрешение одного запуска или на сессию, отказ и отказ с причиной. Настройки клавиш и повторного нажатия управляются самим расширением; собственного диалога Datalab Kit нет.
|
|
52
52
|
- Одновременно работает один субагент. Инструмент `subagent` принимает одну задачу за вызов.
|
|
53
53
|
|
|
54
|
-
Уже заданные пользователем настройки имеют приоритет, включая
|
|
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
|
-
|
|
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 автоматически разрешает
|
|
62
|
+
YOLO автоматически разрешает `ask`. Явные `deny` и ограничения Plan mode сохраняются.
|
|
63
63
|
|
|
64
64
|
## Обновление и ограничение Pi 0.85.1
|
|
65
65
|
|
package/node_modules/@gotgenes/pi-permission-system/src/authority/permission-prompt-component.ts
CHANGED
|
@@ -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
|
|
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",
|
|
396
|
-
|
|
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
package/dist/confirmation.d.ts
DELETED
|
@@ -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 {};
|
package/dist/confirmation.js
DELETED
|
@@ -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
|
-
}
|