@aitne/shared 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.
- package/LICENSE +21 -0
- package/dist/advisor-models.d.ts +34 -0
- package/dist/advisor-models.d.ts.map +1 -0
- package/dist/advisor-models.js +39 -0
- package/dist/advisor-models.js.map +1 -0
- package/dist/agent-identity.d.ts +11 -0
- package/dist/agent-identity.d.ts.map +1 -0
- package/dist/agent-identity.js +29 -0
- package/dist/agent-identity.js.map +1 -0
- package/dist/alerts.d.ts +44 -0
- package/dist/alerts.d.ts.map +1 -0
- package/dist/alerts.js +12 -0
- package/dist/alerts.js.map +1 -0
- package/dist/backend-api-key-config.d.ts +337 -0
- package/dist/backend-api-key-config.d.ts.map +1 -0
- package/dist/backend-api-key-config.js +682 -0
- package/dist/backend-api-key-config.js.map +1 -0
- package/dist/backend.d.ts +93 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +22 -0
- package/dist/backend.js.map +1 -0
- package/dist/branding.d.ts +96 -0
- package/dist/branding.d.ts.map +1 -0
- package/dist/branding.js +102 -0
- package/dist/branding.js.map +1 -0
- package/dist/chat-session-scope.d.ts +14 -0
- package/dist/chat-session-scope.d.ts.map +1 -0
- package/dist/chat-session-scope.js +18 -0
- package/dist/chat-session-scope.js.map +1 -0
- package/dist/date-utils.d.ts +80 -0
- package/dist/date-utils.d.ts.map +1 -0
- package/dist/date-utils.js +187 -0
- package/dist/date-utils.js.map +1 -0
- package/dist/docs-frontmatter.d.ts +51 -0
- package/dist/docs-frontmatter.d.ts.map +1 -0
- package/dist/docs-frontmatter.js +184 -0
- package/dist/docs-frontmatter.js.map +1 -0
- package/dist/docs-schema.d.ts +79 -0
- package/dist/docs-schema.d.ts.map +1 -0
- package/dist/docs-schema.js +135 -0
- package/dist/docs-schema.js.map +1 -0
- package/dist/editable-config-keys.d.ts +14 -0
- package/dist/editable-config-keys.d.ts.map +1 -0
- package/dist/editable-config-keys.js +157 -0
- package/dist/editable-config-keys.js.map +1 -0
- package/dist/exec-with-stdin.d.ts +14 -0
- package/dist/exec-with-stdin.d.ts.map +1 -0
- package/dist/exec-with-stdin.js +35 -0
- package/dist/exec-with-stdin.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations-snapshot.d.ts +183 -0
- package/dist/integrations-snapshot.d.ts.map +1 -0
- package/dist/integrations-snapshot.js +757 -0
- package/dist/integrations-snapshot.js.map +1 -0
- package/dist/integrations.d.ts +675 -0
- package/dist/integrations.d.ts.map +1 -0
- package/dist/integrations.js +1656 -0
- package/dist/integrations.js.map +1 -0
- package/dist/keychain-helper-client.d.ts +31 -0
- package/dist/keychain-helper-client.d.ts.map +1 -0
- package/dist/keychain-helper-client.js +105 -0
- package/dist/keychain-helper-client.js.map +1 -0
- package/dist/log-entry.d.ts +14 -0
- package/dist/log-entry.d.ts.map +1 -0
- package/dist/log-entry.js +2 -0
- package/dist/log-entry.js.map +1 -0
- package/dist/management-domains.d.ts +369 -0
- package/dist/management-domains.d.ts.map +1 -0
- package/dist/management-domains.js +499 -0
- package/dist/management-domains.js.map +1 -0
- package/dist/process-key.d.ts +67 -0
- package/dist/process-key.d.ts.map +1 -0
- package/dist/process-key.js +366 -0
- package/dist/process-key.js.map +1 -0
- package/dist/schemas.d.ts +267 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +271 -0
- package/dist/schemas.js.map +1 -0
- package/dist/secret-client-factory.d.ts +16 -0
- package/dist/secret-client-factory.d.ts.map +1 -0
- package/dist/secret-client-factory.js +111 -0
- package/dist/secret-client-factory.js.map +1 -0
- package/dist/secret-client-file.d.ts +51 -0
- package/dist/secret-client-file.d.ts.map +1 -0
- package/dist/secret-client-file.js +160 -0
- package/dist/secret-client-file.js.map +1 -0
- package/dist/secret-client-linux.d.ts +26 -0
- package/dist/secret-client-linux.d.ts.map +1 -0
- package/dist/secret-client-linux.js +63 -0
- package/dist/secret-client-linux.js.map +1 -0
- package/dist/secret-client-windows.d.ts +37 -0
- package/dist/secret-client-windows.d.ts.map +1 -0
- package/dist/secret-client-windows.js +82 -0
- package/dist/secret-client-windows.js.map +1 -0
- package/dist/secret-redaction.d.ts +3 -0
- package/dist/secret-redaction.d.ts.map +1 -0
- package/dist/secret-redaction.js +31 -0
- package/dist/secret-redaction.js.map +1 -0
- package/dist/skill-curation/decision-language.d.ts +6 -0
- package/dist/skill-curation/decision-language.d.ts.map +1 -0
- package/dist/skill-curation/decision-language.js +38 -0
- package/dist/skill-curation/decision-language.js.map +1 -0
- package/dist/skill-curation/schemas.d.ts +461 -0
- package/dist/skill-curation/schemas.d.ts.map +1 -0
- package/dist/skill-curation/schemas.js +211 -0
- package/dist/skill-curation/schemas.js.map +1 -0
- package/dist/types.d.ts +204 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +54 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const notificationPlatformSchema = z.enum([
|
|
3
|
+
"slack",
|
|
4
|
+
"telegram",
|
|
5
|
+
"discord",
|
|
6
|
+
"whatsapp",
|
|
7
|
+
]);
|
|
8
|
+
// ── Context File API ──
|
|
9
|
+
export const contextPutSchema = z.object({
|
|
10
|
+
content: z.string(),
|
|
11
|
+
/**
|
|
12
|
+
* Optimistic-concurrency token. When provided, the server compares this
|
|
13
|
+
* against the current file's mtime and returns 409 on mismatch. Agents
|
|
14
|
+
* can omit it (backward compatible); the dashboard always sends it to
|
|
15
|
+
* guard against lost updates.
|
|
16
|
+
*/
|
|
17
|
+
expectedMtime: z.string().optional(),
|
|
18
|
+
});
|
|
19
|
+
/** Strict timestamp format used by SignalDetector. Lexicographic comparison
|
|
20
|
+
* only works when both sides use zero-padded YYYY-MM-DD HH:MM:SS. */
|
|
21
|
+
const CUTOFF_FORMAT_RE = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
|
|
22
|
+
export const contextPatchSchema = z.object({
|
|
23
|
+
/**
|
|
24
|
+
* Target `## Section` to operate on. Required for all modes except
|
|
25
|
+
* `append_to_file`, which appends to the end of the file without
|
|
26
|
+
* targeting a section.
|
|
27
|
+
*/
|
|
28
|
+
section: z.string().optional(),
|
|
29
|
+
mode: z.enum(["append", "replace", "clear", "clear_before", "append_to_file"]),
|
|
30
|
+
content: z.string().optional(),
|
|
31
|
+
/**
|
|
32
|
+
* For clear_before mode: remove entries whose `- [YYYY-MM-DD HH:MM:SS]`
|
|
33
|
+
* timestamp is ≤ this value. Entries without a parseable timestamp or
|
|
34
|
+
* with a timestamp > cutoff are preserved. This enables race-safe
|
|
35
|
+
* consumption of timestamped sections like Raw Signals.
|
|
36
|
+
*/
|
|
37
|
+
cutoff: z.string().optional(),
|
|
38
|
+
/**
|
|
39
|
+
* For append mode: after appending, if the section contains more than
|
|
40
|
+
* maxEntries bullet lines (`- ...`), trim the oldest (topmost) to stay
|
|
41
|
+
* within budget. Prevents unbounded section growth.
|
|
42
|
+
*/
|
|
43
|
+
maxEntries: z.number().int().positive().optional(),
|
|
44
|
+
}).refine((data) => data.mode === "append_to_file" || (data.section !== undefined && data.section.length > 0), { message: "section is required for all modes except append_to_file" }).refine((data) => data.mode === "append" || data.maxEntries === undefined, { message: "maxEntries is only valid with mode 'append'" }).refine((data) => data.mode === "clear_before" || data.cutoff === undefined, { message: "cutoff is only valid with mode 'clear_before'" }).refine((data) => data.mode !== "clear_before" || (data.cutoff !== undefined && CUTOFF_FORMAT_RE.test(data.cutoff)), { message: "clear_before requires cutoff in 'YYYY-MM-DD HH:MM:SS' format (zero-padded)" });
|
|
45
|
+
// ── Agent Internal API ──
|
|
46
|
+
export const notifyRequestSchema = z.object({
|
|
47
|
+
message: z.string(),
|
|
48
|
+
platform: notificationPlatformSchema.optional(),
|
|
49
|
+
platforms: z.array(notificationPlatformSchema).optional(),
|
|
50
|
+
priority: z.enum(["critical", "high", "normal", "low"]).optional(),
|
|
51
|
+
}).refine((data) => !(data.platform && data.platforms), { message: "Use either 'platform' or 'platforms', not both" });
|
|
52
|
+
export const scheduleRequestSchema = z.object({
|
|
53
|
+
time: z.string(), // ISO8601
|
|
54
|
+
taskType: z.string(),
|
|
55
|
+
description: z
|
|
56
|
+
.string()
|
|
57
|
+
.min(20, "Description must be at least 20 characters. The wake-up agent has NO memory — the description is its only context."),
|
|
58
|
+
// Optional override for the actual task body the agent receives. When set,
|
|
59
|
+
// takes precedence over `description` as the `task` slot in the task-flow
|
|
60
|
+
// template. When omitted, `description` doubles as both the user-facing
|
|
61
|
+
// label and the agent body (preserves the long-standing skill API).
|
|
62
|
+
prompt: z
|
|
63
|
+
.string()
|
|
64
|
+
.min(20, "Prompt must be at least 20 characters. The wake-up agent has NO memory — the prompt is its only context.")
|
|
65
|
+
.optional(),
|
|
66
|
+
model: z.enum(["sonnet", "opus"]).optional(),
|
|
67
|
+
taskContext: z.record(z.string(), z.unknown()).optional(),
|
|
68
|
+
});
|
|
69
|
+
export const scheduleUpdateRequestSchema = z.object({
|
|
70
|
+
time: z.string().optional(),
|
|
71
|
+
description: z
|
|
72
|
+
.string()
|
|
73
|
+
.min(20, "Description must be at least 20 characters. The wake-up agent has NO memory — the description is its only context.")
|
|
74
|
+
.optional(),
|
|
75
|
+
// Pass `null` to clear an override and fall back to `description`.
|
|
76
|
+
prompt: z
|
|
77
|
+
.union([
|
|
78
|
+
z
|
|
79
|
+
.string()
|
|
80
|
+
.min(20, "Prompt must be at least 20 characters. The wake-up agent has NO memory — the prompt is its only context."),
|
|
81
|
+
z.null(),
|
|
82
|
+
])
|
|
83
|
+
.optional(),
|
|
84
|
+
message: z.string().min(1).optional(), // for dm type only
|
|
85
|
+
model: z.enum(["sonnet", "opus"]).optional(),
|
|
86
|
+
taskContext: z.record(z.string(), z.unknown()).optional(),
|
|
87
|
+
}).refine((data) => Object.values(data).some((v) => v !== undefined), { message: "At least one field must be provided for update" }).refine((data) => !(data.description !== undefined && data.message !== undefined), { message: "Cannot set both 'description' and 'message'. Use 'description' for wake-up tasks, 'message' for dm." }).refine(
|
|
88
|
+
// dm rows do not run an agent, so a prompt override has nothing to
|
|
89
|
+
// override. This catches the cross-type combo at validation time
|
|
90
|
+
// (the route handler also rejects prompt on dm-type rows for the
|
|
91
|
+
// single-field case where the row's task_type is the gate).
|
|
92
|
+
(data) => !(data.prompt !== undefined && data.message !== undefined), { message: "Cannot set both 'prompt' and 'message'. 'prompt' is only valid for non-dm schedules." });
|
|
93
|
+
export const scheduleDmRequestSchema = z.object({
|
|
94
|
+
time: z.string(), // ISO8601 with timezone
|
|
95
|
+
message: z.string().min(1, "Message cannot be empty"),
|
|
96
|
+
platform: notificationPlatformSchema.optional(), // temporary singular form
|
|
97
|
+
platforms: z.array(notificationPlatformSchema).optional(),
|
|
98
|
+
importance: z.enum(["transient", "normal", "strategic"]).optional(),
|
|
99
|
+
}).refine((data) => !(data.platform && data.platforms), { message: "Use either 'platform' or 'platforms', not both" });
|
|
100
|
+
export const actionLogRequestSchema = z.object({
|
|
101
|
+
actionType: z.string(),
|
|
102
|
+
detail: z.string(),
|
|
103
|
+
result: z.enum(["success", "failed", "partial", "skipped"]),
|
|
104
|
+
});
|
|
105
|
+
// ── User Skills API ──
|
|
106
|
+
/**
|
|
107
|
+
* Skill slug constraints — kebab-case, 1-64 chars, safe for filesystem & URLs.
|
|
108
|
+
* Explicitly rejects path traversal, whitespace, and uppercase to keep
|
|
109
|
+
* filesystem semantics consistent across macOS (case-insensitive) and Linux.
|
|
110
|
+
*/
|
|
111
|
+
export const skillNameSchema = z
|
|
112
|
+
.string()
|
|
113
|
+
.min(1, "Skill name cannot be empty")
|
|
114
|
+
.max(64, "Skill name must be at most 64 characters")
|
|
115
|
+
.regex(/^[a-z0-9][a-z0-9-]*$/, "Skill name must be kebab-case (lowercase letters, digits, hyphens) and start with a letter or digit");
|
|
116
|
+
/**
|
|
117
|
+
* Single-line description constraint.
|
|
118
|
+
*
|
|
119
|
+
* The SKILL.md frontmatter serializer writes descriptions inline as a
|
|
120
|
+
* double-quoted YAML scalar. Multi-line descriptions would break the
|
|
121
|
+
* minimal regex-based parser we use, so we reject newlines at the
|
|
122
|
+
* validation layer rather than implementing a full YAML block scalar.
|
|
123
|
+
*/
|
|
124
|
+
const skillDescriptionSchema = z
|
|
125
|
+
.string()
|
|
126
|
+
.min(1, "description is required")
|
|
127
|
+
.max(500, "description must be at most 500 characters")
|
|
128
|
+
.refine((v) => !/[\r\n]/.test(v), {
|
|
129
|
+
message: "description cannot contain newlines",
|
|
130
|
+
});
|
|
131
|
+
/**
|
|
132
|
+
* `allowed-tools` constraint — matches Claude Code's official SKILL.md
|
|
133
|
+
* convention (e.g. `Bash(curl *)`, `Read`, `Grep`). Each entry is a single
|
|
134
|
+
* line with no control characters.
|
|
135
|
+
*/
|
|
136
|
+
const skillAllowedToolsSchema = z
|
|
137
|
+
.array(z
|
|
138
|
+
.string()
|
|
139
|
+
.min(1)
|
|
140
|
+
.max(200)
|
|
141
|
+
.refine((v) => !/[\r\n]/.test(v), {
|
|
142
|
+
message: "tool entries cannot contain newlines",
|
|
143
|
+
}))
|
|
144
|
+
.max(32, "at most 32 allowed-tools entries");
|
|
145
|
+
export const skillCreateSchema = z.object({
|
|
146
|
+
name: skillNameSchema,
|
|
147
|
+
description: skillDescriptionSchema,
|
|
148
|
+
content: z.string().min(1, "content cannot be empty"),
|
|
149
|
+
allowedTools: skillAllowedToolsSchema.optional(),
|
|
150
|
+
});
|
|
151
|
+
export const skillUpdateSchema = z.object({
|
|
152
|
+
description: skillDescriptionSchema.optional(),
|
|
153
|
+
content: z.string().min(1, "content cannot be empty").optional(),
|
|
154
|
+
allowedTools: skillAllowedToolsSchema.optional(),
|
|
155
|
+
}).refine((data) => data.description !== undefined ||
|
|
156
|
+
data.content !== undefined ||
|
|
157
|
+
data.allowedTools !== undefined, { message: "At least one of 'description', 'content', or 'allowedTools' must be provided" });
|
|
158
|
+
// The schemas are consumed only as the source of the `z.infer<typeof ...>`
|
|
159
|
+
// types exported below; the Zod values are never called at runtime. Prefix
|
|
160
|
+
// with `_` so ESLint's no-unused-vars stops flagging the binding.
|
|
161
|
+
const _skillSummarySchema = z.object({
|
|
162
|
+
name: z.string(),
|
|
163
|
+
description: z.string(),
|
|
164
|
+
builtin: z.boolean(),
|
|
165
|
+
updatedAt: z.string(),
|
|
166
|
+
});
|
|
167
|
+
const _skillDetailSchema = z.object({
|
|
168
|
+
name: z.string(),
|
|
169
|
+
description: z.string(),
|
|
170
|
+
content: z.string(),
|
|
171
|
+
allowedTools: z.array(z.string()),
|
|
172
|
+
builtin: z.boolean(),
|
|
173
|
+
updatedAt: z.string(),
|
|
174
|
+
});
|
|
175
|
+
// ── Calendar API ──
|
|
176
|
+
const calendarEventFields = {
|
|
177
|
+
description: z.string().max(10_000).optional(),
|
|
178
|
+
location: z.string().max(1000).optional(),
|
|
179
|
+
reminders: z.object({
|
|
180
|
+
useDefault: z.boolean(),
|
|
181
|
+
overrides: z.array(z.object({
|
|
182
|
+
method: z.enum(["email", "popup"]),
|
|
183
|
+
minutes: z.number().int().min(0).max(40320),
|
|
184
|
+
})).max(5).optional(),
|
|
185
|
+
}).optional(),
|
|
186
|
+
recurrence: z.array(z.string().max(500)).max(5).optional(),
|
|
187
|
+
attendees: z.array(z.object({
|
|
188
|
+
email: z.string().email(),
|
|
189
|
+
})).max(100).optional(),
|
|
190
|
+
visibility: z.enum(["default", "public", "private", "confidential"]).optional(),
|
|
191
|
+
};
|
|
192
|
+
export const calendarCreateEventSchema = z.object({
|
|
193
|
+
summary: z.string().min(1).max(1000),
|
|
194
|
+
start: z.string().min(1),
|
|
195
|
+
end: z.string().min(1),
|
|
196
|
+
...calendarEventFields,
|
|
197
|
+
});
|
|
198
|
+
export const calendarUpdateEventSchema = z.object({
|
|
199
|
+
summary: z.string().min(1).max(1000).optional(),
|
|
200
|
+
start: z.string().min(1).optional(),
|
|
201
|
+
end: z.string().min(1).optional(),
|
|
202
|
+
...calendarEventFields,
|
|
203
|
+
}).refine((data) => Object.values(data).some((v) => v !== undefined), { message: "At least one field must be provided for update" });
|
|
204
|
+
export const calendarFreeBusySchema = z.object({
|
|
205
|
+
timeMin: z.string().min(1),
|
|
206
|
+
timeMax: z.string().min(1),
|
|
207
|
+
calendarIds: z.array(z.string()).min(1).max(50).optional(),
|
|
208
|
+
});
|
|
209
|
+
// ── Recurring Schedules ──
|
|
210
|
+
const HH_MM_RE = /^\d{2}:\d{2}$/;
|
|
211
|
+
export const recurrenceRuleSchema = z.object({
|
|
212
|
+
frequency: z.enum(["daily", "weekly", "monthly"]),
|
|
213
|
+
/** HH:MM local time */
|
|
214
|
+
time: z.string().regex(HH_MM_RE, "time must be HH:MM format"),
|
|
215
|
+
/** IANA timezone (e.g. "America/New_York"). Optional — auto-filled from daemon config when omitted. */
|
|
216
|
+
timezone: z.string().min(1).optional(),
|
|
217
|
+
/** 0=Sun..6=Sat — required when frequency is weekly */
|
|
218
|
+
daysOfWeek: z.array(z.number().int().min(0).max(6)).min(1).max(7).optional(),
|
|
219
|
+
/** 1-31 — required when frequency is monthly. 29-31 clamp to last day of short months */
|
|
220
|
+
daysOfMonth: z.array(z.number().int().min(1).max(31)).min(1).max(31).optional(),
|
|
221
|
+
}).refine((data) => data.frequency !== "weekly" || (data.daysOfWeek !== undefined && data.daysOfWeek.length > 0), { message: "daysOfWeek is required for weekly frequency" }).refine((data) => data.frequency !== "monthly" || (data.daysOfMonth !== undefined && data.daysOfMonth.length > 0), { message: "daysOfMonth is required for monthly frequency" }).refine((data) => data.frequency !== "daily" || data.daysOfWeek === undefined, { message: "daysOfWeek is not allowed for daily frequency" }).refine((data) => data.frequency !== "daily" || data.daysOfMonth === undefined, { message: "daysOfMonth is not allowed for daily frequency" }).refine((data) => data.frequency !== "weekly" || data.daysOfMonth === undefined, { message: "daysOfMonth is not allowed for weekly frequency" }).refine((data) => data.frequency !== "monthly" || data.daysOfWeek === undefined, { message: "daysOfWeek is not allowed for monthly frequency" });
|
|
222
|
+
export const recurringScheduleCreateSchema = z.object({
|
|
223
|
+
taskType: z.string().min(1),
|
|
224
|
+
description: z.string().min(20, "Description must be at least 20 characters. The wake-up agent has NO memory — the description is its only context."),
|
|
225
|
+
// Optional override for the agent task body. See scheduleRequestSchema.prompt.
|
|
226
|
+
prompt: z
|
|
227
|
+
.string()
|
|
228
|
+
.min(20, "Prompt must be at least 20 characters. The wake-up agent has NO memory — the prompt is its only context.")
|
|
229
|
+
.optional(),
|
|
230
|
+
recurrenceRule: recurrenceRuleSchema,
|
|
231
|
+
model: z.enum(["sonnet", "opus"]).optional(),
|
|
232
|
+
taskContext: z.record(z.string(), z.unknown()).optional(),
|
|
233
|
+
});
|
|
234
|
+
export const recurringScheduleUpdateSchema = z.object({
|
|
235
|
+
description: z.string().min(20, "Description must be at least 20 characters.").optional(),
|
|
236
|
+
// Pass `null` to clear an override and fall back to `description`.
|
|
237
|
+
prompt: z
|
|
238
|
+
.union([
|
|
239
|
+
z.string().min(20, "Prompt must be at least 20 characters."),
|
|
240
|
+
z.null(),
|
|
241
|
+
])
|
|
242
|
+
.optional(),
|
|
243
|
+
recurrenceRule: recurrenceRuleSchema.optional(),
|
|
244
|
+
model: z.enum(["sonnet", "opus"]).optional(),
|
|
245
|
+
taskContext: z.record(z.string(), z.unknown()).optional(),
|
|
246
|
+
enabled: z.boolean().optional(),
|
|
247
|
+
}).refine((data) => Object.values(data).some((v) => v !== undefined), { message: "At least one field must be provided for update" });
|
|
248
|
+
// ── Automation Triggers (docs/design/19-dashboard-ia-and-triggers.md) ──
|
|
249
|
+
const HH_MM_RE_TRIGGER = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
250
|
+
const triggerDomainSchema = z.enum(["git"]);
|
|
251
|
+
const triggerEventTypeSchema = z.enum(["cron.daily", "cron.weekly"]);
|
|
252
|
+
export const triggerCreateSchema = z.object({
|
|
253
|
+
domain: triggerDomainSchema,
|
|
254
|
+
eventType: triggerEventTypeSchema,
|
|
255
|
+
prompt: z
|
|
256
|
+
.string()
|
|
257
|
+
.min(20, "Prompt must be at least 20 characters. The trigger run starts with no chat memory — the prompt is its only instruction."),
|
|
258
|
+
time: z.string().regex(HH_MM_RE_TRIGGER, "time must be HH:MM format"),
|
|
259
|
+
daysOfWeek: z.array(z.number().int().min(0).max(6)).min(1).max(7).optional(),
|
|
260
|
+
}).refine((data) => data.eventType !== "cron.weekly" ||
|
|
261
|
+
(data.daysOfWeek !== undefined && data.daysOfWeek.length > 0), { message: "daysOfWeek is required for cron.weekly" });
|
|
262
|
+
export const triggerUpdateSchema = z.object({
|
|
263
|
+
prompt: z
|
|
264
|
+
.string()
|
|
265
|
+
.min(20, "Prompt must be at least 20 characters.")
|
|
266
|
+
.optional(),
|
|
267
|
+
enabled: z.boolean().optional(),
|
|
268
|
+
time: z.string().regex(HH_MM_RE_TRIGGER, "time must be HH:MM format").optional(),
|
|
269
|
+
daysOfWeek: z.array(z.number().int().min(0).max(6)).min(1).max(7).optional(),
|
|
270
|
+
}).refine((data) => Object.values(data).some((v) => v !== undefined), { message: "At least one field must be provided for update" });
|
|
271
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PersonalAgentKeychainClient } from "./keychain-helper-client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a platform-appropriate secret client.
|
|
4
|
+
*
|
|
5
|
+
* Resolution order:
|
|
6
|
+
* - macOS → NativePersonalAgentKeychainClient (macOS Keychain)
|
|
7
|
+
* - win32 → WindowsDpapiSecretClient (DPAPI)
|
|
8
|
+
* - linux → WSL? FileSecretClient : secret-tool available? LinuxSecretClient : FileSecretClient
|
|
9
|
+
* - other → FileSecretClient
|
|
10
|
+
*
|
|
11
|
+
* The FileSecretClient fallback requires a master password from
|
|
12
|
+
* `PA_MASTER_PASSWORD` env or `~/.personal-agent/secrets/.master-key` file.
|
|
13
|
+
* If neither is available, throws with setup instructions.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createSecretClient(): Promise<PersonalAgentKeychainClient>;
|
|
16
|
+
//# sourceMappingURL=secret-client-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-client-factory.d.ts","sourceRoot":"","sources":["../src/secret-client-factory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAE/E;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,2BAA2B,CAAC,CAwC/E"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { platform } from "node:os";
|
|
2
|
+
import { readFileSync, accessSync, constants } from "node:fs";
|
|
3
|
+
import { join, delimiter } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* Create a platform-appropriate secret client.
|
|
6
|
+
*
|
|
7
|
+
* Resolution order:
|
|
8
|
+
* - macOS → NativePersonalAgentKeychainClient (macOS Keychain)
|
|
9
|
+
* - win32 → WindowsDpapiSecretClient (DPAPI)
|
|
10
|
+
* - linux → WSL? FileSecretClient : secret-tool available? LinuxSecretClient : FileSecretClient
|
|
11
|
+
* - other → FileSecretClient
|
|
12
|
+
*
|
|
13
|
+
* The FileSecretClient fallback requires a master password from
|
|
14
|
+
* `PA_MASTER_PASSWORD` env or `~/.personal-agent/secrets/.master-key` file.
|
|
15
|
+
* If neither is available, throws with setup instructions.
|
|
16
|
+
*/
|
|
17
|
+
export async function createSecretClient() {
|
|
18
|
+
const os = platform();
|
|
19
|
+
switch (os) {
|
|
20
|
+
case "darwin": {
|
|
21
|
+
const { NativePersonalAgentKeychainClient } = await import("./keychain-helper-client.js");
|
|
22
|
+
return new NativePersonalAgentKeychainClient();
|
|
23
|
+
}
|
|
24
|
+
case "win32": {
|
|
25
|
+
const { WindowsDpapiSecretClient } = await import("./secret-client-windows.js");
|
|
26
|
+
// Resolve the PowerShell binary once at startup. Windows PowerShell
|
|
27
|
+
// 5.1 (`powershell.exe`) is preferred because it's the in-box choice
|
|
28
|
+
// on every modern desktop SKU; PowerShell 7+ (`pwsh.exe`) is the
|
|
29
|
+
// fallback for setups that ship pwsh-only (Windows Server Core,
|
|
30
|
+
// PowerShell-Core-only installs). If neither is on PATH, leave the
|
|
31
|
+
// default in place — the first DPAPI exec will surface a clear
|
|
32
|
+
// ENOENT and the caller can install one.
|
|
33
|
+
const psBinary = findExecutableInPath("powershell.exe")
|
|
34
|
+
? "powershell.exe"
|
|
35
|
+
: findExecutableInPath("pwsh.exe")
|
|
36
|
+
? "pwsh.exe"
|
|
37
|
+
: "powershell.exe";
|
|
38
|
+
return new WindowsDpapiSecretClient(undefined, psBinary);
|
|
39
|
+
}
|
|
40
|
+
case "linux": {
|
|
41
|
+
if (isWsl()) {
|
|
42
|
+
return createFileClient();
|
|
43
|
+
}
|
|
44
|
+
if (findExecutableInPath("secret-tool")) {
|
|
45
|
+
const { LinuxSecretClient } = await import("./secret-client-linux.js");
|
|
46
|
+
return new LinuxSecretClient();
|
|
47
|
+
}
|
|
48
|
+
return createFileClient();
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
return createFileClient();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function createFileClient() {
|
|
55
|
+
const { FileSecretClient, resolveMasterPassword } = await import("./secret-client-file.js");
|
|
56
|
+
const password = resolveMasterPassword();
|
|
57
|
+
if (!password) {
|
|
58
|
+
throw new Error("No master password configured for the encrypted secret store. " +
|
|
59
|
+
"Set PA_MASTER_PASSWORD environment variable or create " +
|
|
60
|
+
"~/.personal-agent/secrets/.master-key file.");
|
|
61
|
+
}
|
|
62
|
+
return await FileSecretClient.create(password);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Detect Windows Subsystem for Linux.
|
|
66
|
+
* WSL reports `process.platform === "linux"` but cannot use `secret-tool`
|
|
67
|
+
* because D-Bus / GNOME Keyring are typically unavailable.
|
|
68
|
+
*
|
|
69
|
+
* The platform check is intentionally redundant with the `case "linux"`
|
|
70
|
+
* caller above: `/proc/version` only exists on Linux, so calling this
|
|
71
|
+
* helper from a darwin/win32 path would crash in the read. Keeping the
|
|
72
|
+
* guard inline makes this safe to call from any future code site.
|
|
73
|
+
*/
|
|
74
|
+
function isWsl() {
|
|
75
|
+
if (platform() !== "linux")
|
|
76
|
+
return false;
|
|
77
|
+
try {
|
|
78
|
+
const version = readFileSync("/proc/version", "utf-8");
|
|
79
|
+
return /microsoft|wsl/i.test(version);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Lightweight executable finder (shared package cannot depend on daemon's cli-utils).
|
|
87
|
+
* Checks PATH for the given command, respecting PATHEXT on Windows.
|
|
88
|
+
*/
|
|
89
|
+
function findExecutableInPath(command) {
|
|
90
|
+
const pathValue = process.env.PATH;
|
|
91
|
+
if (!pathValue)
|
|
92
|
+
return false;
|
|
93
|
+
const extensions = platform() === "win32" && !/\.[A-Za-z0-9]+$/.test(command)
|
|
94
|
+
? (process.env.PATHEXT?.split(";").filter(Boolean) ?? [".exe", ".cmd", ".bat"])
|
|
95
|
+
: [""];
|
|
96
|
+
for (const dir of pathValue.split(delimiter)) {
|
|
97
|
+
if (!dir)
|
|
98
|
+
continue;
|
|
99
|
+
for (const ext of extensions) {
|
|
100
|
+
try {
|
|
101
|
+
accessSync(join(dir, `${command}${ext}`), constants.X_OK);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// keep scanning
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=secret-client-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-client-factory.js","sourceRoot":"","sources":["../src/secret-client-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG5C;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IAEtB,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,EAAE,iCAAiC,EAAE,GAAG,MAAM,MAAM,CAAC,6BAA6B,CAAC,CAAC;YAC1F,OAAO,IAAI,iCAAiC,EAAE,CAAC;QACjD,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,EAAE,wBAAwB,EAAE,GAAG,MAAM,MAAM,CAAC,4BAA4B,CAAC,CAAC;YAChF,oEAAoE;YACpE,qEAAqE;YACrE,iEAAiE;YACjE,gEAAgE;YAChE,mEAAmE;YACnE,+DAA+D;YAC/D,yCAAyC;YACzC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,gBAAgB,CAAC;gBACrD,CAAC,CAAC,gBAAgB;gBAClB,CAAC,CAAC,oBAAoB,CAAC,UAAU,CAAC;oBAChC,CAAC,CAAC,UAAU;oBACZ,CAAC,CAAC,gBAAgB,CAAC;YACvB,OAAO,IAAI,wBAAwB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC3D,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,IAAI,KAAK,EAAE,EAAE,CAAC;gBACZ,OAAO,gBAAgB,EAAE,CAAC;YAC5B,CAAC;YACD,IAAI,oBAAoB,CAAC,aAAa,CAAC,EAAE,CAAC;gBACxC,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;gBACvE,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACjC,CAAC;YACD,OAAO,gBAAgB,EAAE,CAAC;QAC5B,CAAC;QAED;YACE,OAAO,gBAAgB,EAAE,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,gBAAgB;IAC7B,MAAM,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAC5F,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;IACzC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,gEAAgE;YAChE,wDAAwD;YACxD,6CAA6C,CAC9C,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,KAAK;IACZ,IAAI,QAAQ,EAAE,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QACvD,OAAO,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,oBAAoB,CAAC,OAAe;IAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IACnC,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAE7B,MAAM,UAAU,GAAG,QAAQ,EAAE,KAAK,OAAO,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC;QAC3E,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAET,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,GAAG,EAAE,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;gBAC1D,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,gBAAgB;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { PersonalAgentKeychainClient } from "./keychain-helper-client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Encrypted file-based secret client.
|
|
4
|
+
*
|
|
5
|
+
* Used as the universal fallback when no native secret store is available
|
|
6
|
+
* (headless Linux, WSL, or any unsupported platform).
|
|
7
|
+
*
|
|
8
|
+
* Each secret is stored in its own `.enc` file under `~/.personal-agent/secrets/`,
|
|
9
|
+
* encrypted with AES-256-GCM. The encryption key is derived from a master
|
|
10
|
+
* password using async scrypt with a per-secret random salt.
|
|
11
|
+
*
|
|
12
|
+
* Use the static `create()` factory to construct — it validates the master
|
|
13
|
+
* password asynchronously before returning the instance.
|
|
14
|
+
*
|
|
15
|
+
* The master password is resolved by callers (typically the factory) from:
|
|
16
|
+
* 1. `PA_MASTER_PASSWORD` environment variable
|
|
17
|
+
* 2. `~/.personal-agent/secrets/.master-key` file (chmod 0600)
|
|
18
|
+
*
|
|
19
|
+
* On first use, the master password hash is stored in `.master-hash` for
|
|
20
|
+
* validation on subsequent accesses.
|
|
21
|
+
*/
|
|
22
|
+
export declare class FileSecretClient implements PersonalAgentKeychainClient {
|
|
23
|
+
private readonly secretsDir;
|
|
24
|
+
private readonly masterPassword;
|
|
25
|
+
/**
|
|
26
|
+
* Create and initialize a FileSecretClient.
|
|
27
|
+
* Validates the master password against the stored hash (or creates one).
|
|
28
|
+
*/
|
|
29
|
+
static create(masterPassword: string, secretsDir?: string): Promise<FileSecretClient>;
|
|
30
|
+
/** @internal Use `FileSecretClient.create()` instead. */
|
|
31
|
+
constructor(masterPassword: string, secretsDir?: string);
|
|
32
|
+
private filePath;
|
|
33
|
+
private masterHashPath;
|
|
34
|
+
private deriveKey;
|
|
35
|
+
/**
|
|
36
|
+
* On first use, store a hash of the master password so we can detect
|
|
37
|
+
* mismatches on subsequent accesses. If the hash file already exists,
|
|
38
|
+
* validate against it and throw on mismatch.
|
|
39
|
+
*/
|
|
40
|
+
private ensureMasterHash;
|
|
41
|
+
has(secretName: string): Promise<boolean>;
|
|
42
|
+
get(secretName: string): Promise<string | null>;
|
|
43
|
+
set(secretName: string, value: string): Promise<void>;
|
|
44
|
+
delete(secretName: string): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Resolve master password from environment variable or key file.
|
|
48
|
+
* Returns null if neither source provides a password.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveMasterPassword(secretsDir?: string): string | null;
|
|
51
|
+
//# sourceMappingURL=secret-client-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-client-file.d.ts","sourceRoot":"","sources":["../src/secret-client-file.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAkD/E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,gBAAiB,YAAW,2BAA2B;IAClE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC;;;OAGG;WACU,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAM3F,yDAAyD;gBAC7C,cAAc,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;IAMvD,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,cAAc;YAIR,SAAS;IAQvB;;;;OAIG;YACW,gBAAgB;IAuBxB,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAkB/C,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBrD,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAIhD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI,CAuBf"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes, scrypt, timingSafeEqual, } from "node:crypto";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
// promisify(scrypt) accepts (password, salt, keylen, options?) but TS only
|
|
7
|
+
// types the 3-arg overload. Cast to the correct signature.
|
|
8
|
+
const scryptAsync = promisify(scrypt);
|
|
9
|
+
const ALGORITHM = "aes-256-gcm";
|
|
10
|
+
const KEY_LENGTH = 32; // 256 bits
|
|
11
|
+
const IV_LENGTH = 12; // 96 bits for GCM
|
|
12
|
+
const FILE_MODE = 0o600; // owner-only read/write
|
|
13
|
+
const SALT_LENGTH = 32; // 256 bits
|
|
14
|
+
const SCRYPT_COST = 16384; // N=2^14, balances speed vs. security for local use
|
|
15
|
+
const SCRYPT_BLOCK_SIZE = 8;
|
|
16
|
+
const SCRYPT_PARALLELIZATION = 1;
|
|
17
|
+
/**
|
|
18
|
+
* Encrypted file-based secret client.
|
|
19
|
+
*
|
|
20
|
+
* Used as the universal fallback when no native secret store is available
|
|
21
|
+
* (headless Linux, WSL, or any unsupported platform).
|
|
22
|
+
*
|
|
23
|
+
* Each secret is stored in its own `.enc` file under `~/.personal-agent/secrets/`,
|
|
24
|
+
* encrypted with AES-256-GCM. The encryption key is derived from a master
|
|
25
|
+
* password using async scrypt with a per-secret random salt.
|
|
26
|
+
*
|
|
27
|
+
* Use the static `create()` factory to construct — it validates the master
|
|
28
|
+
* password asynchronously before returning the instance.
|
|
29
|
+
*
|
|
30
|
+
* The master password is resolved by callers (typically the factory) from:
|
|
31
|
+
* 1. `PA_MASTER_PASSWORD` environment variable
|
|
32
|
+
* 2. `~/.personal-agent/secrets/.master-key` file (chmod 0600)
|
|
33
|
+
*
|
|
34
|
+
* On first use, the master password hash is stored in `.master-hash` for
|
|
35
|
+
* validation on subsequent accesses.
|
|
36
|
+
*/
|
|
37
|
+
export class FileSecretClient {
|
|
38
|
+
secretsDir;
|
|
39
|
+
masterPassword;
|
|
40
|
+
/**
|
|
41
|
+
* Create and initialize a FileSecretClient.
|
|
42
|
+
* Validates the master password against the stored hash (or creates one).
|
|
43
|
+
*/
|
|
44
|
+
static async create(masterPassword, secretsDir) {
|
|
45
|
+
const client = new FileSecretClient(masterPassword, secretsDir);
|
|
46
|
+
await client.ensureMasterHash();
|
|
47
|
+
return client;
|
|
48
|
+
}
|
|
49
|
+
/** @internal Use `FileSecretClient.create()` instead. */
|
|
50
|
+
constructor(masterPassword, secretsDir) {
|
|
51
|
+
this.masterPassword = masterPassword;
|
|
52
|
+
this.secretsDir = secretsDir ?? join(homedir(), ".personal-agent", "secrets");
|
|
53
|
+
mkdirSync(this.secretsDir, { recursive: true });
|
|
54
|
+
}
|
|
55
|
+
filePath(secretName) {
|
|
56
|
+
if (/[/\\]/.test(secretName)) {
|
|
57
|
+
throw new Error(`Invalid secret name: ${secretName}`);
|
|
58
|
+
}
|
|
59
|
+
return join(this.secretsDir, `${secretName}.enc`);
|
|
60
|
+
}
|
|
61
|
+
masterHashPath() {
|
|
62
|
+
return join(this.secretsDir, ".master-hash");
|
|
63
|
+
}
|
|
64
|
+
async deriveKey(salt) {
|
|
65
|
+
return await scryptAsync(this.masterPassword, salt, KEY_LENGTH, {
|
|
66
|
+
N: SCRYPT_COST,
|
|
67
|
+
r: SCRYPT_BLOCK_SIZE,
|
|
68
|
+
p: SCRYPT_PARALLELIZATION,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* On first use, store a hash of the master password so we can detect
|
|
73
|
+
* mismatches on subsequent accesses. If the hash file already exists,
|
|
74
|
+
* validate against it and throw on mismatch.
|
|
75
|
+
*/
|
|
76
|
+
async ensureMasterHash() {
|
|
77
|
+
const hashPath = this.masterHashPath();
|
|
78
|
+
if (existsSync(hashPath)) {
|
|
79
|
+
const stored = JSON.parse(readFileSync(hashPath, "utf-8"));
|
|
80
|
+
const salt = Buffer.from(stored.salt, "hex");
|
|
81
|
+
const derived = await this.deriveKey(salt);
|
|
82
|
+
const expected = Buffer.from(stored.hash, "hex");
|
|
83
|
+
if (!timingSafeEqual(derived, expected)) {
|
|
84
|
+
throw new Error("Master password mismatch. The password does not match the one used to create the secret store.");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const salt = randomBytes(SALT_LENGTH);
|
|
89
|
+
const hash = await this.deriveKey(salt);
|
|
90
|
+
const content = {
|
|
91
|
+
salt: salt.toString("hex"),
|
|
92
|
+
hash: hash.toString("hex"),
|
|
93
|
+
};
|
|
94
|
+
writeFileSync(hashPath, JSON.stringify(content), { encoding: "utf-8", mode: FILE_MODE });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async has(secretName) {
|
|
98
|
+
return existsSync(this.filePath(secretName));
|
|
99
|
+
}
|
|
100
|
+
async get(secretName) {
|
|
101
|
+
const path = this.filePath(secretName);
|
|
102
|
+
if (!existsSync(path))
|
|
103
|
+
return null;
|
|
104
|
+
const stored = JSON.parse(readFileSync(path, "utf-8"));
|
|
105
|
+
const salt = Buffer.from(stored.salt, "hex");
|
|
106
|
+
const iv = Buffer.from(stored.iv, "hex");
|
|
107
|
+
const authTag = Buffer.from(stored.authTag, "hex");
|
|
108
|
+
const ciphertext = Buffer.from(stored.ciphertext, "hex");
|
|
109
|
+
const key = await this.deriveKey(salt);
|
|
110
|
+
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
111
|
+
decipher.setAuthTag(authTag);
|
|
112
|
+
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
113
|
+
return decrypted.toString("utf-8");
|
|
114
|
+
}
|
|
115
|
+
async set(secretName, value) {
|
|
116
|
+
const salt = randomBytes(SALT_LENGTH);
|
|
117
|
+
const iv = randomBytes(IV_LENGTH);
|
|
118
|
+
const key = await this.deriveKey(salt);
|
|
119
|
+
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
120
|
+
const encrypted = Buffer.concat([cipher.update(value, "utf-8"), cipher.final()]);
|
|
121
|
+
const authTag = cipher.getAuthTag();
|
|
122
|
+
const content = {
|
|
123
|
+
salt: salt.toString("hex"),
|
|
124
|
+
iv: iv.toString("hex"),
|
|
125
|
+
authTag: authTag.toString("hex"),
|
|
126
|
+
ciphertext: encrypted.toString("hex"),
|
|
127
|
+
};
|
|
128
|
+
writeFileSync(this.filePath(secretName), JSON.stringify(content), { encoding: "utf-8", mode: FILE_MODE });
|
|
129
|
+
}
|
|
130
|
+
async delete(secretName) {
|
|
131
|
+
const path = this.filePath(secretName);
|
|
132
|
+
if (existsSync(path))
|
|
133
|
+
unlinkSync(path);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Resolve master password from environment variable or key file.
|
|
138
|
+
* Returns null if neither source provides a password.
|
|
139
|
+
*/
|
|
140
|
+
export function resolveMasterPassword(secretsDir) {
|
|
141
|
+
// 1. Environment variable takes precedence
|
|
142
|
+
if (process.env.PA_MASTER_PASSWORD) {
|
|
143
|
+
return process.env.PA_MASTER_PASSWORD;
|
|
144
|
+
}
|
|
145
|
+
// 2. Key file fallback
|
|
146
|
+
const dir = secretsDir ?? join(homedir(), ".personal-agent", "secrets");
|
|
147
|
+
const keyFilePath = join(dir, ".master-key");
|
|
148
|
+
if (existsSync(keyFilePath)) {
|
|
149
|
+
// Validate permissions — .master-key must be owner-only (0600 or 0400).
|
|
150
|
+
// Other modes risk exposing the master password to same-machine users.
|
|
151
|
+
const mode = statSync(keyFilePath).mode & 0o777;
|
|
152
|
+
if (mode !== 0o600 && mode !== 0o400) {
|
|
153
|
+
throw new Error(`.master-key has permissions 0${mode.toString(8)}, expected 0600 or 0400. ` +
|
|
154
|
+
`Fix with: chmod 600 ${keyFilePath}`);
|
|
155
|
+
}
|
|
156
|
+
return readFileSync(keyFilePath, "utf-8").trim();
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=secret-client-file.js.map
|