@scotthuang/agent-knock-knock 0.1.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.
@@ -0,0 +1,149 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ const DEFAULT_RETENTION_DAYS = 14;
5
+ const LOG_LEVELS = {
6
+ debug: 10,
7
+ info: 20,
8
+ warn: 30,
9
+ error: 40,
10
+ silent: Number.POSITIVE_INFINITY
11
+ };
12
+ const SENSITIVE_KEY_PATTERN = /(authorization|api[_-]?key|token|secret|password|passwd|gatewayToken|proxy|allProxy)/i;
13
+ const cleanupPerformed = new Set();
14
+ export function defaultRuntimeLogDir() {
15
+ return path.join(os.homedir(), ".agent-knock-knock", "logs");
16
+ }
17
+ export function localDateStamp(date = new Date()) {
18
+ return [
19
+ date.getFullYear(),
20
+ pad(date.getMonth() + 1),
21
+ pad(date.getDate())
22
+ ].join("-");
23
+ }
24
+ export function localTimestamp(date = new Date()) {
25
+ return `${localDateStamp(date)}T${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}${timezoneOffset(date)}`;
26
+ }
27
+ export function runtimeLogPath({ now = new Date(), logDir = defaultRuntimeLogDir() } = {}) {
28
+ return path.join(expandHome(logDir), `runtime-${localDateStamp(now)}.ndjson`);
29
+ }
30
+ export function writeRuntimeLog(record, options = {}) {
31
+ const level = normalizeLevel(record.level ?? "info");
32
+ const configuredLevel = normalizeLevel(options.level ?? process.env.AKK_LOG_LEVEL ?? "info");
33
+ if (!shouldLog(level, configuredLevel)) {
34
+ return { written: false };
35
+ }
36
+ const now = options.now ?? new Date();
37
+ const logDir = expandHome(options.logDir ?? process.env.AKK_LOG_DIR ?? defaultRuntimeLogDir());
38
+ const retentionDays = retentionDaysFromOptions(options);
39
+ maybeCleanupRuntimeLogs({ logDir, retentionDays, now });
40
+ fs.mkdirSync(logDir, { recursive: true });
41
+ const logPath = runtimeLogPath({ now, logDir });
42
+ const entry = redactRecord({
43
+ ts: localTimestamp(now),
44
+ ts_utc: now.toISOString(),
45
+ level,
46
+ ...record
47
+ });
48
+ fs.appendFileSync(logPath, `${JSON.stringify(entry)}\n`, "utf8");
49
+ return { written: true, path: logPath, entry };
50
+ }
51
+ export function cleanupRuntimeLogs({ logDir = defaultRuntimeLogDir(), retentionDays = DEFAULT_RETENTION_DAYS, now = new Date() } = {}) {
52
+ const expandedLogDir = expandHome(logDir);
53
+ const retention = Number(retentionDays);
54
+ if (!Number.isFinite(retention) || retention <= 0 || !fs.existsSync(expandedLogDir)) {
55
+ return { checked: 0, deleted: 0, retention_days: retention };
56
+ }
57
+ const cutoffMs = startOfLocalDay(now).getTime() - (retention * 24 * 60 * 60 * 1000);
58
+ let checked = 0;
59
+ let deleted = 0;
60
+ for (const entry of fs.readdirSync(expandedLogDir, { withFileTypes: true })) {
61
+ if (!entry.isFile()) {
62
+ continue;
63
+ }
64
+ const match = /^runtime-(\d{4})-(\d{2})-(\d{2})\.ndjson$/.exec(entry.name);
65
+ if (!match) {
66
+ continue;
67
+ }
68
+ checked += 1;
69
+ const fileDay = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
70
+ if (fileDay.getTime() < cutoffMs) {
71
+ fs.rmSync(path.join(expandedLogDir, entry.name), { force: true });
72
+ deleted += 1;
73
+ }
74
+ }
75
+ return { checked, deleted, retention_days: retention };
76
+ }
77
+ export function redactRecord(value) {
78
+ if (Array.isArray(value)) {
79
+ return value.map((item) => redactRecord(item));
80
+ }
81
+ if (value && typeof value === "object") {
82
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => {
83
+ if (SENSITIVE_KEY_PATTERN.test(key)) {
84
+ return [key, "[REDACTED]"];
85
+ }
86
+ return [key, redactRecord(item)];
87
+ }));
88
+ }
89
+ if (typeof value === "string") {
90
+ return redactString(value);
91
+ }
92
+ return value;
93
+ }
94
+ export function redactString(value) {
95
+ return String(value)
96
+ .replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [REDACTED]")
97
+ .replace(/(--(?:gateway-)?token(?:=|\s+))("[^"]+"|'[^']+'|\S+)/gi, "$1[REDACTED]")
98
+ .replace(/\bsk-[A-Za-z0-9_-]{12,}\b/g, "sk-[REDACTED]")
99
+ .replace(/\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g, "gh[REDACTED]")
100
+ .replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "github_pat_[REDACTED]")
101
+ .replace(/\bAKIA[0-9A-Z]{16}\b/g, "AKIA[REDACTED]")
102
+ .replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED PRIVATE KEY]")
103
+ .replace(/\b([a-z][a-z0-9+.-]*:\/\/)([^/\s:@]+):([^@\s/]+)@/gi, "$1[REDACTED]@");
104
+ }
105
+ function maybeCleanupRuntimeLogs({ logDir, retentionDays, now }) {
106
+ const key = `${path.resolve(logDir)}:${retentionDays}`;
107
+ if (cleanupPerformed.has(key)) {
108
+ return;
109
+ }
110
+ cleanupPerformed.add(key);
111
+ cleanupRuntimeLogs({ logDir, retentionDays, now });
112
+ }
113
+ function retentionDaysFromOptions(options) {
114
+ if (options.retentionDays !== undefined) {
115
+ return Number(options.retentionDays);
116
+ }
117
+ if (process.env.AKK_LOG_RETENTION_DAYS !== undefined) {
118
+ return Number(process.env.AKK_LOG_RETENTION_DAYS);
119
+ }
120
+ return DEFAULT_RETENTION_DAYS;
121
+ }
122
+ function normalizeLevel(level) {
123
+ return typeof level === "string" && Object.hasOwn(LOG_LEVELS, level) ? level : "info";
124
+ }
125
+ function shouldLog(level, configuredLevel) {
126
+ return LOG_LEVELS[level] >= LOG_LEVELS[configuredLevel];
127
+ }
128
+ function startOfLocalDay(date) {
129
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
130
+ }
131
+ function timezoneOffset(date) {
132
+ const offsetMinutes = -date.getTimezoneOffset();
133
+ const sign = offsetMinutes >= 0 ? "+" : "-";
134
+ const absolute = Math.abs(offsetMinutes);
135
+ return `${sign}${pad(Math.floor(absolute / 60))}:${pad(absolute % 60)}`;
136
+ }
137
+ function pad(value, size = 2) {
138
+ return String(value).padStart(size, "0");
139
+ }
140
+ function expandHome(filePath) {
141
+ if (filePath === "~") {
142
+ return os.homedir();
143
+ }
144
+ if (filePath?.startsWith("~/")) {
145
+ return path.join(os.homedir(), filePath.slice(2));
146
+ }
147
+ return filePath;
148
+ }
149
+ //# sourceMappingURL=runtime-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-log.js","sourceRoot":"","sources":["../../src/runtime-log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { AgentMessage, Conversation } from "./protocol.js";
2
+ export declare function defaultStoreDir(_workspace?: string): string;
3
+ export declare function defaultLogDir(workspace?: string): string;
4
+ export declare function ensureDir(dir: string): void;
5
+ export interface ConversationPaths {
6
+ storeDir: string;
7
+ logDir: string;
8
+ conversationDir: string;
9
+ logPath: string;
10
+ statePath: string;
11
+ }
12
+ export interface EventRecord {
13
+ event: string;
14
+ [key: string]: unknown;
15
+ }
16
+ export declare function pathsForConversation(conversationId: string, storeDir?: string): ConversationPaths;
17
+ export declare function pathsForConversationDir(conversationDir: string): ConversationPaths;
18
+ export declare function logPathForStatePath(statePath: string): string;
19
+ export declare function saveState(statePath: string, conversation: Conversation): void;
20
+ export declare function loadState(statePath: string): Conversation;
21
+ export declare function statePathForConversationId(conversationId: string, storeDir?: string): string;
22
+ export declare function loadConversationById(conversationId: string, storeDir?: string): Conversation;
23
+ export declare function listConversations(storeDir?: string): Conversation[];
24
+ export declare function appendEvent(logPath: string, event: EventRecord): void;
25
+ export declare function assertAppendableEventLog(logPath: string): true;
26
+ export declare function messageEvent(message: AgentMessage): EventRecord;
27
+ export declare function rawExchangeEvent({ conversationId, from, to, prompt, response, round, type }: {
28
+ conversationId: string;
29
+ from: string;
30
+ to: string;
31
+ prompt: string;
32
+ response: string;
33
+ round: number;
34
+ type?: string;
35
+ }): EventRecord;
@@ -0,0 +1,121 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ export function defaultStoreDir(_workspace = process.cwd()) {
5
+ return path.join(os.homedir(), ".agent-knock-knock", "conversations");
6
+ }
7
+ export function defaultLogDir(workspace = process.cwd()) {
8
+ return defaultStoreDir(workspace);
9
+ }
10
+ export function ensureDir(dir) {
11
+ fs.mkdirSync(dir, { recursive: true });
12
+ }
13
+ export function pathsForConversation(conversationId, storeDir = defaultStoreDir()) {
14
+ const conversationDir = path.join(storeDir, conversationId);
15
+ return {
16
+ storeDir,
17
+ logDir: storeDir,
18
+ conversationDir,
19
+ logPath: path.join(conversationDir, "events.ndjson"),
20
+ statePath: path.join(conversationDir, "state.json")
21
+ };
22
+ }
23
+ export function pathsForConversationDir(conversationDir) {
24
+ return {
25
+ storeDir: path.dirname(conversationDir),
26
+ logDir: path.dirname(conversationDir),
27
+ conversationDir,
28
+ logPath: path.join(conversationDir, "events.ndjson"),
29
+ statePath: path.join(conversationDir, "state.json")
30
+ };
31
+ }
32
+ export function logPathForStatePath(statePath) {
33
+ if (path.basename(statePath) === "state.json") {
34
+ return path.join(path.dirname(statePath), "events.ndjson");
35
+ }
36
+ return statePath.replace(/\.state\.json$/, ".ndjson");
37
+ }
38
+ export function saveState(statePath, conversation) {
39
+ ensureDir(path.dirname(statePath));
40
+ fs.writeFileSync(statePath, `${JSON.stringify(conversation, null, 2)}\n`, "utf8");
41
+ }
42
+ export function loadState(statePath) {
43
+ return JSON.parse(fs.readFileSync(statePath, "utf8"));
44
+ }
45
+ export function statePathForConversationId(conversationId, storeDir = defaultStoreDir()) {
46
+ return path.join(storeDir, conversationId, "state.json");
47
+ }
48
+ export function loadConversationById(conversationId, storeDir = defaultStoreDir()) {
49
+ return loadState(statePathForConversationId(conversationId, storeDir));
50
+ }
51
+ export function listConversations(storeDir = defaultStoreDir()) {
52
+ if (!fs.existsSync(storeDir)) {
53
+ return [];
54
+ }
55
+ return fs.readdirSync(storeDir, { withFileTypes: true })
56
+ .filter((entry) => entry.isDirectory())
57
+ .map((entry) => path.join(storeDir, entry.name, "state.json"))
58
+ .filter((statePath) => fs.existsSync(statePath))
59
+ .map((statePath) => {
60
+ const conversation = loadState(statePath);
61
+ return {
62
+ ...conversation,
63
+ state_path: conversation.state_path ?? statePath,
64
+ event_log_path: conversation.event_log_path ?? logPathForStatePath(statePath),
65
+ conversation_dir: conversation.conversation_dir ?? path.dirname(statePath)
66
+ };
67
+ })
68
+ .sort((left, right) => String(right.updated_at ?? "").localeCompare(String(left.updated_at ?? "")));
69
+ }
70
+ export function appendEvent(logPath, event) {
71
+ ensureDir(path.dirname(logPath));
72
+ assertAppendableEventLog(logPath);
73
+ fs.appendFileSync(logPath, `${JSON.stringify(event)}\n`, "utf8");
74
+ }
75
+ export function assertAppendableEventLog(logPath) {
76
+ if (!fs.existsSync(logPath)) {
77
+ return true;
78
+ }
79
+ const text = fs.readFileSync(logPath, "utf8");
80
+ const lines = text.split(/\r?\n/).filter((line) => line.trim().length > 0);
81
+ for (const [index, line] of lines.entries()) {
82
+ let parsed;
83
+ try {
84
+ parsed = JSON.parse(line);
85
+ }
86
+ catch (error) {
87
+ throw new Error(`event log is not valid NDJSON at line ${index + 1}: ${error instanceof Error ? error.message : String(error)}`);
88
+ }
89
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || typeof parsed.event !== "string") {
90
+ throw new Error(`event log line ${index + 1} is not an event object`);
91
+ }
92
+ }
93
+ return true;
94
+ }
95
+ export function messageEvent(message) {
96
+ return {
97
+ ts: message.ts,
98
+ conversation_id: message.conversation_id,
99
+ event: "message",
100
+ from: message.from,
101
+ to: message.to,
102
+ type: message.type,
103
+ requires_response: message.requires_response,
104
+ round: message.round,
105
+ body: message.body,
106
+ message
107
+ };
108
+ }
109
+ export function rawExchangeEvent({ conversationId, from, to, prompt, response, round, type = "raw_exchange" }) {
110
+ return {
111
+ ts: new Date().toISOString(),
112
+ conversation_id: conversationId,
113
+ event: type,
114
+ from,
115
+ to,
116
+ round,
117
+ prompt,
118
+ response
119
+ };
120
+ }
121
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface TranscriptEvent {
2
+ event?: string;
3
+ conversation?: Record<string, unknown>;
4
+ conversation_id?: string;
5
+ from?: string;
6
+ to?: string;
7
+ type?: string;
8
+ round?: number;
9
+ requires_response?: boolean;
10
+ body?: string;
11
+ status?: string;
12
+ response_rounds_used?: number;
13
+ manager_final?: string;
14
+ response?: string;
15
+ tool_name?: string;
16
+ permission?: string;
17
+ source?: string;
18
+ [key: string]: unknown;
19
+ }
20
+ export declare function readNdjsonLog(logPath: string): TranscriptEvent[];
21
+ export declare function parseNdjson(text: string): TranscriptEvent[];
22
+ export declare function formatTranscript(events: TranscriptEvent[], { includeRaw }?: {
23
+ includeRaw?: boolean;
24
+ }): string;
@@ -0,0 +1,88 @@
1
+ import fs from "node:fs";
2
+ export function readNdjsonLog(logPath) {
3
+ const text = fs.readFileSync(logPath, "utf8");
4
+ return parseNdjson(text);
5
+ }
6
+ export function parseNdjson(text) {
7
+ return text
8
+ .split(/\r?\n/)
9
+ .map((line) => line.trim())
10
+ .filter(Boolean)
11
+ .map((line, index) => {
12
+ try {
13
+ return JSON.parse(line);
14
+ }
15
+ catch (error) {
16
+ throw new Error(`invalid NDJSON at line ${index + 1}: ${error instanceof Error ? error.message : String(error)}`);
17
+ }
18
+ });
19
+ }
20
+ export function formatTranscript(events, { includeRaw = false } = {}) {
21
+ const lines = [];
22
+ for (const event of events) {
23
+ if (event.event === "conversation_created") {
24
+ lines.push(formatConversationCreated(event));
25
+ }
26
+ else if (event.event === "message" && event.source !== "normalized_acpx") {
27
+ lines.push(formatMessage(event));
28
+ }
29
+ else if (event.event === "conversation_closed") {
30
+ lines.push(formatConversationClosed(event));
31
+ }
32
+ else if (includeRaw && isDebugEvent(event)) {
33
+ lines.push(formatRawEvent(event));
34
+ }
35
+ }
36
+ return `${lines.filter(Boolean).join("\n\n")}\n`;
37
+ }
38
+ function formatConversationCreated(event) {
39
+ const conversation = event.conversation;
40
+ const id = event.conversation_id ?? conversation?.conversation_id ?? "unknown";
41
+ const status = typeof conversation?.status === "string" ? ` status=${conversation.status}` : "";
42
+ const request = typeof conversation?.user_request === "string" ? `\nRequest: ${conversation.user_request}` : "";
43
+ return `[conversation_created] ${id}${status}${request}`;
44
+ }
45
+ function formatMessage(event) {
46
+ const label = `${event.from} -> ${event.to}`;
47
+ const flags = [
48
+ `type=${event.type}`,
49
+ `round=${event.round}`,
50
+ `requires_response=${event.requires_response}`
51
+ ].join(" ");
52
+ return `[message] ${label} ${flags}\n${indent(event.body)}`;
53
+ }
54
+ function formatConversationClosed(event) {
55
+ const parts = [
56
+ `status=${event.status ?? "unknown"}`,
57
+ `rounds=${event.response_rounds_used ?? "unknown"}`
58
+ ];
59
+ const final = event.manager_final ? `\n${indent(event.manager_final)}` : "";
60
+ return `[conversation_closed] ${parts.join(" ")}${final}`;
61
+ }
62
+ function formatRawEvent(event) {
63
+ const label = `${event.from ?? "unknown"} -> ${event.to ?? "unknown"}`;
64
+ const details = [
65
+ event.type ? `type=${event.type}` : null,
66
+ event.status ? `status=${event.status}` : null,
67
+ event.tool_name ? `tool=${event.tool_name}` : null,
68
+ event.permission ? `permission=${event.permission}` : null
69
+ ].filter(Boolean);
70
+ const suffix = details.length > 0 ? ` ${details.join(" ")}` : "";
71
+ const body = event.response ?? event.body;
72
+ const formattedBody = body ? `\n${indent(body)}` : "";
73
+ return `[${event.event}] ${label} round=${event.round ?? "unknown"}${suffix}${formattedBody}`;
74
+ }
75
+ function isDebugEvent(event) {
76
+ return event.event === "raw_exchange" ||
77
+ event.event?.startsWith("developer_step_") ||
78
+ event.event?.startsWith("manager_step_") ||
79
+ event.event === "manager_final" ||
80
+ event.source === "normalized_acpx";
81
+ }
82
+ function indent(value) {
83
+ return String(value)
84
+ .split(/\r?\n/)
85
+ .map((line) => ` ${line}`)
86
+ .join("\n");
87
+ }
88
+ //# sourceMappingURL=transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../src/transcript.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,150 @@
1
+ {
2
+ "id": "agent-knock-knock",
3
+ "name": "Agent Knock Knock",
4
+ "description": "Agent Knock Knock (AKK/akk) delegates OpenClaw coding work to local Codex, Claude, or Cursor agents. Use this plugin when the user says AKK, akk, Agent Knock Knock, asks to hand work to Codex, Claude, or Cursor, asks what agent tasks are running, sends a follow-up to an agent task, recovers or restarts an unavailable agent session, cancels a running agent task, or closes an agent task. Default delegation target comes from plugin config defaultAgent and falls back to Codex when unset; explicit user agent requests override it.",
5
+ "activation": {
6
+ "onStartup": true
7
+ },
8
+ "contracts": {
9
+ "commands": [
10
+ "akk"
11
+ ],
12
+ "tools": [
13
+ "agent_knock_knock_delegate",
14
+ "agent_knock_knock_list",
15
+ "agent_knock_knock_status",
16
+ "agent_knock_knock_send",
17
+ "agent_knock_knock_cancel",
18
+ "agent_knock_knock_recover",
19
+ "agent_knock_knock_restart",
20
+ "agent_knock_knock_close"
21
+ ]
22
+ },
23
+ "toolMetadata": {
24
+ "agent_knock_knock_delegate": {
25
+ "optional": true
26
+ },
27
+ "agent_knock_knock_list": {
28
+ "optional": true
29
+ },
30
+ "agent_knock_knock_status": {
31
+ "optional": true
32
+ },
33
+ "agent_knock_knock_send": {
34
+ "optional": true
35
+ },
36
+ "agent_knock_knock_cancel": {
37
+ "optional": true
38
+ },
39
+ "agent_knock_knock_recover": {
40
+ "optional": true
41
+ },
42
+ "agent_knock_knock_restart": {
43
+ "optional": true
44
+ },
45
+ "agent_knock_knock_close": {
46
+ "optional": true
47
+ }
48
+ },
49
+ "configSchema": {
50
+ "type": "object",
51
+ "additionalProperties": false,
52
+ "properties": {
53
+ "binPath": {
54
+ "type": "string",
55
+ "description": "Path to agent-knock-knock CLI. Defaults to this package's dist/src/cli.js build output."
56
+ },
57
+ "workspace": {
58
+ "type": "string",
59
+ "description": "Default workspace for delegated coding-agent tasks."
60
+ },
61
+ "storeDir": {
62
+ "type": "string",
63
+ "description": "Default conversation store directory."
64
+ },
65
+ "claudeSession": {
66
+ "type": "string",
67
+ "description": "Default Claude Code session name."
68
+ },
69
+ "codexSession": {
70
+ "type": "string",
71
+ "description": "Default Codex session name."
72
+ },
73
+ "cursorSession": {
74
+ "type": "string",
75
+ "description": "Default Cursor session name."
76
+ },
77
+ "defaultAgent": {
78
+ "type": "string",
79
+ "enum": ["claude", "codex", "cursor"],
80
+ "description": "Default coding agent for unspecified AKK delegations. If unset, Agent Knock Knock falls back to codex."
81
+ },
82
+ "defaultClaudeSession": {
83
+ "type": "string",
84
+ "description": "Default Claude Code session name. claudeSession remains supported as a compatibility alias."
85
+ },
86
+ "defaultCodexSession": {
87
+ "type": "string",
88
+ "description": "Default Codex session name."
89
+ },
90
+ "defaultCursorSession": {
91
+ "type": "string",
92
+ "description": "Default Cursor session name."
93
+ },
94
+ "codexAllProxy": {
95
+ "type": "string",
96
+ "description": "ALL_PROXY value used when launching Codex through ACPX."
97
+ },
98
+ "cursorAllProxy": {
99
+ "type": "string",
100
+ "description": "ALL_PROXY value used when launching Cursor through ACPX."
101
+ },
102
+ "codexModel": {
103
+ "type": "string",
104
+ "description": "ACPX model id used when launching Codex."
105
+ },
106
+ "cursorModel": {
107
+ "type": "string",
108
+ "description": "ACPX model id used when launching Cursor."
109
+ },
110
+ "model": {
111
+ "type": "string",
112
+ "description": "ACPX model id used when launching coding agents."
113
+ },
114
+ "allProxy": {
115
+ "type": "string",
116
+ "description": "ALL_PROXY value used when launching coding agents through ACPX."
117
+ },
118
+ "openclawSession": {
119
+ "type": "string",
120
+ "description": "Default OpenClaw session label stored in the protocol state."
121
+ },
122
+ "gatewayUrl": {
123
+ "type": "string",
124
+ "description": "Gateway URL used by the legacy CLI callback delivery path."
125
+ },
126
+ "gatewayToken": {
127
+ "type": "string",
128
+ "description": "Gateway token used by the legacy CLI callback delivery path."
129
+ },
130
+ "openclawBin": {
131
+ "type": "string",
132
+ "description": "Path to the OpenClaw CLI used by callback delivery. Defaults to PATH plus common user install locations."
133
+ },
134
+ "callbackCommand": {
135
+ "type": "string",
136
+ "description": "Optional callback command template. {statePath} and {state_path} are replaced with the shell-quoted state path."
137
+ },
138
+ "idleTimeoutMinutes": {
139
+ "type": "number",
140
+ "description": "Minutes an idle AKK session remains open before lazy cleanup closes it. Defaults to 10080."
141
+ },
142
+ "softLimit": {
143
+ "type": "number"
144
+ },
145
+ "hardLimit": {
146
+ "type": "number"
147
+ }
148
+ }
149
+ }
150
+ }
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@scotthuang/agent-knock-knock",
3
+ "version": "0.1.0",
4
+ "description": "OpenClaw plugin bridge for delegating work to local coding agents through ACPX.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "homepage": "https://github.com/scotthuang/agent-knock-knock#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/scotthuang/agent-knock-knock.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/scotthuang/agent-knock-knock/issues"
14
+ },
15
+ "keywords": [
16
+ "openclaw",
17
+ "acpx",
18
+ "codex",
19
+ "claude-code",
20
+ "cursor",
21
+ "coding-agent"
22
+ ],
23
+ "openclaw": {
24
+ "extensions": [
25
+ "./dist/src/openclaw-plugin.js"
26
+ ],
27
+ "compat": {
28
+ "pluginApi": ">=2026.3.24-beta.2",
29
+ "minGatewayVersion": "2026.3.24-beta.2"
30
+ }
31
+ },
32
+ "bin": {
33
+ "agent-knock-knock": "dist/src/cli.js"
34
+ },
35
+ "files": [
36
+ "dist/src",
37
+ "templates",
38
+ "openclaw.plugin.json",
39
+ "README.md",
40
+ "LICENSE",
41
+ "CHANGELOG.md"
42
+ ],
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "scripts": {
47
+ "clean": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\"",
48
+ "build": "npm run clean && tsc -p tsconfig.json",
49
+ "prepack": "npm run build",
50
+ "typecheck": "tsc -p tsconfig.json --noEmit",
51
+ "test": "npm run build && node --test dist/test/*.test.js",
52
+ "simulate:architecture": "node scripts/two-claude-weather-test.js --scenario architecture-questions",
53
+ "simulate:weather": "node scripts/two-claude-weather-test.js --scenario weather",
54
+ "transcript": "node dist/src/cli.js transcript"
55
+ },
56
+ "engines": {
57
+ "node": ">=20"
58
+ },
59
+ "devDependencies": {
60
+ "@types/node": "^26.0.0",
61
+ "typescript": "^6.0.3"
62
+ }
63
+ }