neoctl 0.2.5 → 0.2.6

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 (95) hide show
  1. package/README.md +16 -26
  2. package/dist/agents/agent-activity.d.ts +70 -0
  3. package/dist/agents/agent-activity.js +261 -0
  4. package/dist/agents/agent-activity.js.map +1 -0
  5. package/dist/agents/agent-definition.d.ts +7 -0
  6. package/dist/agents/agent-definition.js +44 -1
  7. package/dist/agents/agent-definition.js.map +1 -1
  8. package/dist/agents/agent-report-tool.d.ts +11 -0
  9. package/dist/agents/agent-report-tool.js +50 -0
  10. package/dist/agents/agent-report-tool.js.map +1 -0
  11. package/dist/agents/agent-tool.d.ts +3 -1
  12. package/dist/agents/agent-tool.js +56 -11
  13. package/dist/agents/agent-tool.js.map +1 -1
  14. package/dist/agents/local-agent-task.d.ts +3 -0
  15. package/dist/agents/local-agent-task.js +2 -0
  16. package/dist/agents/local-agent-task.js.map +1 -1
  17. package/dist/agents/smoke-agents.js +131 -7
  18. package/dist/agents/smoke-agents.js.map +1 -1
  19. package/dist/context/prompts.js +4 -0
  20. package/dist/context/prompts.js.map +1 -1
  21. package/dist/core/query-engine.d.ts +3 -1
  22. package/dist/core/query-engine.js +2 -0
  23. package/dist/core/query-engine.js.map +1 -1
  24. package/dist/core/query.d.ts +4 -0
  25. package/dist/core/query.js +10 -1
  26. package/dist/core/query.js.map +1 -1
  27. package/dist/core/run-agent.d.ts +2 -0
  28. package/dist/core/run-agent.js +156 -21
  29. package/dist/core/run-agent.js.map +1 -1
  30. package/dist/core/smoke-core-loop.js +1 -1
  31. package/dist/core/smoke-core-loop.js.map +1 -1
  32. package/dist/index.d.ts +5 -2
  33. package/dist/index.js +5 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/model/anthropic-mapper.js +27 -2
  36. package/dist/model/anthropic-mapper.js.map +1 -1
  37. package/dist/model/config.d.ts +2 -8
  38. package/dist/model/config.js +1 -41
  39. package/dist/model/config.js.map +1 -1
  40. package/dist/model/env.js +6 -11
  41. package/dist/model/env.js.map +1 -1
  42. package/dist/model/model-metadata.json +1 -115
  43. package/dist/model/openai-chat-mapper.js +4 -19
  44. package/dist/model/openai-chat-mapper.js.map +1 -1
  45. package/dist/model/provider-factory.js +0 -32
  46. package/dist/model/provider-factory.js.map +1 -1
  47. package/dist/model/smoke-anthropic-mapper.js +6 -2
  48. package/dist/model/smoke-anthropic-mapper.js.map +1 -1
  49. package/dist/repl/commands.d.ts +8 -0
  50. package/dist/repl/commands.js +35 -1
  51. package/dist/repl/commands.js.map +1 -1
  52. package/dist/repl/index.js +731 -127
  53. package/dist/repl/index.js.map +1 -1
  54. package/dist/secrets/secret-crypto.d.ts +22 -0
  55. package/dist/secrets/secret-crypto.js +58 -0
  56. package/dist/secrets/secret-crypto.js.map +1 -0
  57. package/dist/secrets/secret-redaction.d.ts +8 -0
  58. package/dist/secrets/secret-redaction.js +40 -0
  59. package/dist/secrets/secret-redaction.js.map +1 -0
  60. package/dist/secrets/secret-store.d.ts +28 -0
  61. package/dist/secrets/secret-store.js +158 -0
  62. package/dist/secrets/secret-store.js.map +1 -0
  63. package/dist/secrets/secret-types.d.ts +31 -0
  64. package/dist/secrets/secret-types.js +17 -0
  65. package/dist/secrets/secret-types.js.map +1 -0
  66. package/dist/secrets/smoke-secrets.js +68 -0
  67. package/dist/secrets/smoke-secrets.js.map +1 -0
  68. package/dist/tools/builtins/exec-tool.d.ts +20 -1
  69. package/dist/tools/builtins/exec-tool.js +164 -29
  70. package/dist/tools/builtins/exec-tool.js.map +1 -1
  71. package/dist/tools/builtins/plan-tool.d.ts +1 -0
  72. package/dist/tools/builtins/plan-tool.js +80 -27
  73. package/dist/tools/builtins/plan-tool.js.map +1 -1
  74. package/dist/tools/builtins/secret-tools.d.ts +10 -0
  75. package/dist/tools/builtins/secret-tools.js +75 -0
  76. package/dist/tools/builtins/secret-tools.js.map +1 -0
  77. package/dist/tools/run-tool-use.js +4 -2
  78. package/dist/tools/run-tool-use.js.map +1 -1
  79. package/dist/tools/smoke-tool-system.js +42 -10
  80. package/dist/tools/smoke-tool-system.js.map +1 -1
  81. package/dist/tools/tool.d.ts +3 -0
  82. package/dist/tools/tool.js.map +1 -1
  83. package/dist/web/html.js +1 -1
  84. package/dist/web/index.js +11 -50
  85. package/dist/web/index.js.map +1 -1
  86. package/package.json +2 -2
  87. package/dist/model/deepseek-adapter.d.ts +0 -29
  88. package/dist/model/deepseek-adapter.js +0 -108
  89. package/dist/model/deepseek-adapter.js.map +0 -1
  90. package/dist/model/kimi-adapter.d.ts +0 -29
  91. package/dist/model/kimi-adapter.js +0 -108
  92. package/dist/model/kimi-adapter.js.map +0 -1
  93. package/dist/model/smoke-deepseek-mapper.js +0 -65
  94. package/dist/model/smoke-deepseek-mapper.js.map +0 -1
  95. /package/dist/{model/smoke-deepseek-mapper.d.ts → secrets/smoke-secrets.d.ts} +0 -0
