@kernel.chat/kbot 4.1.1 → 4.4.0

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 (36) hide show
  1. package/dist/adapters/agent-sdk/from-agent-sdk.d.ts +28 -0
  2. package/dist/adapters/agent-sdk/from-agent-sdk.js +107 -0
  3. package/dist/adapters/agent-sdk/index.d.ts +4 -0
  4. package/dist/adapters/agent-sdk/index.js +14 -0
  5. package/dist/adapters/agent-sdk/to-agent-sdk.d.ts +13 -0
  6. package/dist/adapters/agent-sdk/to-agent-sdk.js +73 -0
  7. package/dist/adapters/agent-sdk/types.d.ts +41 -0
  8. package/dist/adapters/agent-sdk/types.js +9 -0
  9. package/dist/adapters/peekaboo/commands.d.ts +42 -0
  10. package/dist/adapters/peekaboo/commands.js +209 -0
  11. package/dist/adapters/peekaboo/index.d.ts +4 -0
  12. package/dist/adapters/peekaboo/index.js +9 -0
  13. package/dist/adapters/peekaboo/runner.d.ts +25 -0
  14. package/dist/adapters/peekaboo/runner.js +75 -0
  15. package/dist/adapters/peekaboo/types.d.ts +69 -0
  16. package/dist/adapters/peekaboo/types.js +8 -0
  17. package/dist/cli.js +15 -1
  18. package/dist/permissions.d.ts +17 -0
  19. package/dist/permissions.js +48 -0
  20. package/dist/tool-pipeline.js +11 -0
  21. package/dist/tools/computer.js +64 -0
  22. package/dist/tools/peekaboo.d.ts +4 -0
  23. package/dist/tools/peekaboo.js +371 -0
  24. package/dist/tools/security-audit-local.d.ts +47 -0
  25. package/dist/tools/security-audit-local.js +363 -0
  26. package/dist/tools/stream-overlay.d.ts +9 -0
  27. package/dist/tools/stream-overlay.js +167 -134
  28. package/dist/tools/stream-renderer.js +10 -1
  29. package/dist/tools/swarm-2026-04.js +4 -0
  30. package/package.json +1 -1
  31. package/skills/ai-engineering/full-stack-mastery/SKILL.md +174 -0
  32. package/skills/native-automation/peekaboo-snapshot-act/SKILL.md +91 -0
  33. package/skills/security-audit/dependency-audit/SKILL.md +102 -0
  34. package/skills/security-audit/local-vulnerability-hunt/SKILL.md +127 -0
  35. package/skills/security-audit/secrets-leak-scan/SKILL.md +109 -0
  36. package/skills/security-audit/threat-model-quickdraw/SKILL.md +107 -0
