@kelpie/schemas 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 +661 -0
- package/README.md +33 -0
- package/dist/account.d.ts +79 -0
- package/dist/account.d.ts.map +1 -0
- package/dist/account.js +66 -0
- package/dist/account.js.map +1 -0
- package/dist/activity.d.ts +23 -0
- package/dist/activity.d.ts.map +1 -0
- package/dist/activity.js +27 -0
- package/dist/activity.js.map +1 -0
- package/dist/agentTask.d.ts +97 -0
- package/dist/agentTask.d.ts.map +1 -0
- package/dist/agentTask.js +127 -0
- package/dist/agentTask.js.map +1 -0
- package/dist/candidate.d.ts +39 -0
- package/dist/candidate.d.ts.map +1 -0
- package/dist/candidate.js +40 -0
- package/dist/candidate.js.map +1 -0
- package/dist/company.d.ts +38 -0
- package/dist/company.d.ts.map +1 -0
- package/dist/company.js +57 -0
- package/dist/company.js.map +1 -0
- package/dist/dashboard.d.ts +112 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +165 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/deal.d.ts +40 -0
- package/dist/deal.d.ts.map +1 -0
- package/dist/deal.js +59 -0
- package/dist/deal.js.map +1 -0
- package/dist/decision.d.ts +46 -0
- package/dist/decision.d.ts.map +1 -0
- package/dist/decision.js +48 -0
- package/dist/decision.js.map +1 -0
- package/dist/form.d.ts +97 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +98 -0
- package/dist/form.js.map +1 -0
- package/dist/formSubmission.d.ts +47 -0
- package/dist/formSubmission.d.ts.map +1 -0
- package/dist/formSubmission.js +47 -0
- package/dist/formSubmission.js.map +1 -0
- package/dist/handbookPage.d.ts +52 -0
- package/dist/handbookPage.d.ts.map +1 -0
- package/dist/handbookPage.js +56 -0
- package/dist/handbookPage.js.map +1 -0
- package/dist/importExport.d.ts +143 -0
- package/dist/importExport.d.ts.map +1 -0
- package/dist/importExport.js +239 -0
- package/dist/importExport.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/invite.d.ts +35 -0
- package/dist/invite.d.ts.map +1 -0
- package/dist/invite.js +31 -0
- package/dist/invite.js.map +1 -0
- package/dist/mcpTool.d.ts +26 -0
- package/dist/mcpTool.d.ts.map +1 -0
- package/dist/mcpTool.js +13 -0
- package/dist/mcpTool.js.map +1 -0
- package/dist/member.d.ts +26 -0
- package/dist/member.d.ts.map +1 -0
- package/dist/member.js +24 -0
- package/dist/member.js.map +1 -0
- package/dist/moduleSetting.d.ts +19 -0
- package/dist/moduleSetting.d.ts.map +1 -0
- package/dist/moduleSetting.js +16 -0
- package/dist/moduleSetting.js.map +1 -0
- package/dist/note.d.ts +34 -0
- package/dist/note.d.ts.map +1 -0
- package/dist/note.js +35 -0
- package/dist/note.js.map +1 -0
- package/dist/opportunity.d.ts +30 -0
- package/dist/opportunity.d.ts.map +1 -0
- package/dist/opportunity.js +41 -0
- package/dist/opportunity.js.map +1 -0
- package/dist/partnership.d.ts +36 -0
- package/dist/partnership.d.ts.map +1 -0
- package/dist/partnership.js +50 -0
- package/dist/partnership.js.map +1 -0
- package/dist/person.d.ts +45 -0
- package/dist/person.d.ts.map +1 -0
- package/dist/person.js +60 -0
- package/dist/person.js.map +1 -0
- package/dist/pipelineStage.d.ts +29 -0
- package/dist/pipelineStage.d.ts.map +1 -0
- package/dist/pipelineStage.js +38 -0
- package/dist/pipelineStage.js.map +1 -0
- package/dist/planItem.d.ts +43 -0
- package/dist/planItem.d.ts.map +1 -0
- package/dist/planItem.js +44 -0
- package/dist/planItem.js.map +1 -0
- package/dist/position.d.ts +22 -0
- package/dist/position.d.ts.map +1 -0
- package/dist/position.js +25 -0
- package/dist/position.js.map +1 -0
- package/dist/raise.d.ts +38 -0
- package/dist/raise.d.ts.map +1 -0
- package/dist/raise.js +53 -0
- package/dist/raise.js.map +1 -0
- package/dist/role.d.ts +21 -0
- package/dist/role.d.ts.map +1 -0
- package/dist/role.js +21 -0
- package/dist/role.js.map +1 -0
- package/dist/search.d.ts +41 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +41 -0
- package/dist/search.js.map +1 -0
- package/dist/session.d.ts +92 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +67 -0
- package/dist/session.js.map +1 -0
- package/dist/values.d.ts +216 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +329 -0
- package/dist/values.js.map +1 -0
- package/dist/webhook.d.ts +85 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +75 -0
- package/dist/webhook.js.map +1 -0
- package/dist/wire.d.ts +40 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +40 -0
- package/dist/wire.js.map +1 -0
- package/package.json +51 -0
- package/src/account.ts +149 -0
- package/src/activity.ts +52 -0
- package/src/agentTask.ts +254 -0
- package/src/candidate.ts +83 -0
- package/src/company.ts +98 -0
- package/src/dashboard.ts +307 -0
- package/src/deal.ts +102 -0
- package/src/decision.ts +106 -0
- package/src/form.ts +217 -0
- package/src/formSubmission.ts +99 -0
- package/src/handbookPage.ts +99 -0
- package/src/importExport.ts +339 -0
- package/src/index.ts +324 -0
- package/src/invite.ts +69 -0
- package/src/mcpTool.ts +32 -0
- package/src/member.ts +53 -0
- package/src/moduleSetting.ts +37 -0
- package/src/note.ts +73 -0
- package/src/opportunity.ts +74 -0
- package/src/partnership.ts +89 -0
- package/src/person.ts +116 -0
- package/src/pipelineStage.ts +71 -0
- package/src/planItem.ts +91 -0
- package/src/position.ts +50 -0
- package/src/raise.ts +94 -0
- package/src/role.ts +45 -0
- package/src/search.ts +86 -0
- package/src/session.ts +177 -0
- package/src/values.ts +427 -0
- package/src/webhook.ts +164 -0
- package/src/wire.ts +51 -0
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kelpie/schemas",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Wire contract for the Kelpie API, as Zod schemas. Shared by the service, the UI, and any agent decoding /v1 responses.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"kelpie",
|
|
7
|
+
"crm",
|
|
8
|
+
"zod",
|
|
9
|
+
"schema",
|
|
10
|
+
"api"
|
|
11
|
+
],
|
|
12
|
+
"license": "AGPL-3.0-only",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/velvet-tiger/kelpie.git",
|
|
16
|
+
"directory": "packages/schemas"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/velvet-tiger/kelpie/tree/main/packages/schemas#readme",
|
|
19
|
+
"bugs": "https://github.com/velvet-tiger/kelpie/issues",
|
|
20
|
+
"type": "module",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=24"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"src",
|
|
30
|
+
"!src/**/*.test.ts"
|
|
31
|
+
],
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"kelpie-source": "./src/index.ts",
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"default": "./dist/index.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc --project tsconfig.build.json",
|
|
41
|
+
"typecheck": "tsc --project tsconfig.json",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:watch": "vitest"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"zod": "^4.4.3"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"vitest": "^4.1.10"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/account.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { THEME_PREFERENCES } from './values.ts'
|
|
4
|
+
import type { ThemePreference } from './values.ts'
|
|
5
|
+
import { definedFields, idSchema, timestampSchema } from './wire.ts'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Wire shapes for `/v1/account`: the signed-in human, rather than the workspace
|
|
9
|
+
* they are looking at or the session they arrived on.
|
|
10
|
+
*
|
|
11
|
+
* An account is global. Changing a name here changes it in every workspace the
|
|
12
|
+
* person belongs to, which is why this is not part of the member resource.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export interface Account {
|
|
16
|
+
readonly id: string
|
|
17
|
+
readonly email: string
|
|
18
|
+
readonly name: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const accountSchema: z.ZodType<Account, unknown> = z.object({
|
|
22
|
+
id: idSchema,
|
|
23
|
+
email: z.string(),
|
|
24
|
+
name: z.string(),
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export interface UpdateAccountInput {
|
|
28
|
+
readonly name?: string
|
|
29
|
+
readonly email?: string
|
|
30
|
+
/** Required by the service whenever `email` is present. */
|
|
31
|
+
readonly currentPassword?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function updateAccountBody(input: UpdateAccountInput): Record<string, unknown> {
|
|
35
|
+
return definedFields({
|
|
36
|
+
name: input.name,
|
|
37
|
+
email: input.email,
|
|
38
|
+
current_password: input.currentPassword,
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* One of the caller's sessions, as the Security page lists them.
|
|
44
|
+
*
|
|
45
|
+
* Distinct from `Session` in `session.ts`, which is the single identity behind
|
|
46
|
+
* `GET /v1/auth/me`. This is a row in "where am I signed in", and `current`
|
|
47
|
+
* marks the one asking.
|
|
48
|
+
*
|
|
49
|
+
* `device` and `location` are nullable because the service records what the
|
|
50
|
+
* request actually carried. A `User-Agent` is usually present; nothing derives
|
|
51
|
+
* a location today, so it is always `null`.
|
|
52
|
+
*/
|
|
53
|
+
export interface AccountSession {
|
|
54
|
+
readonly id: string
|
|
55
|
+
readonly device: string | null
|
|
56
|
+
readonly location: string | null
|
|
57
|
+
readonly lastActiveAt: Date
|
|
58
|
+
readonly current: boolean
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const accountSessionSchema: z.ZodType<AccountSession, unknown> = z
|
|
62
|
+
.object({
|
|
63
|
+
id: idSchema,
|
|
64
|
+
device: z.string().nullable(),
|
|
65
|
+
location: z.string().nullable(),
|
|
66
|
+
last_active_at: timestampSchema,
|
|
67
|
+
current: z.boolean(),
|
|
68
|
+
})
|
|
69
|
+
.transform(
|
|
70
|
+
(wire): AccountSession => ({
|
|
71
|
+
id: wire.id,
|
|
72
|
+
device: wire.device,
|
|
73
|
+
location: wire.location,
|
|
74
|
+
lastActiveAt: wire.last_active_at,
|
|
75
|
+
current: wire.current,
|
|
76
|
+
}),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The shortest password the service will hash.
|
|
81
|
+
*
|
|
82
|
+
* Part of the contract rather than a server detail: signup, reset, and the
|
|
83
|
+
* change-password form all have to state the rule before a caller submits, and
|
|
84
|
+
* a second copy in the browser is a copy that can drift below the real one.
|
|
85
|
+
*/
|
|
86
|
+
export const MINIMUM_PASSWORD_LENGTH = 12
|
|
87
|
+
|
|
88
|
+
export interface ChangePasswordInput {
|
|
89
|
+
readonly currentPassword: string
|
|
90
|
+
readonly newPassword: string
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function changePasswordBody(input: ChangePasswordInput): Record<string, unknown> {
|
|
94
|
+
return { current_password: input.currentPassword, new_password: input.newPassword }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Per-account settings that follow the person between browsers.
|
|
99
|
+
*
|
|
100
|
+
* The three notification fields are stored choices, not switches over a running
|
|
101
|
+
* mailer: Kelpie sends no digest, mention, or product email yet. They record
|
|
102
|
+
* what to do when it does, and the Preferences page says so on screen rather
|
|
103
|
+
* than leaving a reader to infer a capability from a toggle.
|
|
104
|
+
*/
|
|
105
|
+
export interface AccountPreferences {
|
|
106
|
+
readonly timezone: string
|
|
107
|
+
readonly theme: ThemePreference
|
|
108
|
+
readonly emailDigest: boolean
|
|
109
|
+
readonly mentionEmails: boolean
|
|
110
|
+
readonly productUpdates: boolean
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const accountPreferencesSchema: z.ZodType<AccountPreferences, unknown> = z
|
|
114
|
+
.object({
|
|
115
|
+
timezone: z.string(),
|
|
116
|
+
theme: z.enum(THEME_PREFERENCES),
|
|
117
|
+
email_digest: z.boolean(),
|
|
118
|
+
mention_emails: z.boolean(),
|
|
119
|
+
product_updates: z.boolean(),
|
|
120
|
+
})
|
|
121
|
+
.transform(
|
|
122
|
+
(wire): AccountPreferences => ({
|
|
123
|
+
timezone: wire.timezone,
|
|
124
|
+
theme: wire.theme,
|
|
125
|
+
emailDigest: wire.email_digest,
|
|
126
|
+
mentionEmails: wire.mention_emails,
|
|
127
|
+
productUpdates: wire.product_updates,
|
|
128
|
+
}),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
export interface UpdateAccountPreferencesInput {
|
|
132
|
+
readonly timezone?: string
|
|
133
|
+
readonly theme?: ThemePreference
|
|
134
|
+
readonly emailDigest?: boolean
|
|
135
|
+
readonly mentionEmails?: boolean
|
|
136
|
+
readonly productUpdates?: boolean
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function updateAccountPreferencesBody(
|
|
140
|
+
input: UpdateAccountPreferencesInput,
|
|
141
|
+
): Record<string, unknown> {
|
|
142
|
+
return definedFields({
|
|
143
|
+
timezone: input.timezone,
|
|
144
|
+
theme: input.theme,
|
|
145
|
+
email_digest: input.emailDigest,
|
|
146
|
+
mention_emails: input.mentionEmails,
|
|
147
|
+
product_updates: input.productUpdates,
|
|
148
|
+
})
|
|
149
|
+
}
|
package/src/activity.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { ACTIVITY_KINDS, RECORD_TARGET_TYPES } from './values.ts'
|
|
4
|
+
import type { ActivityKind, RecordTargetType } from './values.ts'
|
|
5
|
+
import { idSchema, timestampSchema } from './wire.ts'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Wire shape for `/v1/activities`. Read-only, so there is no body builder here.
|
|
9
|
+
*
|
|
10
|
+
* No `updatedAt`: the table is append-only and carries no such column.
|
|
11
|
+
*
|
|
12
|
+
* `actorLabel` is the display name to use when `actorMemberId` is null, e.g.
|
|
13
|
+
* "Form", "Gmail", "API key". Exactly one of the two is set.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export interface Activity {
|
|
17
|
+
readonly id: string
|
|
18
|
+
readonly targetType: RecordTargetType
|
|
19
|
+
readonly targetId: string
|
|
20
|
+
readonly kind: ActivityKind
|
|
21
|
+
readonly actorMemberId: string | null
|
|
22
|
+
readonly actorLabel: string | null
|
|
23
|
+
readonly action: string
|
|
24
|
+
readonly detail: string | null
|
|
25
|
+
readonly createdAt: Date
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const activitySchema: z.ZodType<Activity, unknown> = z
|
|
29
|
+
.object({
|
|
30
|
+
id: idSchema,
|
|
31
|
+
target_type: z.enum(RECORD_TARGET_TYPES),
|
|
32
|
+
target_id: idSchema,
|
|
33
|
+
kind: z.enum(ACTIVITY_KINDS),
|
|
34
|
+
actor_member_id: idSchema.nullable(),
|
|
35
|
+
actor_label: z.string().nullable(),
|
|
36
|
+
action: z.string(),
|
|
37
|
+
detail: z.string().nullable(),
|
|
38
|
+
created_at: timestampSchema,
|
|
39
|
+
})
|
|
40
|
+
.transform(
|
|
41
|
+
(wire): Activity => ({
|
|
42
|
+
id: wire.id,
|
|
43
|
+
targetType: wire.target_type,
|
|
44
|
+
targetId: wire.target_id,
|
|
45
|
+
kind: wire.kind,
|
|
46
|
+
actorMemberId: wire.actor_member_id,
|
|
47
|
+
actorLabel: wire.actor_label,
|
|
48
|
+
action: wire.action,
|
|
49
|
+
detail: wire.detail,
|
|
50
|
+
createdAt: wire.created_at,
|
|
51
|
+
}),
|
|
52
|
+
)
|
package/src/agentTask.ts
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AGENT_RUN_STATUSES,
|
|
5
|
+
AGENT_TASK_PLACEMENTS,
|
|
6
|
+
AGENT_TASK_TARGET_TYPES,
|
|
7
|
+
} from './values.ts'
|
|
8
|
+
import type { AgentRunStatus, AgentTaskPlacement, AgentTaskTargetType } from './values.ts'
|
|
9
|
+
import {
|
|
10
|
+
definedFields,
|
|
11
|
+
idSchema,
|
|
12
|
+
nullableTimestampSchema,
|
|
13
|
+
recordTimestamps,
|
|
14
|
+
} from './wire.ts'
|
|
15
|
+
import type { RecordTimestamps } from './wire.ts'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Agent tasks (`agent-tasks.md`): prompt recipes over the workspace's own data.
|
|
19
|
+
*
|
|
20
|
+
* The task catalog ships in code, so a TaskDefinition has no timestamps and no
|
|
21
|
+
* body builder — it is read-only on the wire. A ResolvedTask is the one payload
|
|
22
|
+
* both triggers share: Copy puts `prompt` on the clipboard, Run POSTs the whole
|
|
23
|
+
* thing to a registered agent.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** A catalog entry. `id` is a stable string like `company.enrich`, not a ULID. */
|
|
27
|
+
export interface AgentTaskDefinition {
|
|
28
|
+
readonly id: string
|
|
29
|
+
readonly label: string
|
|
30
|
+
readonly description: string
|
|
31
|
+
readonly targetTypes: readonly AgentTaskTargetType[]
|
|
32
|
+
readonly placement: AgentTaskPlacement
|
|
33
|
+
readonly handbookSlugs: readonly string[]
|
|
34
|
+
readonly instructions: string
|
|
35
|
+
readonly writePolicy: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const agentTaskDefinitionSchema: z.ZodType<AgentTaskDefinition, unknown> = z
|
|
39
|
+
.object({
|
|
40
|
+
id: idSchema,
|
|
41
|
+
label: z.string(),
|
|
42
|
+
description: z.string(),
|
|
43
|
+
target_types: z.array(z.enum(AGENT_TASK_TARGET_TYPES)),
|
|
44
|
+
placement: z.enum(AGENT_TASK_PLACEMENTS),
|
|
45
|
+
handbook_slugs: z.array(z.string()),
|
|
46
|
+
instructions: z.string(),
|
|
47
|
+
write_policy: z.string(),
|
|
48
|
+
})
|
|
49
|
+
.transform(
|
|
50
|
+
(wire): AgentTaskDefinition => ({
|
|
51
|
+
id: wire.id,
|
|
52
|
+
label: wire.label,
|
|
53
|
+
description: wire.description,
|
|
54
|
+
targetTypes: wire.target_types,
|
|
55
|
+
placement: wire.placement,
|
|
56
|
+
handbookSlugs: wire.handbook_slugs,
|
|
57
|
+
instructions: wire.instructions,
|
|
58
|
+
writePolicy: wire.write_policy,
|
|
59
|
+
}),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The structured snapshot resolve assembled. `related` keys are id-list names
|
|
64
|
+
* such as `person_ids`; which keys appear depends on the target type.
|
|
65
|
+
*/
|
|
66
|
+
export interface AgentTaskContextPack {
|
|
67
|
+
readonly targetLabel: string
|
|
68
|
+
readonly deepLink: string
|
|
69
|
+
readonly handbookSlugs: readonly string[]
|
|
70
|
+
readonly pinnedNoteIds: readonly string[]
|
|
71
|
+
readonly openPlanIds: readonly string[]
|
|
72
|
+
readonly openDecisionIds: readonly string[]
|
|
73
|
+
readonly related: Readonly<Record<string, readonly string[]>>
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const contextPackSchema: z.ZodType<AgentTaskContextPack, unknown> = z
|
|
77
|
+
.object({
|
|
78
|
+
target_label: z.string(),
|
|
79
|
+
deep_link: z.string(),
|
|
80
|
+
handbook_slugs: z.array(z.string()),
|
|
81
|
+
pinned_note_ids: z.array(idSchema),
|
|
82
|
+
open_plan_ids: z.array(idSchema),
|
|
83
|
+
open_decision_ids: z.array(idSchema),
|
|
84
|
+
related: z.record(z.string(), z.array(idSchema)),
|
|
85
|
+
})
|
|
86
|
+
.transform(
|
|
87
|
+
(wire): AgentTaskContextPack => ({
|
|
88
|
+
targetLabel: wire.target_label,
|
|
89
|
+
deepLink: wire.deep_link,
|
|
90
|
+
handbookSlugs: wire.handbook_slugs,
|
|
91
|
+
pinnedNoteIds: wire.pinned_note_ids,
|
|
92
|
+
openPlanIds: wire.open_plan_ids,
|
|
93
|
+
openDecisionIds: wire.open_decision_ids,
|
|
94
|
+
related: wire.related,
|
|
95
|
+
}),
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
/** What resolve answers, and what a run dispatches. Identical for copy and run. */
|
|
99
|
+
export interface ResolvedAgentTask {
|
|
100
|
+
readonly taskId: string
|
|
101
|
+
readonly targetType: AgentTaskTargetType
|
|
102
|
+
readonly targetId: string
|
|
103
|
+
readonly prompt: string
|
|
104
|
+
readonly context: AgentTaskContextPack
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const resolvedAgentTaskSchema: z.ZodType<ResolvedAgentTask, unknown> = z
|
|
108
|
+
.object({
|
|
109
|
+
task_id: idSchema,
|
|
110
|
+
target_type: z.enum(AGENT_TASK_TARGET_TYPES),
|
|
111
|
+
target_id: idSchema,
|
|
112
|
+
prompt: z.string(),
|
|
113
|
+
context: contextPackSchema,
|
|
114
|
+
})
|
|
115
|
+
.transform(
|
|
116
|
+
(wire): ResolvedAgentTask => ({
|
|
117
|
+
taskId: wire.task_id,
|
|
118
|
+
targetType: wire.target_type,
|
|
119
|
+
targetId: wire.target_id,
|
|
120
|
+
prompt: wire.prompt,
|
|
121
|
+
context: wire.context,
|
|
122
|
+
}),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
export interface ResolveAgentTaskInput {
|
|
126
|
+
readonly targetType: AgentTaskTargetType
|
|
127
|
+
readonly targetId: string
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function resolveAgentTaskBody(input: ResolveAgentTaskInput): Record<string, unknown> {
|
|
131
|
+
return {
|
|
132
|
+
target_type: input.targetType,
|
|
133
|
+
target_id: input.targetId,
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface RunAgentTaskInput extends ResolveAgentTaskInput {
|
|
138
|
+
readonly agentId: string
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function runAgentTaskBody(input: RunAgentTaskInput): Record<string, unknown> {
|
|
142
|
+
return {
|
|
143
|
+
...resolveAgentTaskBody(input),
|
|
144
|
+
agent_id: input.agentId,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* A bring-your-own agent endpoint. The auth header is sealed server-side and
|
|
150
|
+
* never returned; `hasAuthHeader` is all a reader learns about it.
|
|
151
|
+
*/
|
|
152
|
+
export interface RegisteredAgent extends RecordTimestamps {
|
|
153
|
+
readonly id: string
|
|
154
|
+
readonly name: string
|
|
155
|
+
readonly endpoint: string
|
|
156
|
+
readonly hasAuthHeader: boolean
|
|
157
|
+
readonly lastRunAt: Date | null
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export const registeredAgentSchema: z.ZodType<RegisteredAgent, unknown> = z
|
|
161
|
+
.object({
|
|
162
|
+
id: idSchema,
|
|
163
|
+
name: z.string(),
|
|
164
|
+
endpoint: z.string(),
|
|
165
|
+
has_auth_header: z.boolean(),
|
|
166
|
+
last_run_at: nullableTimestampSchema,
|
|
167
|
+
...recordTimestamps,
|
|
168
|
+
})
|
|
169
|
+
.transform(
|
|
170
|
+
(wire): RegisteredAgent => ({
|
|
171
|
+
id: wire.id,
|
|
172
|
+
name: wire.name,
|
|
173
|
+
endpoint: wire.endpoint,
|
|
174
|
+
hasAuthHeader: wire.has_auth_header,
|
|
175
|
+
lastRunAt: wire.last_run_at,
|
|
176
|
+
createdAt: wire.created_at,
|
|
177
|
+
updatedAt: wire.updated_at,
|
|
178
|
+
}),
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
export interface CreateRegisteredAgentInput {
|
|
182
|
+
readonly name: string
|
|
183
|
+
readonly endpoint: string
|
|
184
|
+
/** Sent as the `Authorization` header on every dispatch to this agent. */
|
|
185
|
+
readonly authHeader?: string
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function createRegisteredAgentBody(
|
|
189
|
+
input: CreateRegisteredAgentInput,
|
|
190
|
+
): Record<string, unknown> {
|
|
191
|
+
return definedFields({
|
|
192
|
+
name: input.name,
|
|
193
|
+
endpoint: input.endpoint,
|
|
194
|
+
auth_header: input.authHeader,
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface RegisteredAgentInput {
|
|
199
|
+
readonly name?: string
|
|
200
|
+
readonly endpoint?: string
|
|
201
|
+
/** A string replaces the stored header; `null` clears it. */
|
|
202
|
+
readonly authHeader?: string | null
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function registeredAgentBody(input: RegisteredAgentInput): Record<string, unknown> {
|
|
206
|
+
return definedFields({
|
|
207
|
+
name: input.name,
|
|
208
|
+
endpoint: input.endpoint,
|
|
209
|
+
auth_header: input.authHeader,
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* One dispatch of a ResolvedTask to a registered agent. `failureReason` is set
|
|
215
|
+
* only on `failed`, and says what the dispatch hit — a status, a timeout, a
|
|
216
|
+
* refused connection.
|
|
217
|
+
*/
|
|
218
|
+
export interface AgentRun extends RecordTimestamps {
|
|
219
|
+
readonly id: string
|
|
220
|
+
readonly agentId: string
|
|
221
|
+
readonly taskId: string
|
|
222
|
+
readonly targetType: AgentTaskTargetType
|
|
223
|
+
readonly targetId: string
|
|
224
|
+
readonly status: AgentRunStatus
|
|
225
|
+
readonly prompt: string
|
|
226
|
+
readonly failureReason: string | null
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const agentRunSchema: z.ZodType<AgentRun, unknown> = z
|
|
230
|
+
.object({
|
|
231
|
+
id: idSchema,
|
|
232
|
+
agent_id: idSchema,
|
|
233
|
+
task_id: idSchema,
|
|
234
|
+
target_type: z.enum(AGENT_TASK_TARGET_TYPES),
|
|
235
|
+
target_id: idSchema,
|
|
236
|
+
status: z.enum(AGENT_RUN_STATUSES),
|
|
237
|
+
prompt: z.string(),
|
|
238
|
+
failure_reason: z.string().nullable(),
|
|
239
|
+
...recordTimestamps,
|
|
240
|
+
})
|
|
241
|
+
.transform(
|
|
242
|
+
(wire): AgentRun => ({
|
|
243
|
+
id: wire.id,
|
|
244
|
+
agentId: wire.agent_id,
|
|
245
|
+
taskId: wire.task_id,
|
|
246
|
+
targetType: wire.target_type,
|
|
247
|
+
targetId: wire.target_id,
|
|
248
|
+
status: wire.status,
|
|
249
|
+
prompt: wire.prompt,
|
|
250
|
+
failureReason: wire.failure_reason,
|
|
251
|
+
createdAt: wire.created_at,
|
|
252
|
+
updatedAt: wire.updated_at,
|
|
253
|
+
}),
|
|
254
|
+
)
|
package/src/candidate.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { CANDIDATE_STATUSES, INTERVIEW_STAGES } from './values.ts'
|
|
4
|
+
import type { CandidateStatus, InterviewStage } from './values.ts'
|
|
5
|
+
import { definedFields, idSchema, recordTimestamps } from './wire.ts'
|
|
6
|
+
import type { RecordTimestamps } from './wire.ts'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Wire and write shapes for `/v1/candidates`, the Person↔Role link.
|
|
10
|
+
*
|
|
11
|
+
* Hiring pipeline state sits here rather than on Person, so the same person can
|
|
12
|
+
* be interviewing for one role and in the nurture pile for another. Interview
|
|
13
|
+
* notes attach to the candidate, not to the person or the role.
|
|
14
|
+
*
|
|
15
|
+
* Neither end is updatable: moving a candidacy to a different role or person is
|
|
16
|
+
* a delete and a create, the rule Position already follows.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export interface Candidate extends RecordTimestamps {
|
|
20
|
+
readonly id: string
|
|
21
|
+
readonly roleId: string
|
|
22
|
+
readonly personId: string
|
|
23
|
+
readonly status: CandidateStatus
|
|
24
|
+
/** Null unless the candidate is in process. The API keeps that true. */
|
|
25
|
+
readonly interviewStage: InterviewStage | null
|
|
26
|
+
readonly referrerPersonId: string | null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const candidateSchema: z.ZodType<Candidate, unknown> = z
|
|
30
|
+
.object({
|
|
31
|
+
id: idSchema,
|
|
32
|
+
role_id: idSchema,
|
|
33
|
+
person_id: idSchema,
|
|
34
|
+
status: z.enum(CANDIDATE_STATUSES),
|
|
35
|
+
interview_stage: z.enum(INTERVIEW_STAGES).nullable(),
|
|
36
|
+
referrer_person_id: idSchema.nullable(),
|
|
37
|
+
...recordTimestamps,
|
|
38
|
+
})
|
|
39
|
+
.transform(
|
|
40
|
+
(wire): Candidate => ({
|
|
41
|
+
id: wire.id,
|
|
42
|
+
roleId: wire.role_id,
|
|
43
|
+
personId: wire.person_id,
|
|
44
|
+
status: wire.status,
|
|
45
|
+
interviewStage: wire.interview_stage,
|
|
46
|
+
referrerPersonId: wire.referrer_person_id,
|
|
47
|
+
createdAt: wire.created_at,
|
|
48
|
+
updatedAt: wire.updated_at,
|
|
49
|
+
}),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
export interface CreateCandidateInput {
|
|
53
|
+
readonly roleId: string
|
|
54
|
+
readonly personId: string
|
|
55
|
+
/** Absent means in process, where the mockup's "Add candidate" starts one. */
|
|
56
|
+
readonly status?: CandidateStatus
|
|
57
|
+
readonly interviewStage?: InterviewStage | null
|
|
58
|
+
readonly referrerPersonId?: string | null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function createCandidateBody(input: CreateCandidateInput): Record<string, unknown> {
|
|
62
|
+
return definedFields({
|
|
63
|
+
role_id: input.roleId,
|
|
64
|
+
person_id: input.personId,
|
|
65
|
+
status: input.status,
|
|
66
|
+
interview_stage: input.interviewStage,
|
|
67
|
+
referrer_person_id: input.referrerPersonId,
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface CandidateInput {
|
|
72
|
+
readonly status?: CandidateStatus
|
|
73
|
+
readonly interviewStage?: InterviewStage | null
|
|
74
|
+
readonly referrerPersonId?: string | null
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function candidateBody(input: CandidateInput): Record<string, unknown> {
|
|
78
|
+
return definedFields({
|
|
79
|
+
status: input.status,
|
|
80
|
+
interview_stage: input.interviewStage,
|
|
81
|
+
referrer_person_id: input.referrerPersonId,
|
|
82
|
+
})
|
|
83
|
+
}
|
package/src/company.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { ACCOUNT_TYPES, COMPANY_STAGES, ICP_FITS, SIZE_BANDS } from './values.ts'
|
|
4
|
+
import type { AccountType, CompanyStage, IcpFit, SizeBand } from './values.ts'
|
|
5
|
+
import { definedFields, idSchema, recordTimestamps } from './wire.ts'
|
|
6
|
+
import type { RecordTimestamps } from './wire.ts'
|
|
7
|
+
|
|
8
|
+
/** Wire and write shapes for `/v1/companies`. */
|
|
9
|
+
|
|
10
|
+
export interface Company extends RecordTimestamps {
|
|
11
|
+
readonly id: string
|
|
12
|
+
readonly name: string
|
|
13
|
+
readonly domain: string | null
|
|
14
|
+
readonly industry: string | null
|
|
15
|
+
readonly description: string
|
|
16
|
+
readonly stage: CompanyStage
|
|
17
|
+
readonly sizeBand: SizeBand
|
|
18
|
+
readonly hq: string | null
|
|
19
|
+
readonly website: string | null
|
|
20
|
+
readonly accountType: AccountType
|
|
21
|
+
readonly icpFit: IcpFit
|
|
22
|
+
readonly techStack: readonly string[]
|
|
23
|
+
readonly summary: string
|
|
24
|
+
readonly tags: readonly string[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const companySchema: z.ZodType<Company, unknown> = z
|
|
28
|
+
.object({
|
|
29
|
+
id: idSchema,
|
|
30
|
+
name: z.string(),
|
|
31
|
+
domain: z.string().nullable(),
|
|
32
|
+
industry: z.string().nullable(),
|
|
33
|
+
description: z.string(),
|
|
34
|
+
stage: z.enum(COMPANY_STAGES),
|
|
35
|
+
size_band: z.enum(SIZE_BANDS),
|
|
36
|
+
hq: z.string().nullable(),
|
|
37
|
+
website: z.string().nullable(),
|
|
38
|
+
account_type: z.enum(ACCOUNT_TYPES),
|
|
39
|
+
icp_fit: z.enum(ICP_FITS),
|
|
40
|
+
tech_stack: z.array(z.string()),
|
|
41
|
+
summary: z.string(),
|
|
42
|
+
tags: z.array(z.string()),
|
|
43
|
+
...recordTimestamps,
|
|
44
|
+
})
|
|
45
|
+
.transform(
|
|
46
|
+
(wire): Company => ({
|
|
47
|
+
id: wire.id,
|
|
48
|
+
name: wire.name,
|
|
49
|
+
domain: wire.domain,
|
|
50
|
+
industry: wire.industry,
|
|
51
|
+
description: wire.description,
|
|
52
|
+
stage: wire.stage,
|
|
53
|
+
sizeBand: wire.size_band,
|
|
54
|
+
hq: wire.hq,
|
|
55
|
+
website: wire.website,
|
|
56
|
+
accountType: wire.account_type,
|
|
57
|
+
icpFit: wire.icp_fit,
|
|
58
|
+
techStack: wire.tech_stack,
|
|
59
|
+
summary: wire.summary,
|
|
60
|
+
tags: wire.tags,
|
|
61
|
+
createdAt: wire.created_at,
|
|
62
|
+
updatedAt: wire.updated_at,
|
|
63
|
+
}),
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
export interface CompanyInput {
|
|
67
|
+
readonly name?: string
|
|
68
|
+
readonly domain?: string | null
|
|
69
|
+
readonly industry?: string | null
|
|
70
|
+
readonly description?: string
|
|
71
|
+
readonly stage?: CompanyStage
|
|
72
|
+
readonly sizeBand?: SizeBand
|
|
73
|
+
readonly hq?: string | null
|
|
74
|
+
readonly website?: string | null
|
|
75
|
+
readonly accountType?: AccountType
|
|
76
|
+
readonly icpFit?: IcpFit
|
|
77
|
+
readonly techStack?: readonly string[]
|
|
78
|
+
readonly summary?: string
|
|
79
|
+
readonly tags?: readonly string[]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function companyBody(input: CompanyInput): Record<string, unknown> {
|
|
83
|
+
return definedFields({
|
|
84
|
+
name: input.name,
|
|
85
|
+
domain: input.domain,
|
|
86
|
+
industry: input.industry,
|
|
87
|
+
description: input.description,
|
|
88
|
+
stage: input.stage,
|
|
89
|
+
size_band: input.sizeBand,
|
|
90
|
+
hq: input.hq,
|
|
91
|
+
website: input.website,
|
|
92
|
+
account_type: input.accountType,
|
|
93
|
+
icp_fit: input.icpFit,
|
|
94
|
+
tech_stack: input.techStack,
|
|
95
|
+
summary: input.summary,
|
|
96
|
+
tags: input.tags,
|
|
97
|
+
})
|
|
98
|
+
}
|