@@ -0,0 +1,22 @@
1
+ export interface SecretKdfConfig {
2
+ type: "scrypt";
3
+ salt: string;
4
+ N: number;
5
+ r: number;
6
+ p: number;
7
+ }
8
+ export interface EncryptedSecretPayload {
9
+ ciphertext: string;
10
+ iv: string;
11
+ tag: string;
12
+ }
13
+ export interface SecretCryptoConfig {
14
+ kdf: SecretKdfConfig;
15
+ passphrase?: string;
16
+ }
17
+ export declare function createDefaultKdf(): SecretKdfConfig;
18
+ export declare function resolveSecretPassphrase(passphrase?: string): string;
19
+ export declare function deriveSecretKey(config: SecretCryptoConfig): Buffer;
20
+ export declare function encryptSecret(plaintext: string, key: Buffer): EncryptedSecretPayload;
21
+ export declare function decryptSecret(payload: EncryptedSecretPayload, key: Buffer): string;
22
+ export declare function fingerprintSecret(value: string): string;
@@ -0,0 +1,58 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync, createHash } from "node:crypto";
2
+ const KEY_LENGTH = 32;
3
+ const IV_LENGTH = 12;
4
+ const DEFAULT_KDF = { type: "scrypt", N: 32768, r: 8, p: 1 };
5
+ export function createDefaultKdf() {
6
+ return { ...DEFAULT_KDF, salt: randomBytes(16).toString("base64") };
7
+ }
8
+ export function resolveSecretPassphrase(passphrase) {
9
+ const explicit = passphrase ?? process.env.NEOCTL_SECRETS_KEY ?? process.env.NEO_SECRETS_KEY;
10
+ if (explicit && explicit.length > 0)
11
+ return explicit;
12
+ // Local fallback keeps storage encrypted-at-rest without interactive prompting. Users who need stronger
13
+ // separation should set NEOCTL_SECRETS_KEY; changing it makes existing secrets undecryptable.
14
+ return `neoctl-local-secret-key:${process.env.USERPROFILE ?? process.env.HOME ?? "unknown"}`;
15
+ }
16
+ export function deriveSecretKey(config) {
17
+ const passphrase = resolveSecretPassphrase(config.passphrase);
18
+ if (/^[A-Za-z0-9+/=]+$/.test(passphrase)) {
19
+ try {
20
+ const decoded = Buffer.from(passphrase, "base64");
21
+ if (decoded.length === KEY_LENGTH)
22
+ return decoded;
23
+ }
24
+ catch {
25
+ // Fall through to scrypt.
26
+ }
27
+ }
28
+ return scryptSync(passphrase, Buffer.from(config.kdf.salt, "base64"), KEY_LENGTH, {
29
+ N: config.kdf.N,
30
+ r: config.kdf.r,
31
+ p: config.kdf.p,
32
+ maxmem: 64 * 1024 * 1024,
33
+ });
34
+ }
35
+ export function encryptSecret(plaintext, key) {
36
+ const iv = randomBytes(IV_LENGTH);
37
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
38
+ const ciphertext = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
39
+ const tag = cipher.getAuthTag();
40
+ return {
41
+ ciphertext: ciphertext.toString("base64"),
42
+ iv: iv.toString("base64"),
43
+ tag: tag.toString("base64"),
44
+ };
45
+ }
46
+ export function decryptSecret(payload, key) {
47
+ const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(payload.iv, "base64"));
48
+ decipher.setAuthTag(Buffer.from(payload.tag, "base64"));
49
+ const plaintext = Buffer.concat([
50
+ decipher.update(Buffer.from(payload.ciphertext, "base64")),
51
+ decipher.final(),
52
+ ]);
53
+ return plaintext.toString("utf8");
54
+ }
55
+ export function fingerprintSecret(value) {
56
+ return createHash("sha256").update(value).digest("hex").slice(0, 12);
57
+ }
58
+ //# sourceMappingURL=secret-crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-crypto.js","sourceRoot":"","sources":["../../src/secrets/secret-crypto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { SecretRedactionRegistry } from "./secret-types.js";
2
+ export declare class InMemorySecretRedactionRegistry implements SecretRedactionRegistry {
3
+ private readonly values;
4
+ record(key: string, value: string): void;
5
+ redact<T>(value: T): T;
6
+ redactString(input: string): string;
7
+ }
8
+ export declare function redactWithRegistry<T>(registry: SecretRedactionRegistry | undefined, value: T): T;
@@ -0,0 +1,40 @@
1
+ export class InMemorySecretRedactionRegistry {
2
+ values = new Map();
3
+ record(key, value) {
4
+ if (!value)
5
+ return;
6
+ const set = this.values.get(key) ?? new Set();
7
+ set.add(value);
8
+ set.add(value.trim());
9
+ set.add(`Bearer ${value}`);
10
+ this.values.set(key, set);
11
+ }
12
+ redact(value) {
13
+ if (typeof value === "string")
14
+ return this.redactString(value);
15
+ if (Array.isArray(value))
16
+ return value.map((entry) => this.redact(entry));
17
+ if (value && typeof value === "object") {
18
+ const output = {};
19
+ for (const [k, v] of Object.entries(value))
20
+ output[k] = this.redact(v);
21
+ return output;
22
+ }
23
+ return value;
24
+ }
25
+ redactString(input) {
26
+ let output = input;
27
+ for (const [key, values] of this.values.entries()) {
28
+ for (const secret of values) {
29
+ if (!secret)
30
+ continue;
31
+ output = output.split(secret).join(`[secret:${key}]`);
32
+ }
33
+ }
34
+ return output;
35
+ }
36
+ }
37
+ export function redactWithRegistry(registry, value) {
38
+ return registry ? registry.redact(value) : value;
39
+ }
40
+ //# sourceMappingURL=secret-redaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-redaction.js","sourceRoot":"","sources":["../../src/secrets/secret-redaction.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,+BAA+B;IACzB,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAEzD,MAAM,CAAC,GAAW,EAAE,KAAa;QAC/B,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;QACtD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACf,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACtB,GAAG,CAAC,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC;QAC3B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,MAAM,CAAI,KAAQ;QAChB,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAM,CAAC;QACpE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAM,CAAC;QAC/E,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvC,MAAM,MAAM,GAA4B,EAAE,CAAC;YAC3C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;gBAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAClG,OAAO,MAAW,CAAC;QACrB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,YAAY,CAAC,KAAa;QACxB,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;YAClD,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;gBAC5B,IAAI,CAAC,MAAM;oBAAE,SAAS;gBACtB,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAED,MAAM,UAAU,kBAAkB,CAAI,QAA6C,EAAE,KAAQ;IAC3F,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACnD,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { type SecretMetadata, type SecretResolver } from "./secret-types.js";
2
+ export interface SecretStoreOptions {
3
+ filePath?: string;
4
+ passphrase?: string;
5
+ }
6
+ export declare class SecretStore implements SecretResolver {
7
+ private readonly filePath;
8
+ private readonly passphrase;
9
+ private file;
10
+ private constructor();
11
+ static open(options?: SecretStoreOptions): Promise<SecretStore>;
12
+ list(): Promise<SecretMetadata[]>;
13
+ info(key: string): Promise<SecretMetadata | undefined>;
14
+ requestEmpty(key: string, options?: {
15
+ reason?: string;
16
+ requestedBy?: "agent" | "user";
17
+ }): Promise<SecretMetadata>;
18
+ getPlaintext(key: string): Promise<string>;
19
+ setPlaintext(key: string, value: string): Promise<SecretMetadata>;
20
+ delete(key: string): Promise<boolean>;
21
+ rename(oldKey: string, newKey: string): Promise<SecretMetadata>;
22
+ resolve(key: string): Promise<string>;
23
+ resolveForTool(key: string): Promise<string>;
24
+ private requireEntry;
25
+ private decryptEntry;
26
+ private key;
27
+ private save;
28
+ }
@@ -0,0 +1,158 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { getNeoctlHome } from "../paths.js";
4
+ import { createDefaultKdf, decryptSecret, deriveSecretKey, encryptSecret } from "./secret-crypto.js";
5
+ import { SecretEmptyError, SecretNotFoundError } from "./secret-types.js";
6
+ function nowIso() {
7
+ return new Date().toISOString();
8
+ }
9
+ function validateKey(key) {
10
+ const trimmed = key.trim();
11
+ if (!/^[A-Za-z0-9_.:@/-]{1,128}$/.test(trimmed)) {
12
+ throw new Error("Secret key must be 1-128 chars and contain only letters, numbers, _, -, ., :, @, or /.");
13
+ }
14
+ return trimmed;
15
+ }
16
+ function metadata(entry) {
17
+ return {
18
+ key: entry.key,
19
+ status: entry.status,
20
+ length: entry.length,
21
+ createdAt: entry.createdAt,
22
+ updatedAt: entry.updatedAt,
23
+ requestedBy: entry.requestedBy,
24
+ requestReason: entry.requestReason,
25
+ };
26
+ }
27
+ export class SecretStore {
28
+ filePath;
29
+ passphrase;
30
+ file;
31
+ constructor(filePath, passphrase, file) {
32
+ this.filePath = filePath;
33
+ this.passphrase = passphrase;
34
+ this.file = file;
35
+ }
36
+ static async open(options = {}) {
37
+ const filePath = options.filePath ?? path.join(getNeoctlHome(), "secrets.json");
38
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
39
+ let file;
40
+ try {
41
+ const raw = await fs.readFile(filePath, "utf8");
42
+ file = JSON.parse(raw);
43
+ }
44
+ catch (error) {
45
+ if (error.code !== "ENOENT")
46
+ throw error;
47
+ }
48
+ file ??= { version: 1, kdf: createDefaultKdf(), items: {} };
49
+ return new SecretStore(filePath, options.passphrase, file);
50
+ }
51
+ async list() {
52
+ return Object.values(this.file.items).map(metadata).sort((a, b) => a.key.localeCompare(b.key));
53
+ }
54
+ async info(key) {
55
+ const entry = this.file.items[validateKey(key)];
56
+ return entry ? metadata(entry) : undefined;
57
+ }
58
+ async requestEmpty(key, options = {}) {
59
+ const normalized = validateKey(key);
60
+ const existing = this.file.items[normalized];
61
+ if (existing) {
62
+ if (options.reason && !existing.requestReason)
63
+ existing.requestReason = options.reason;
64
+ existing.requestedBy ??= options.requestedBy;
65
+ existing.updatedAt = nowIso();
66
+ await this.save();
67
+ return metadata(existing);
68
+ }
69
+ const timestamp = nowIso();
70
+ const entry = {
71
+ key: normalized,
72
+ status: "empty",
73
+ length: 0,
74
+ createdAt: timestamp,
75
+ updatedAt: timestamp,
76
+ requestedBy: options.requestedBy,
77
+ requestReason: options.reason,
78
+ };
79
+ this.file.items[normalized] = entry;
80
+ await this.save();
81
+ return metadata(entry);
82
+ }
83
+ async getPlaintext(key) {
84
+ const entry = this.requireEntry(key);
85
+ if (entry.status === "empty")
86
+ return "";
87
+ return this.decryptEntry(entry);
88
+ }
89
+ async setPlaintext(key, value) {
90
+ const normalized = validateKey(key);
91
+ const timestamp = nowIso();
92
+ const existing = this.file.items[normalized];
93
+ const encrypted = encryptSecret(value, this.key());
94
+ const entry = {
95
+ key: normalized,
96
+ status: "set",
97
+ length: value.length,
98
+ createdAt: existing?.createdAt ?? timestamp,
99
+ updatedAt: timestamp,
100
+ requestedBy: existing?.requestedBy,
101
+ requestReason: existing?.requestReason,
102
+ ...encrypted,
103
+ };
104
+ this.file.items[normalized] = entry;
105
+ await this.save();
106
+ return metadata(entry);
107
+ }
108
+ async delete(key) {
109
+ const normalized = validateKey(key);
110
+ const existed = Boolean(this.file.items[normalized]);
111
+ delete this.file.items[normalized];
112
+ if (existed)
113
+ await this.save();
114
+ return existed;
115
+ }
116
+ async rename(oldKey, newKey) {
117
+ const oldNormalized = validateKey(oldKey);
118
+ const newNormalized = validateKey(newKey);
119
+ if (this.file.items[newNormalized])
120
+ throw new Error(`Secret "${newNormalized}" already exists.`);
121
+ const entry = this.requireEntry(oldNormalized);
122
+ delete this.file.items[oldNormalized];
123
+ const renamed = { ...entry, key: newNormalized, updatedAt: nowIso() };
124
+ this.file.items[newNormalized] = renamed;
125
+ await this.save();
126
+ return metadata(renamed);
127
+ }
128
+ async resolve(key) {
129
+ return this.resolveForTool(key);
130
+ }
131
+ async resolveForTool(key) {
132
+ const entry = this.requireEntry(key);
133
+ if (entry.status === "empty")
134
+ throw new SecretEmptyError(entry.key);
135
+ return this.decryptEntry(entry);
136
+ }
137
+ requireEntry(key) {
138
+ const normalized = validateKey(key);
139
+ const entry = this.file.items[normalized];
140
+ if (!entry)
141
+ throw new SecretNotFoundError(normalized);
142
+ return entry;
143
+ }
144
+ decryptEntry(entry) {
145
+ if (!entry.ciphertext || !entry.iv || !entry.tag)
146
+ throw new SecretEmptyError(entry.key);
147
+ return decryptSecret({ ciphertext: entry.ciphertext, iv: entry.iv, tag: entry.tag }, this.key());
148
+ }
149
+ key() {
150
+ return deriveSecretKey({ kdf: this.file.kdf, passphrase: this.passphrase });
151
+ }
152
+ async save() {
153
+ const tmp = `${this.filePath}.tmp`;
154
+ await fs.writeFile(tmp, `${JSON.stringify(this.file, null, 2)}\n`, "utf8");
155
+ await fs.rename(tmp, this.filePath);
156
+ }
157
+ }
158
+ //# sourceMappingURL=secret-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-store.js","sourceRoot":"","sources":["../../src/secrets/secret-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export type SecretStatus = "set" | "empty";
2
+ export interface SecretMetadata {
3
+ key: string;
4
+ status: SecretStatus;
5
+ length: number;
6
+ createdAt: string;
7
+ updatedAt: string;
8
+ requestedBy?: "agent" | "user";
9
+ requestReason?: string;
10
+ }
11
+ export interface SecretResolver {
12
+ list(): Promise<SecretMetadata[]>;
13
+ info(key: string): Promise<SecretMetadata | undefined>;
14
+ requestEmpty(key: string, options?: {
15
+ reason?: string;
16
+ requestedBy?: "agent" | "user";
17
+ }): Promise<SecretMetadata>;
18
+ resolve(key: string): Promise<string>;
19
+ }
20
+ export interface SecretRedactionRegistry {
21
+ record(key: string, value: string): void;
22
+ redact<T>(value: T): T;
23
+ }
24
+ export declare class SecretNotFoundError extends Error {
25
+ readonly key: string;
26
+ constructor(key: string);
27
+ }
28
+ export declare class SecretEmptyError extends Error {
29
+ readonly key: string;
30
+ constructor(key: string);
31
+ }
@@ -0,0 +1,17 @@
1
+ export class SecretNotFoundError extends Error {
2
+ key;
3
+ constructor(key) {
4
+ super(`Secret "${key}" does not exist.`);
5
+ this.key = key;
6
+ this.name = "SecretNotFoundError";
7
+ }
8
+ }
9
+ export class SecretEmptyError extends Error {
10
+ key;
11
+ constructor(key) {
12
+ super(`Secret "${key}" exists but has no value. Fill it in REPL with: /secret set ${key} <value>`);
13
+ this.key = key;
14
+ this.name = "SecretEmptyError";
15
+ }
16
+ }
17
+ //# sourceMappingURL=secret-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-types.js","sourceRoot":"","sources":["../../src/secrets/secret-types.ts"],"names":[],"mappings":"AAwBA,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAChB;IAA5B,YAA4B,GAAW;QACrC,KAAK,CAAC,WAAW,GAAG,mBAAmB,CAAC,CAAC;QADf,QAAG,GAAH,GAAG,CAAQ;QAErC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACb;IAA5B,YAA4B,GAAW;QACrC,KAAK,CAAC,WAAW,GAAG,gEAAgE,GAAG,UAAU,CAAC,CAAC;QADzE,QAAG,GAAH,GAAG,CAAQ;QAErC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,68 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { InMemoryAppState } from "../app/app-state.js";
5
+ import { ToolRegistry } from "../tools/registry.js";
6
+ import { runToolUse } from "../tools/run-tool-use.js";
7
+ import { createExecTool } from "../tools/builtins/exec-tool.js";
8
+ import { createSecretTools } from "../tools/builtins/secret-tools.js";
9
+ import { InMemorySecretRedactionRegistry } from "./secret-redaction.js";
10
+ import { SecretStore } from "./secret-store.js";
11
+ async function main() {
12
+ const dir = await fs.mkdtemp(path.join(os.tmpdir(), "neoctl-secrets-"));
13
+ const filePath = path.join(dir, "secrets.json");
14
+ const store = await SecretStore.open({ filePath, passphrase: "smoke-passphrase" });
15
+ await store.setPlaintext("api_token", "super-secret-token");
16
+ const empty = await store.requestEmpty("github_token", { reason: "Need GitHub API", requestedBy: "agent" });
17
+ const raw = await fs.readFile(filePath, "utf8");
18
+ const encryptedAtRestOk = !raw.includes("super-secret-token") && raw.includes("api_token") && raw.includes("github_token");
19
+ const list = await store.list();
20
+ const metadataOk = list.some((entry) => entry.key === "api_token" && entry.status === "set" && entry.length === "super-secret-token".length)
21
+ && empty.status === "empty";
22
+ const registry = new ToolRegistry();
23
+ for (const tool of createSecretTools())
24
+ registry.register(tool);
25
+ registry.register(createExecTool());
26
+ const redactions = new InMemorySecretRedactionRegistry();
27
+ const context = {
28
+ agentId: "smoke",
29
+ tools: registry,
30
+ appState: new InMemoryAppState("smoke", dir),
31
+ secrets: store,
32
+ secretRedactions: redactions,
33
+ emit: () => undefined,
34
+ };
35
+ const secretList = await runToolUse({ id: "secret_list", name: "secret_list", input: {} }, context);
36
+ const secretListJson = JSON.stringify(secretList);
37
+ const listToolOk = secretListJson.includes("api_token") && secretListJson.includes('"length":18') && !secretListJson.includes("super-secret-token");
38
+ const request = await runToolUse({ id: "secret_request", name: "secret_request", input: { key: "new_token", reason: "test" } }, context);
39
+ const requestOk = JSON.stringify(request).includes("new_token") && (await store.info("new_token"))?.status === "empty";
40
+ const execResult = await runToolUse({
41
+ id: "exec_secret",
42
+ name: "exec",
43
+ input: {
44
+ command: "node -e \"console.log(process.env.API_TOKEN)\"",
45
+ description: "verify secret env redaction",
46
+ envSecrets: { API_TOKEN: "api_token" },
47
+ maxOutputChars: 1000,
48
+ },
49
+ }, context);
50
+ const execJson = JSON.stringify(execResult);
51
+ const execRedactedOk = execJson.includes("[secret:api_token]") && !execJson.includes("super-secret-token");
52
+ let emptyErrorOk = false;
53
+ try {
54
+ await store.resolveForTool("github_token");
55
+ }
56
+ catch (error) {
57
+ emptyErrorOk = error instanceof Error && error.message.includes("has no value");
58
+ }
59
+ const ok = encryptedAtRestOk && metadataOk && listToolOk && requestOk && execRedactedOk && emptyErrorOk;
60
+ console.log(JSON.stringify({ ok, encryptedAtRestOk, metadataOk, listToolOk, requestOk, execRedactedOk, emptyErrorOk }, null, 2));
61
+ if (!ok)
62
+ process.exitCode = 1;
63
+ }
64
+ void main().catch((error) => {
65
+ console.error(error);
66
+ process.exitCode = 1;
67
+ });
68
+ //# sourceMappingURL=smoke-secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke-secrets.js","sourceRoot":"","sources":["../../src/secrets/smoke-secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAEnF,MAAM,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5G,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,iBAAiB,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAC3H,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IAChC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,WAAW,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,oBAAoB,CAAC,MAAM,CAAC;WACvI,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC;IAE9B,MAAM,QAAQ,GAAG,IAAI,YAAY,EAAE,CAAC;IACpC,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE;QAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAChE,QAAQ,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC;IACpC,MAAM,UAAU,GAAG,IAAI,+BAA+B,EAAE,CAAC;IACzD,MAAM,OAAO,GAAmB;QAC9B,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE,IAAI,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC;QAC5C,OAAO,EAAE,KAAK;QACd,gBAAgB,EAAE,UAAU;QAC5B,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS;KACtB,CAAC;IAEF,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACpG,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IAEpJ,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACzI,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAEvH,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC;QAClC,EAAE,EAAE,aAAa;QACjB,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE;YACL,OAAO,EAAE,gDAAgD;YACzD,WAAW,EAAE,6BAA6B;YAC1C,UAAU,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;YACtC,cAAc,EAAE,IAAI;SACrB;KACF,EAAE,OAAO,CAAC,CAAC;IACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,cAAc,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IAE3G,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,GAAG,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,EAAE,GAAG,iBAAiB,IAAI,UAAU,IAAI,UAAU,IAAI,SAAS,IAAI,cAAc,IAAI,YAAY,CAAC;IACxG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACjI,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -8,11 +8,30 @@ export interface ExecToolInput {
8
8
  maxOutputChars: number;
9
9
  shell: ExecShell;
10
10
  env: Record<string, string>;
11
- description?: string;
11
+ envSecrets: Record<string, string>;
12
+ description: string;
12
13
  background?: boolean;
13
14
  }
15
+ export interface ForegroundExecDetachResult {
16
+ ok: boolean;
17
+ message: string;
18
+ taskId?: string;
19
+ agentId?: string;
20
+ }
21
+ export interface ForegroundExecDetachHandle {
22
+ toolUseId?: string;
23
+ command: string;
24
+ description?: string;
25
+ cwd: string;
26
+ startedAt: number;
27
+ detach(): ForegroundExecDetachResult;
28
+ }
29
+ export interface ForegroundExecDetachRegistry {
30
+ set(handle: ForegroundExecDetachHandle): () => void;
31
+ }
14
32
  export interface ExecToolRuntime {
15
33
  taskStore?: TaskStore;
34
+ foregroundDetachRegistry?: ForegroundExecDetachRegistry;
16
35
  }
17
36
  export declare function createExecTool(runtime?: ExecToolRuntime): Tool<ExecToolInput>;
18
37
  export declare const execTool: Tool<ExecToolInput>;