@@ -0,0 +1,69 @@
1
+ export interface PeekabooFrame {
2
+ x: number;
3
+ y: number;
4
+ width: number;
5
+ height: number;
6
+ }
7
+ export interface PeekabooElement {
8
+ /** Element handle, e.g. "B1" (button), "T1" (text field). */
9
+ id: string;
10
+ role: string;
11
+ label?: string;
12
+ frame: PeekabooFrame;
13
+ /** Whether the element accepts a value (text fields, sliders, etc.). */
14
+ settable?: boolean;
15
+ /** Action names the element advertises via the AX API. */
16
+ named_actions?: string[];
17
+ }
18
+ export interface PeekabooSeeResult {
19
+ /** Snapshot id used by subsequent `--snapshot $id` arguments. */
20
+ snapshot: string;
21
+ app?: string;
22
+ window?: string;
23
+ elements: PeekabooElement[];
24
+ /** Optional path on disk where the screenshot was written. */
25
+ screenshot_path?: string;
26
+ }
27
+ export interface PeekabooClickResult {
28
+ ok: boolean;
29
+ target?: string;
30
+ coords?: [number, number];
31
+ }
32
+ export interface PeekabooTypeResult {
33
+ ok: boolean;
34
+ typed: string;
35
+ cleared?: boolean;
36
+ }
37
+ export interface PeekabooSetValueResult {
38
+ ok: boolean;
39
+ target: string;
40
+ value: string;
41
+ }
42
+ export interface PeekabooPerformActionResult {
43
+ ok: boolean;
44
+ target: string;
45
+ action: string;
46
+ }
47
+ export interface PeekabooAgentResult {
48
+ ok: boolean;
49
+ output: string;
50
+ }
51
+ /**
52
+ * Structured error returned by all command helpers when the binary exits
53
+ * non-zero or emits malformed JSON. Helpers return `{ ok: false, error }`
54
+ * rather than throw so callers can route via discriminated unions.
55
+ */
56
+ export interface PeekabooError {
57
+ ok: false;
58
+ error: {
59
+ code: 'non-zero-exit' | 'malformed-json' | 'binary-missing' | 'unknown';
60
+ message: string;
61
+ stderr?: string;
62
+ stdout?: string;
63
+ exitCode?: number;
64
+ };
65
+ }
66
+ export type PeekabooOutcome<T> = ({
67
+ ok: true;
68
+ } & T) | PeekabooError;
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,8 @@
1
+ // Peekaboo CLI surface — minimal type model.
2
+ //
3
+ // Mirrors the JSON shape emitted by the `peekaboo` macOS CLI
4
+ // (https://github.com/openclaw/Peekaboo) without taking a runtime
5
+ // dependency. kbot stays binary-agnostic; this adapter only ever
6
+ // speaks JSON across the process boundary.
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
package/dist/cli.js CHANGED
@@ -56,6 +56,7 @@ async function main() {
56
56
  .option('--lite', 'Lightweight mode — skip heavy tools (auto-enabled on Replit)')
57
57
  .option('--safe', 'Confirm destructive operations')
58
58
  .option('--strict', 'Confirm ALL operations')
59
+ .option('--persona <id>', 'Scope tool access to a persona (researcher, coder, computer-use)')
59
60
  .option('--ollama-launch', 'Auto-configure for ollama launch (sets Ollama as provider)')
60
61
  .argument('[prompt...]', 'One-shot prompt')
61
62
  .helpOption('-h, --help', 'display help for command')
@@ -4369,7 +4370,7 @@ async function main() {
4369
4370
  }
4370
4371
  // Permission mode: autonomous by default, users opt-in to confirmations
4371
4372
  {
4372
- const { setPermissionMode } = await import('./permissions.js');
4373
+ const { setPermissionMode, setActivePersona } = await import('./permissions.js');
4373
4374
  if (opts.yes) {
4374
4375
  // --yes / -y: skip all confirmations (for scripts & CI)
4375
4376
  setPermissionMode('permissive');
@@ -4384,6 +4385,19 @@ async function main() {
4384
4385
  // DEFAULT: permissive — kbot acts autonomously, no confirmation prompts
4385
4386
  setPermissionMode('permissive');
4386
4387
  }
4388
+ // Persona scoping (v4.2.0). Optional. Falls back to env var.
4389
+ const personaId = opts.persona || process.env.KBOT_PERSONA || null;
4390
+ if (personaId) {
4391
+ try {
4392
+ setActivePersona(personaId);
4393
+ if (!opts.quiet && !opts.pipe)
4394
+ printInfo(`Persona: ${personaId}`);
4395
+ }
4396
+ catch (err) {
4397
+ printError(err.message);
4398
+ process.exit(1);
4399
+ }
4400
+ }
4387
4401
  }
4388
4402
  // Register built-in agents (hacker, operator, dreamer) so --agent flag works
4389
4403
  registerBuiltinAgents();
@@ -1,4 +1,21 @@
1
+ import { type Persona } from './futures/persona/index.js';
1
2
  export type PermissionMode = 'permissive' | 'normal' | 'strict';
3
+ /**
4
+ * Set (or clear) the active persona by id. Pass null to disable persona checking.
5
+ * Throws if id is not found in PERSONA_REGISTRY.
6
+ *
7
+ * v4.2.0 wires the futures/persona substrate into the live permissions chain.
8
+ * When a persona is set, every checkPermission() call runs canInvoke() FIRST;
9
+ * if the persona denies, the tool is blocked before the destructive-op prompt.
10
+ */
11
+ export declare function setActivePersona(id: string | null): void;
12
+ /** Get the currently active persona, or null if none. */
13
+ export declare function getActivePersona(): Persona | null;
14
+ /**
15
+ * Check the active persona (if any) against a tool invocation.
16
+ * Returns the denial reason string if denied, or null if allowed (or no persona set).
17
+ */
18
+ export declare function checkPersonaScope(toolName: string, args: Record<string, unknown>): string | null;
2
19
  /** Set the permission mode */
3
20
  export declare function setPermissionMode(mode: PermissionMode): void;
4
21
  /** Get the current permission mode */
@@ -13,7 +13,46 @@
13
13
  // 'strict' — confirm all file writes and tool calls
14
14
  import { createInterface } from 'node:readline';
15
15
  import chalk from 'chalk';
16
+ import { canInvoke, PERSONA_REGISTRY, } from './futures/persona/index.js';
16
17
  let currentMode = 'normal';
18
+ /** Active persona for this CLI run. null = no persona-scoping (default). */
19
+ let activePersona = null;
20
+ /**
21
+ * Set (or clear) the active persona by id. Pass null to disable persona checking.
22
+ * Throws if id is not found in PERSONA_REGISTRY.
23
+ *
24
+ * v4.2.0 wires the futures/persona substrate into the live permissions chain.
25
+ * When a persona is set, every checkPermission() call runs canInvoke() FIRST;
26
+ * if the persona denies, the tool is blocked before the destructive-op prompt.
27
+ */
28
+ export function setActivePersona(id) {
29
+ if (id === null) {
30
+ activePersona = null;
31
+ return;
32
+ }
33
+ const persona = PERSONA_REGISTRY[id];
34
+ if (!persona) {
35
+ const known = Object.keys(PERSONA_REGISTRY).join(', ');
36
+ throw new Error(`unknown persona "${id}". Known personas: ${known}`);
37
+ }
38
+ activePersona = persona;
39
+ }
40
+ /** Get the currently active persona, or null if none. */
41
+ export function getActivePersona() {
42
+ return activePersona;
43
+ }
44
+ /**
45
+ * Check the active persona (if any) against a tool invocation.
46
+ * Returns the denial reason string if denied, or null if allowed (or no persona set).
47
+ */
48
+ export function checkPersonaScope(toolName, args) {
49
+ if (!activePersona)
50
+ return null;
51
+ const verdict = canInvoke(activePersona, toolName, args);
52
+ if (verdict.allowed)
53
+ return null;
54
+ return `Persona '${activePersona.id}' denies '${toolName}': ${verdict.reason ?? 'permission denied'}`;
55
+ }
17
56
  /** Patterns that always require confirmation in normal mode */
18
57
  const DESTRUCTIVE_PATTERNS = [
19
58
  { pattern: /^git\s+push/i, reason: 'Pushes code to remote — visible to others' },
@@ -119,6 +158,15 @@ export async function confirmToolCall(toolName, args, reason) {
119
158
  * Used as middleware in the tool execution pipeline.
120
159
  */
121
160
  export async function checkPermission(toolName, args) {
161
+ // Persona check fires BEFORE the destructive-op prompt. If a persona is
162
+ // set and denies the tool, fail fast — no confirmation prompt, no retry.
163
+ const personaDenial = checkPersonaScope(toolName, args);
164
+ if (personaDenial) {
165
+ console.log();
166
+ console.log(` ${chalk.red('✗')} ${personaDenial}`);
167
+ console.log();
168
+ return false;
169
+ }
122
170
  const reason = needsConfirmation(toolName, args);
123
171
  if (!reason)
124
172
  return true;
@@ -11,6 +11,7 @@
11
11
  // pipeline.use(metricsMiddleware(recordMetrics))
12
12
  // pipeline.use(executionMiddleware(executeTool))
13
13
  // await pipeline.execute(ctx)
14
+ import { checkPersonaScope } from './permissions.js';
14
15
  export class ToolPipeline {
15
16
  middleware = [];
16
17
  /** Append middleware to the end of the pipeline */
@@ -56,6 +57,16 @@ export class ToolPipeline {
56
57
  */
57
58
  export function permissionMiddleware(checkPermission) {
58
59
  return async (ctx, next) => {
60
+ // v4.2.0: persona scope check fires BEFORE the destructive-op
61
+ // confirmation. A persona denial blocks the tool with a clear reason
62
+ // and is non-interactive — no prompt, no retry.
63
+ const personaDenial = checkPersonaScope(ctx.toolName, ctx.toolArgs);
64
+ if (personaDenial) {
65
+ ctx.aborted = true;
66
+ ctx.abortReason = personaDenial;
67
+ ctx.error = personaDenial;
68
+ return;
69
+ }
59
70
  const allowed = await checkPermission(ctx.toolName, ctx.toolArgs);
60
71
  if (!allowed) {
61
72
  ctx.aborted = true;
@@ -17,7 +17,19 @@ import { join } from 'node:path';
17
17
  import { readFileSync, unlinkSync, existsSync, mkdirSync, rmSync } from 'node:fs';
18
18
  import { registerTool } from './index.js';
19
19
  import { Coordinator } from '../computer-use-coordinator.js';
20
+ import { peekabooAvailable, see as peekabooSee, click as peekabooClick, type_ as peekabooType, } from '../adapters/peekaboo/index.js';
20
21
  const platform = process.platform;
22
+ // ── Peekaboo AX-first fallback ───────────────────────────────────
23
+ // When the peekaboo CLI is installed, try AX-aware automation before
24
+ // synthetic input. Cached at module-load, refreshed if env hint changes.
25
+ let _peekabooReady = null;
26
+ function peekabooReady() {
27
+ if (process.env.KBOT_DISABLE_PEEKABOO === '1')
28
+ return Promise.resolve(false);
29
+ if (!_peekabooReady)
30
+ _peekabooReady = peekabooAvailable().catch(() => false);
31
+ return _peekabooReady;
32
+ }
21
33
  const LOCK_DIR = join(homedir(), '.kbot');
22
34
  // Legacy single-session lock path. Retained as a constant for back-compat
23
35
  // with any callers that referenced it; the actual locking is now performed
@@ -485,6 +497,27 @@ export function registerComputerTools() {
485
497
  return 'Error: x and y must be numbers';
486
498
  }
487
499
  try {
500
+ // AX-first fallback: when peekaboo is on PATH, try AX-aware click
501
+ // before synthetic input. Falls through to AppleScript+cliclick on
502
+ // any failure so existing behavior is preserved.
503
+ if (platform === 'darwin' && app && await peekabooReady()) {
504
+ try {
505
+ const snap = await peekabooSee({ app });
506
+ if (snap.ok) {
507
+ const target = (args.element_id ?? args.label ?? null);
508
+ if (target) {
509
+ const result = await peekabooClick({
510
+ snapshot: snap.snapshot,
511
+ on: String(target),
512
+ });
513
+ if (result.ok)
514
+ return `clicked via AX: ${target}`;
515
+ // fall through to synthetic on AX failure
516
+ }
517
+ }
518
+ }
519
+ catch { /* fall through */ }
520
+ }
488
521
  if (platform === 'darwin') {
489
522
  try {
490
523
  if (button === 'double') {
@@ -712,6 +745,21 @@ export function registerComputerTools() {
712
745
  const text = String(args.text);
713
746
  if (!text)
714
747
  return 'Error: text is required';
748
+ // AX-first fallback: when peekaboo is on PATH, try AX-aware typing
749
+ // before synthetic keystrokes. Falls through to AppleScript on any
750
+ // failure so existing behavior is preserved.
751
+ if (platform === 'darwin' && await peekabooReady()) {
752
+ try {
753
+ const clear = args.clear === true;
754
+ const delayMs = typeof args.delayMs === 'number' ? args.delayMs : undefined;
755
+ const result = await peekabooType({ text, clear, delayMs });
756
+ if (result.ok) {
757
+ return `Typed via AX: ${text.slice(0, 80)}${text.length > 80 ? '...' : ''}`;
758
+ }
759
+ // fall through to synthetic on AX failure
760
+ }
761
+ catch { /* fall through */ }
762
+ }
715
763
  if (platform === 'darwin') {
716
764
  const escaped = escapeAppleScript(text);
717
765
  try {
@@ -1104,5 +1152,21 @@ export function registerComputerTools() {
1104
1152
  return `Computer use session ended.${releasedNote}`;
1105
1153
  },
1106
1154
  });
1155
+ // ── Peekaboo status (AX-first diagnostics) ──
1156
+ registerTool({
1157
+ name: 'peekaboo_status',
1158
+ description: 'Report whether the AX-first peekaboo CLI is available on PATH for accessibility-aware automation.',
1159
+ parameters: {},
1160
+ tier: 'free',
1161
+ async execute() {
1162
+ if (process.env.KBOT_DISABLE_PEEKABOO === '1') {
1163
+ return 'AX-first unavailable (disabled via KBOT_DISABLE_PEEKABOO=1)';
1164
+ }
1165
+ const ready = await peekabooReady();
1166
+ return ready
1167
+ ? 'AX-first available via peekaboo'
1168
+ : 'AX-first unavailable (peekaboo CLI not on PATH)';
1169
+ },
1170
+ });
1107
1171
  }
1108
1172
  //# sourceMappingURL=computer.js.map
@@ -0,0 +1,4 @@
1
+ import { type ToolDefinition } from './index.js';
2
+ export declare const peekabooTools: readonly ToolDefinition[];
3
+ export declare function registerPeekabooTools(): void;
4
+ //# sourceMappingURL=peekaboo.d.ts.map