@hitch42/applet 0.1.1-beta.20 → 0.1.1-beta.22
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/dist/_internal/client.d.ts +0 -2
- package/dist/_internal/client.js +3 -5
- package/dist/_internal/log-context.d.ts +0 -2
- package/dist/_internal/log-context.js +1 -2
- package/dist/_internal/server.d.ts +2 -10
- package/dist/_internal/server.js +9 -14
- package/dist/applet.js +64 -23
- package/dist/auth-DuMRqSGe.js +49 -0
- package/dist/{batch-_ZjAg-Kk.js → batch-DwyWmiaE.js} +3 -4
- package/dist/build-C7hi2yg4.js +1 -0
- package/dist/{build-D47vK5aa.js → build-FAQSHJgm.js} +4 -3
- package/dist/{ci-BTFTCBgy.js → ci-oWlUJKm9.js} +5 -6
- package/dist/client/hitch/client.d.ts +1 -1
- package/dist/client/hitch/client.js +1 -2
- package/dist/client/hitch/phone.d.ts +1 -1
- package/dist/client/hitch/phone.js +1 -2
- package/dist/client/hitch.d.ts +2 -2
- package/dist/client/hitch.js +2 -2
- package/dist/client/react/markdown-editor.d.ts +1 -1
- package/dist/client/react/markdown-editor.js +1 -2
- package/dist/client/react/markdown.d.ts +1 -1
- package/dist/client/react/markdown.js +1 -2
- package/dist/client/react.d.ts +2 -2
- package/dist/client/react.js +2 -2
- package/dist/client.d.ts +2 -4
- package/dist/client.js +3 -5
- package/dist/{contract-CJv-n1l3.d.ts → contract-CUc0B2rl.d.ts} +1 -3
- package/dist/{contract-BeKz1Qcs.js → contract-D9LCNGjD.js} +1 -2
- package/dist/{create-C2UrZYSK.d.ts → create-BJqLT8Uq.d.ts} +0 -4
- package/dist/{deploy-BbqyK5Ik.js → deploy-BM55ZoSp.js} +160 -152
- package/dist/{device-BgIfytaR.js → device-CZWWckCq.js} +54 -34
- package/dist/{email-protocol-B9u_dh2p.d.ts → email-protocol-BWja_v7c.d.ts} +16 -16
- package/dist/generate-DG9vVkBO.js +1 -0
- package/dist/{generate-BLD0DoCk.js → generate-DNgO44RO.js} +32 -37
- package/dist/generated-agents-BUnJ0FQA.js +215 -0
- package/dist/git-credential-CU7-Erzs.js +24 -0
- package/dist/git-deploy-C12nMNB6.js +290 -0
- package/dist/git-deploy-CNz6mxiF.js +1 -0
- package/dist/git-migration-CIq-sN61.js +629 -0
- package/dist/git-safety-Ck3X7jvA.js +13 -0
- package/dist/{headers-CeRX-Xji.js → headers-BcEMIVCo.js} +1 -2
- package/dist/{hitch-client-Cw-WZ_8v.js → hitch-client-CNN-dU6d.js} +5 -7
- package/dist/{hitch-client-DtyTZzP5.d.ts → hitch-client-k7_jIjPw.d.ts} +5 -7
- package/dist/{hitch-file-url-BPKj9zVG.js → hitch-file-url--AMjDOzP.js} +1 -2
- package/dist/index.d.ts +13 -17
- package/dist/index.js +33 -38
- package/dist/{init-BKUBf6i9.js → init-BD5mC_9L.js} +70 -18
- package/dist/{lazy-client-CwIzYAoE.js → lazy-client--QCL0wiu.js} +1 -2
- package/dist/{load-config-DGALUExv.js → load-config-Cffvj-aM.js} +24 -26
- package/dist/{log-context-DWznGjfz.js → log-context-BepwdjrR.js} +1 -2
- package/dist/login-BWZKo7Ui.js +21 -0
- package/dist/{logs-Cv5z1e2w.js → logs-glCVHI-8.js} +6 -6
- package/dist/{manifest-BBHD_EY9.d.ts → manifest-CpghlaJc.d.ts} +6 -7
- package/dist/manifest-patterns-BfxqImlp.js +4 -0
- package/dist/{markdown-CwlqzBtP.js → markdown-BA_XzFxq.js} +2 -3
- package/dist/{markdown-DSHOQIOb.d.ts → markdown-CnB35mjc.d.ts} +1 -3
- package/dist/{markdown-editor-C5mLHGqu.js → markdown-editor-CaUuphfc.js} +3 -5
- package/dist/{markdown-editor-BmEaBzd7.d.ts → markdown-editor-xF3uATBp.d.ts} +1 -5
- package/dist/parent-D52Kxp8U.js +1 -0
- package/dist/parent-Zx8Eg1Ki.js +75 -0
- package/dist/{project-CrxdZR0B.js → project-DZGk765E.js} +63 -54
- package/dist/{prompt-ChS-grYO.js → prompt-CW98R-Un.js} +1 -2
- package/dist/{query-cache-CXmAyLv3.js → query-cache-DQJy45RT.js} +1 -2
- package/dist/{query-utils-zz9pVjgp.d.ts → query-utils-okxIoKM3.d.ts} +0 -2
- package/dist/{schedules-Dajgni_z.js → schedules-CSUb84e2.js} +5 -5
- package/dist/server.d.ts +5 -13
- package/dist/server.js +17 -20
- package/dist/source-hash-BbvtRaus.js +107 -0
- package/dist/store-E5NhITHl.js +448 -0
- package/dist/{upload-DRbVhuDm.js → upload-D1mzpsSk.js} +4 -6
- package/dist/{upload-D_kkmne_.d.ts → upload-wp-Ilsv6.d.ts} +6 -10
- package/dist/{use-phone-ug4B5gQp.js → use-phone-CB_idmrz.js} +9 -13
- package/dist/{use-phone-M7c_HsB7.d.ts → use-phone-DBAkasPq.d.ts} +0 -4
- package/dist/{variables-B-CLu8cY.js → variables-CgZstC7I.js} +7 -8
- package/dist/vite.d.ts +1 -3
- package/dist/vite.js +41 -50
- package/dist/{workflow-DurM6Fwx.d.ts → workflow-BnBrJIzu.d.ts} +0 -2
- package/dist/{workflow-engine-BOTzURKM.js → workflow-engine-CyyaVENo.js} +2 -4
- package/dist/{workflow-CTo2kZF1.js → workflow-l2SlVePB.js} +2 -4
- package/dist/workspace-CtIKSgMD.js +76 -0
- package/package.json +6 -5
- package/scaffold/.agents/skills/hitch-applets/SKILL.md +27 -9
- package/scaffold/.agents/skills/hitch-applets/references/email-tracking.md +4 -4
- package/scaffold/.agents/skills/hitch-applets/references/files.md +2 -2
- package/scaffold/.agents/skills/hitch-applets/references/manifest.md +8 -6
- package/scaffold/.agents/skills/hitch-applets/references/performance.md +2 -2
- package/scaffold/.agents/skills/hitch-applets/references/records.md +8 -8
- package/scaffold/.agents/skills/hitch-cli/SKILL.md +52 -43
- package/scaffold/AGENTS.md +6 -0
- package/dist/auth-D3CrCtZq.js +0 -21
- package/dist/build-JtbY8q2p.js +0 -2
- package/dist/generate-COCRy1Bs.js +0 -2
- package/dist/login-CceGvlMi.js +0 -14
- package/dist/store-B8N_8JIN.js +0 -196
- package/dist/workspace-8yqXsvce.js +0 -31
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ContractProcedure, Meta, Schema } from "@orpc/contract";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
//#region src/hitch/email.d.ts
|
|
4
3
|
type EmailTags = Record<string, string>;
|
|
5
4
|
type CreateEmailPixelInput = {
|
|
6
5
|
tags?: EmailTags;
|
|
@@ -10,10 +9,10 @@ type CreateEmailPixelOutput = {
|
|
|
10
9
|
url: string;
|
|
11
10
|
};
|
|
12
11
|
type GetEmailTrackerInput = {
|
|
13
|
-
|
|
12
|
+
trackerId: string;
|
|
14
13
|
};
|
|
15
14
|
type MarkEmailTrackerSentInput = {
|
|
16
|
-
|
|
15
|
+
trackerId: string;
|
|
17
16
|
sentAt?: string;
|
|
18
17
|
};
|
|
19
18
|
type EmailTracker = {
|
|
@@ -44,17 +43,17 @@ type EmailContract = {
|
|
|
44
43
|
};
|
|
45
44
|
threads: {
|
|
46
45
|
list: ContractProcedure<Schema<ListHitchEmailThreadsInput, ListHitchEmailThreadsInput>, Schema<HitchEmailThreadsOutput, HitchEmailThreadsOutput>, Record<never, never>, Meta>;
|
|
47
|
-
get: ContractProcedure<Schema<
|
|
46
|
+
get: ContractProcedure<Schema<HitchEmailThreadInput, HitchEmailThreadInput>, Schema<HitchEmailThread, HitchEmailThread>, Record<never, never>, Meta>;
|
|
48
47
|
};
|
|
49
48
|
messages: {
|
|
50
49
|
/** Newest first. Pass threadId to page through one thread. */
|
|
51
50
|
list: ContractProcedure<Schema<ListHitchEmailMessagesInput, ListHitchEmailMessagesInput>, Schema<HitchEmailMessagesOutput, HitchEmailMessagesOutput>, Record<never, never>, Meta>;
|
|
52
|
-
get: ContractProcedure<Schema<
|
|
51
|
+
get: ContractProcedure<Schema<HitchEmailMessageInput, HitchEmailMessageInput>, Schema<HitchEmailMessage, HitchEmailMessage>, Record<never, never>, Meta>;
|
|
53
52
|
send: ContractProcedure<Schema<SendHitchEmailInput, SendHitchEmailInput>, Schema<HitchEmailMessage, HitchEmailMessage>, Record<never, never>, Meta>;
|
|
54
|
-
raw: ContractProcedure<Schema<
|
|
53
|
+
raw: ContractProcedure<Schema<HitchEmailMessageInput, HitchEmailMessageInput>, Schema<HitchEmailRawOutput, HitchEmailRawOutput>, Record<never, never>, Meta>;
|
|
55
54
|
};
|
|
56
55
|
attachments: {
|
|
57
|
-
get: ContractProcedure<Schema<
|
|
56
|
+
get: ContractProcedure<Schema<HitchEmailAttachmentInput, HitchEmailAttachmentInput>, Schema<HitchEmailAttachmentOutput, HitchEmailAttachmentOutput>, Record<never, never>, Meta>;
|
|
58
57
|
};
|
|
59
58
|
tracking: {
|
|
60
59
|
createPixel: ContractProcedure<Schema<CreateEmailPixelInput | undefined, CreateEmailPixelInput | undefined>, Schema<CreateEmailPixelOutput, CreateEmailPixelOutput>, Record<never, never>, Meta>;
|
|
@@ -152,8 +151,14 @@ type SendHitchEmailInput = {
|
|
|
152
151
|
attachmentFileIds?: string[];
|
|
153
152
|
requestId?: string;
|
|
154
153
|
};
|
|
155
|
-
type
|
|
156
|
-
|
|
154
|
+
type HitchEmailThreadInput = {
|
|
155
|
+
threadId: string;
|
|
156
|
+
};
|
|
157
|
+
type HitchEmailMessageInput = {
|
|
158
|
+
messageId: string;
|
|
159
|
+
};
|
|
160
|
+
type HitchEmailAttachmentInput = {
|
|
161
|
+
attachmentId: string;
|
|
157
162
|
};
|
|
158
163
|
type HitchEmailMailboxesOutput = {
|
|
159
164
|
data: HitchMailbox[];
|
|
@@ -175,10 +180,8 @@ type HitchEmailAttachmentOutput = {
|
|
|
175
180
|
contentType: string;
|
|
176
181
|
sizeBytes: number;
|
|
177
182
|
};
|
|
178
|
-
//#endregion
|
|
179
|
-
//#region src/server/telephony-protocol.d.ts
|
|
180
183
|
/** Handle events at least once and without order. Use eventId for idempotency.
|
|
181
|
-
* Read the message with hitch.telephony.messages.get({
|
|
184
|
+
* Read the message with hitch.telephony.messages.get({ messageId }). */
|
|
182
185
|
type TelephonyMessageReceivedEvent = {
|
|
183
186
|
eventId: string;
|
|
184
187
|
type: "message.received";
|
|
@@ -186,10 +189,8 @@ type TelephonyMessageReceivedEvent = {
|
|
|
186
189
|
numberId: string;
|
|
187
190
|
occurredAt: string;
|
|
188
191
|
};
|
|
189
|
-
//#endregion
|
|
190
|
-
//#region src/server/email-protocol.d.ts
|
|
191
192
|
/** Handle events at least once and without order. Use eventId for idempotency.
|
|
192
|
-
* Read the message with hitch.email.messages.get({
|
|
193
|
+
* Read the message with hitch.email.messages.get({ messageId }). */
|
|
193
194
|
type EmailMessageReceivedEvent = {
|
|
194
195
|
eventId: string;
|
|
195
196
|
type: "message.received";
|
|
@@ -198,5 +199,4 @@ type EmailMessageReceivedEvent = {
|
|
|
198
199
|
threadId: string;
|
|
199
200
|
occurredAt: string;
|
|
200
201
|
};
|
|
201
|
-
//#endregion
|
|
202
202
|
export { EmailTracker as a, HitchEmailMessage as c, ListEmailTrackersInput as d, ListEmailTrackersOutput as f, emailContract as g, SendHitchEmailInput as h, EmailContract as i, HitchEmailThread as l, ListHitchEmailThreadsInput as m, TelephonyMessageReceivedEvent as n, HitchEmailAddress as o, ListHitchEmailMessagesInput as p, CreateEmailPixelInput as r, HitchEmailAttachment as s, EmailMessageReceivedEvent as t, HitchMailbox as u };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { r as runGenerate } from "./generate-DNgO44RO.js";
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { i as
|
|
1
|
+
import { l as organizationInstanceUrl, m as resolveInstanceUrl } from "./store-E5NhITHl.js";
|
|
2
|
+
import { n as findAppletRoot } from "./workspace-CtIKSgMD.js";
|
|
3
|
+
import { n as fetchWithOrgAuth } from "./auth-DuMRqSGe.js";
|
|
4
|
+
import { t as loadAppletConfig } from "./load-config-Cffvj-aM.js";
|
|
5
|
+
import { i as prepareAppletProject, o as userAgent } from "./project-DZGk765E.js";
|
|
6
|
+
import { i as loadGitHubActionsBuildInputs, n as githubActionsContext, r as hitchResponseError } from "./ci-oWlUJKm9.js";
|
|
6
7
|
import { createRequire } from "node:module";
|
|
7
8
|
import { isContractProcedure, minifyContractRouter } from "@orpc/contract";
|
|
8
9
|
import { randomUUID } from "node:crypto";
|
|
10
|
+
import { pathToFileURL } from "node:url";
|
|
9
11
|
import { existsSync } from "node:fs";
|
|
10
12
|
import { access, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
11
13
|
import { dirname, resolve } from "node:path";
|
|
12
|
-
import { pathToFileURL } from "node:url";
|
|
13
14
|
import { execFile } from "node:child_process";
|
|
14
15
|
import { promisify } from "node:util";
|
|
15
16
|
import { createClient } from "@hey-api/openapi-ts";
|
|
16
|
-
|
|
17
|
+
// src/generated.ts
|
|
17
18
|
const GENERATED_HEADER = "// Generated by @hitch42/applet — do not edit";
|
|
18
19
|
async function writeGenerated(path, source) {
|
|
19
20
|
await mkdir(dirname(path), { recursive: true });
|
|
@@ -57,8 +58,7 @@ import { createWorkerEntry } from "@hitch42/applet/_internal/server";
|
|
|
57
58
|
export default createWorkerEntry(server, { code: ${JSON.stringify(appletCode)} });
|
|
58
59
|
`);
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
-
//#region src/typegen/create-schema.ts
|
|
61
|
+
// src/typegen/create-schema.ts
|
|
62
62
|
function isObject$3(value) {
|
|
63
63
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
64
64
|
}
|
|
@@ -71,22 +71,21 @@ function singleCreateSchema(value) {
|
|
|
71
71
|
const [single, array] = value.oneOf;
|
|
72
72
|
return isComponentRef(single) && isObject$3(array) && array.type === "array" && isComponentRef(array.items) && array.items.$ref === single.$ref ? single : void 0;
|
|
73
73
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const RECORD_ROUTE = /^\/v1\/([^/]+)(?:\/(\{id\}(?:\/history)?|query|update|aggregate))?$/;
|
|
74
|
+
// src/typegen/operations.ts
|
|
75
|
+
const RECORD_ROUTE = /^\/v1\/([^/]+)(?:\/(\{recordId\}(?:\/history)?|query|bulk-update|aggregate))?$/;
|
|
77
76
|
const COMPONENT_REF_PREFIX$1 = "#/components/schemas/";
|
|
78
|
-
const BATCH_PATH = "/v1/batch";
|
|
79
|
-
const BATCH_ITEM_PATH = "paths./v1/batch.post.requestBody.content.application/json.schema.properties.requests.items";
|
|
77
|
+
const BATCH_PATH = "/v1/batch/run";
|
|
78
|
+
const BATCH_ITEM_PATH = "paths./v1/batch/run.post.requestBody.content.application/json.schema.properties.requests.items";
|
|
80
79
|
const BATCH_ID_PATH = /^\^\/v1\/([^/]+)\/\[0-9a-fA-F-\]\{36\}\$$/;
|
|
81
80
|
const VERBS = {
|
|
82
81
|
"get:": "list",
|
|
83
82
|
"post:": "create",
|
|
84
|
-
"get:{
|
|
85
|
-
"get:{
|
|
86
|
-
"patch:{
|
|
87
|
-
"delete:{
|
|
83
|
+
"get:{recordId}": "get",
|
|
84
|
+
"get:{recordId}/history": "history",
|
|
85
|
+
"patch:{recordId}": "update",
|
|
86
|
+
"delete:{recordId}": "delete",
|
|
88
87
|
"post:query": "query",
|
|
89
|
-
"post:update": "updateWhere",
|
|
88
|
+
"post:bulk-update": "updateWhere",
|
|
90
89
|
"post:aggregate": "aggregate"
|
|
91
90
|
};
|
|
92
91
|
const COMPONENT_RESPONSE_STATUS = {
|
|
@@ -103,7 +102,7 @@ function isObject$2(value) {
|
|
|
103
102
|
function recordOperation(path, method) {
|
|
104
103
|
const match = RECORD_ROUTE.exec(path);
|
|
105
104
|
const objectCode = match?.[1];
|
|
106
|
-
if (objectCode === void 0 || objectCode === "
|
|
105
|
+
if (objectCode === void 0 || objectCode === "objects") return void 0;
|
|
107
106
|
const key = `${method.toLowerCase()}:${match?.at(2) ?? ""}`;
|
|
108
107
|
if (!Object.hasOwn(VERBS, key)) return void 0;
|
|
109
108
|
return {
|
|
@@ -113,7 +112,7 @@ function recordOperation(path, method) {
|
|
|
113
112
|
}
|
|
114
113
|
function recordObjectCode(path) {
|
|
115
114
|
const match = RECORD_ROUTE.exec(path);
|
|
116
|
-
return match?.[1] === "
|
|
115
|
+
return match?.[1] === "objects" ? void 0 : match?.[1];
|
|
117
116
|
}
|
|
118
117
|
function withRecordOperationId(path, method, operation) {
|
|
119
118
|
const record = recordOperation(path, method);
|
|
@@ -130,13 +129,13 @@ function batchEntry(entry, index) {
|
|
|
130
129
|
const enumPath = Array.isArray(path?.enum) && path.enum.length === 1 ? path.enum[0] : void 0;
|
|
131
130
|
if (Array.isArray(method) && method.length !== 1 || Array.isArray(path?.enum) && path.enum.length !== 1) throw new Error(`${BATCH_ITEM_PATH}.oneOf[${index}] expected a create, update, delete, or updateWhere batch entry, found ${describeValue$1(entry)}`);
|
|
132
131
|
if (methodValue === "POST" && typeof enumPath === "string") {
|
|
133
|
-
const updateWhere = /^\/v1\/([^/]+)\/update$/.exec(enumPath);
|
|
132
|
+
const updateWhere = /^\/v1\/([^/]+)\/bulk-update$/.exec(enumPath);
|
|
134
133
|
if (updateWhere?.[1] !== void 0) return {
|
|
135
134
|
objectCode: updateWhere[1],
|
|
136
135
|
verb: "updateWhere"
|
|
137
136
|
};
|
|
138
137
|
const create = /^\/v1\/([^/]+)$/.exec(enumPath);
|
|
139
|
-
if (create?.[1] !== void 0
|
|
138
|
+
if (create?.[1] !== void 0) return {
|
|
140
139
|
objectCode: create[1],
|
|
141
140
|
verb: "create"
|
|
142
141
|
};
|
|
@@ -194,6 +193,7 @@ function prepareRecordSpec(spec, manifest) {
|
|
|
194
193
|
return operation === void 0 ? [] : [[path, { post: operation }]];
|
|
195
194
|
}
|
|
196
195
|
const objectCode = recordObjectCode(path);
|
|
196
|
+
if (objectCode === void 0 && /^\/v1\/(?!objects\/)[^/]+\/\{/.test(path)) throw new Error(`paths.${path} is a record route that this SDK cannot read. Use the @hitch42/applet version that matches the Hitch server.`);
|
|
197
197
|
if (!isObject$2(pathItem)) {
|
|
198
198
|
if (objectCode === void 0) return [];
|
|
199
199
|
throw new Error(`object "${objectCode}": paths.${path} expected an object, found ${describeValue$1(pathItem)}`);
|
|
@@ -225,7 +225,7 @@ function prepareRecordSpec(spec, manifest) {
|
|
|
225
225
|
}));
|
|
226
226
|
manifest?.objects.forEach(({ code, optionalAttributes }) => {
|
|
227
227
|
if (optionalAttributes === void 0 || optionalAttributes.length === 0) return;
|
|
228
|
-
const responsePath = `/v1/${code}/{
|
|
228
|
+
const responsePath = `/v1/${code}/{recordId}`;
|
|
229
229
|
const response = prepared.paths[responsePath]?.get?.responses;
|
|
230
230
|
const schema = isObject$2(response) && isObject$2(response["200"]) ? response["200"].content : void 0;
|
|
231
231
|
const mediaType = isObject$2(schema) && isObject$2(schema["application/json"]) ? schema["application/json"] : void 0;
|
|
@@ -263,8 +263,7 @@ function describeValue$1(value, expectedRef = false) {
|
|
|
263
263
|
if (typeof value === "object") return expectedRef ? "an object without a valid $ref" : "an object";
|
|
264
264
|
return `${typeof value} ${JSON.stringify(value)}`;
|
|
265
265
|
}
|
|
266
|
-
|
|
267
|
-
//#region src/typegen/catalog.ts
|
|
266
|
+
// src/typegen/catalog.ts
|
|
268
267
|
const COMPONENT_REF_PREFIX = "#/components/schemas/";
|
|
269
268
|
const RESERVED_ATTRIBUTE_CODES = /* @__PURE__ */ new Set([
|
|
270
269
|
"id",
|
|
@@ -310,8 +309,7 @@ function catalogFromSpec(spec) {
|
|
|
310
309
|
return [[operation.objectCode, Object.keys(schema.properties).filter((code) => !RESERVED_ATTRIBUTE_CODES.has(code))]];
|
|
311
310
|
}));
|
|
312
311
|
}
|
|
313
|
-
|
|
314
|
-
//#region src/typegen/guard.ts
|
|
312
|
+
// src/typegen/guard.ts
|
|
315
313
|
function isObject(value) {
|
|
316
314
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
317
315
|
}
|
|
@@ -326,8 +324,7 @@ function guardManifestForSpec(spec, manifest) {
|
|
|
326
324
|
const missing = manifest.objects.find(({ code }) => !available.includes(code));
|
|
327
325
|
if (missing !== void 0) throw new Error(`object "${missing.code}" not found in org spec (available: ${available.join(", ")})`);
|
|
328
326
|
}
|
|
329
|
-
|
|
330
|
-
//#region src/typegen/register.ts
|
|
327
|
+
// src/typegen/register.ts
|
|
331
328
|
function registerFile(catalog, options, publicApplet) {
|
|
332
329
|
const catalogType = catalog === void 0 ? "type Catalog = Record<string, string>;" : `type Catalog = {
|
|
333
330
|
${Object.entries(catalog).map(([objectCode, attributeCodes]) => ` ${JSON.stringify(objectCode)}: ${attributeCodes.map((code) => JSON.stringify(code)).join(" | ") || "never"};`).join("\n")}
|
|
@@ -391,8 +388,7 @@ async function writeRegisterDeclaration(outDir, catalog, publicApplet = false) {
|
|
|
391
388
|
hasServer: existsSync(resolve(outDir, "../src/server/main.ts"))
|
|
392
389
|
}, publicApplet));
|
|
393
390
|
}
|
|
394
|
-
|
|
395
|
-
//#region src/typegen/generate.ts
|
|
391
|
+
// src/typegen/generate.ts
|
|
396
392
|
const execFileAsync = promisify(execFile);
|
|
397
393
|
const require = createRequire(import.meta.url);
|
|
398
394
|
function routesModuleSource(routes) {
|
|
@@ -515,7 +511,7 @@ async function writeContractFiles(outDir, manifest, spec) {
|
|
|
515
511
|
await generateContract(preparedSpec, outDir);
|
|
516
512
|
await writeManifestGen(outDir, manifest);
|
|
517
513
|
await writeRegisterDeclaration(outDir, catalog, manifest.public === true);
|
|
518
|
-
const hasBatch = Object.hasOwn(preparedSpec.paths, "/v1/batch");
|
|
514
|
+
const hasBatch = Object.hasOwn(preparedSpec.paths, "/v1/batch/run");
|
|
519
515
|
await writeFile(resolve(outDir, "index.ts"), `// Generated by applet generate — do not edit.
|
|
520
516
|
import { emailContract, filesContract as files, meContract as me, pruneContract, registerHitchContract, teamsContract as teams, telephonyContract as telephony } from "@hitch42/applet";
|
|
521
517
|
import manifest from "./manifest.gen.ts";
|
|
@@ -545,11 +541,11 @@ async function syncContract(outDir, manifest) {
|
|
|
545
541
|
}
|
|
546
542
|
async function runGenerate() {
|
|
547
543
|
await prepareAppletProject();
|
|
548
|
-
const root = process.cwd();
|
|
549
|
-
const outDir = resolve("
|
|
544
|
+
const root = findAppletRoot(process.cwd()) ?? process.cwd();
|
|
545
|
+
const outDir = resolve(root, ".hitch");
|
|
550
546
|
const manifest = await loadAppletConfig(process.cwd());
|
|
551
547
|
const { spec, theme: themeStylesheet } = await loadBuildInputs(manifest);
|
|
552
|
-
const stagedDir = await mkdtemp(resolve("
|
|
548
|
+
const stagedDir = await mkdtemp(resolve(root, ".hitch.tmp-"));
|
|
553
549
|
const backupDir = `${stagedDir}.backup`;
|
|
554
550
|
let staged = true;
|
|
555
551
|
let backedUp = false;
|
|
@@ -595,5 +591,4 @@ async function runGenerate() {
|
|
|
595
591
|
if (backedUp && !await fileExists(outDir)) await rename(backupDir, outDir);
|
|
596
592
|
}
|
|
597
593
|
}
|
|
598
|
-
//#endregion
|
|
599
594
|
export { writeRegisterDeclaration as a, writeAppletRoot as c, writeServerEntry as d, syncContract as i, writeClientEntry as l, routesModuleSource as n, prepareRecordSpec as o, runGenerate as r, recordOperation as s, generateContract as t, writeManifestGen as u };
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { r as findParentRoot } from "./workspace-CtIKSgMD.js";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import fs$1 from "node:fs/promises";
|
|
6
|
+
import { dirname, relative, resolve } from "node:path";
|
|
7
|
+
// src/atomic-file.ts
|
|
8
|
+
async function writeChangedFile(path, contents) {
|
|
9
|
+
const expected = Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
|
|
10
|
+
if ((await fs$1.readFile(path).catch((error) => {
|
|
11
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
|
|
12
|
+
throw error;
|
|
13
|
+
}))?.equals(expected) && !(await fs$1.lstat(path)).isSymbolicLink()) return;
|
|
14
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
15
|
+
try {
|
|
16
|
+
await fs$1.writeFile(temporary, expected);
|
|
17
|
+
await fs$1.rename(temporary, path);
|
|
18
|
+
} finally {
|
|
19
|
+
await fs$1.rm(temporary, { force: true });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// src/generated-agents.ts
|
|
23
|
+
const GENERATED_SKILLS = [
|
|
24
|
+
"hitch-applets",
|
|
25
|
+
"hitch-cli",
|
|
26
|
+
"hitch-data",
|
|
27
|
+
"hitch-theory",
|
|
28
|
+
"react-best-practices",
|
|
29
|
+
"tanstack-query",
|
|
30
|
+
"tanstack-router",
|
|
31
|
+
"web-design-guidelines"
|
|
32
|
+
];
|
|
33
|
+
const PARENT_GUIDE = `# Hitch applet parent\n\nEach child folder is one applet repo. Run applet commands in a child for that applet.\nRun applet deploy or applet bootstrap in this parent for all children. Commit changes in each child separately.\n\n`;
|
|
34
|
+
function agentFileAction(input) {
|
|
35
|
+
if (input.child) {
|
|
36
|
+
if (input.kind !== "missing" && !input.dangling && !input.generated) return "edited";
|
|
37
|
+
return input.kind === "link" && input.correctLink && !input.dangling ? "keep" : "link";
|
|
38
|
+
}
|
|
39
|
+
return "write";
|
|
40
|
+
}
|
|
41
|
+
async function state(path) {
|
|
42
|
+
try {
|
|
43
|
+
return (await fs$1.lstat(path)).isSymbolicLink() ? "link" : "file";
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return "missing";
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function files(root) {
|
|
50
|
+
const entries = await fs$1.readdir(root, { withFileTypes: true });
|
|
51
|
+
const contents = await Promise.all(entries.map(async (entry) => {
|
|
52
|
+
if (entry.isDirectory()) return [...await files(resolve(root, entry.name))].map(([path, bytes]) => [`${entry.name}/${path}`, bytes]);
|
|
53
|
+
if (entry.isSymbolicLink()) return [[entry.name, Buffer.from(`symlink:${await fs$1.readlink(resolve(root, entry.name))}`)]];
|
|
54
|
+
return [[entry.name, await fs$1.readFile(resolve(root, entry.name))]];
|
|
55
|
+
}));
|
|
56
|
+
return new Map(contents.flat());
|
|
57
|
+
}
|
|
58
|
+
async function replaceLink(path, target, directory = false) {
|
|
59
|
+
const kind = await state(path);
|
|
60
|
+
if (kind === "link" && await fs$1.readlink(path) === target) return;
|
|
61
|
+
await fs$1.mkdir(dirname(path), { recursive: true });
|
|
62
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
63
|
+
try {
|
|
64
|
+
await fs$1.symlink(target, temporary, directory ? "dir" : "file");
|
|
65
|
+
if (kind === "file" && directory) await fs$1.rm(path, {
|
|
66
|
+
recursive: true,
|
|
67
|
+
force: true
|
|
68
|
+
});
|
|
69
|
+
await fs$1.rename(temporary, path);
|
|
70
|
+
} finally {
|
|
71
|
+
await fs$1.rm(temporary, { force: true });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function generatedAgentContents() {
|
|
75
|
+
const agents = await fs$1.readFile(new URL("../scaffold/AGENTS.md", import.meta.url));
|
|
76
|
+
const result = /* @__PURE__ */ new Map([["AGENTS.md", agents], ["CLAUDE.md", agents]]);
|
|
77
|
+
await Promise.all(GENERATED_SKILLS.map(async (skill) => {
|
|
78
|
+
(await files(fileURLToPath(new URL(`../scaffold/.agents/skills/${skill}`, import.meta.url)))).forEach((bytes, name) => {
|
|
79
|
+
result.set(`.agents/skills/${skill}/${name}`, bytes);
|
|
80
|
+
result.set(`.claude/skills/${skill}/${name}`, bytes);
|
|
81
|
+
});
|
|
82
|
+
}));
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
const editedPaths = /* @__PURE__ */ new Set();
|
|
86
|
+
async function writeGeneratedAgents(root) {
|
|
87
|
+
const parent = findParentRoot(dirname(root));
|
|
88
|
+
const home = parent ?? root;
|
|
89
|
+
const parentGuide = parent !== void 0 || existsSync(resolve(root, ".hitchroot"));
|
|
90
|
+
const agents = await fs$1.readFile(new URL("../scaffold/AGENTS.md", import.meta.url), "utf8");
|
|
91
|
+
const guide = `${parentGuide ? PARENT_GUIDE : ""}${agents}`;
|
|
92
|
+
await fs$1.mkdir(home, { recursive: true });
|
|
93
|
+
const inventoryPath = resolve(home, ".agents/.hitch-generated.json");
|
|
94
|
+
const previous = JSON.parse(await fs$1.readFile(inventoryPath, "utf8").catch((error) => {
|
|
95
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return "{}";
|
|
96
|
+
throw error;
|
|
97
|
+
}));
|
|
98
|
+
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
99
|
+
const generated = await Promise.all(GENERATED_SKILLS.map(async (skill) => ({
|
|
100
|
+
skill,
|
|
101
|
+
contents: await files(fileURLToPath(new URL(`../scaffold/.agents/skills/${skill}`, import.meta.url)))
|
|
102
|
+
})));
|
|
103
|
+
const editedLinks = /* @__PURE__ */ new Set();
|
|
104
|
+
await Promise.all(generated.map(async ({ skill, contents }) => {
|
|
105
|
+
const path = resolve(home, ".agents/skills", skill);
|
|
106
|
+
if (await state(path) !== "link") return;
|
|
107
|
+
const current = await files(path).catch((error) => {
|
|
108
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
|
|
109
|
+
throw error;
|
|
110
|
+
});
|
|
111
|
+
if (current !== void 0 && (current.size !== contents.size || [...contents].some(([name, bytes]) => !current.get(name)?.equals(bytes)))) {
|
|
112
|
+
if (!editedPaths.has(path)) console.warn(`${path} was edited; Hitch left it in place.`);
|
|
113
|
+
editedPaths.add(path);
|
|
114
|
+
editedLinks.add(skill);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
await fs$1.unlink(path).catch((error) => {
|
|
118
|
+
if (!(error instanceof Error && "code" in error && ["ENOENT", "EISDIR"].includes(String(error.code)))) throw error;
|
|
119
|
+
});
|
|
120
|
+
}));
|
|
121
|
+
const expected = /* @__PURE__ */ new Map([["AGENTS.md", Buffer.from(guide)]]);
|
|
122
|
+
await Promise.all(generated.map(async ({ skill, contents }) => {
|
|
123
|
+
const realClaude = await state(resolve(home, ".claude/skills", skill)) === "file";
|
|
124
|
+
contents.forEach((bytes, name) => {
|
|
125
|
+
if (!editedLinks.has(skill)) expected.set(`.agents/skills/${skill}/${name}`, bytes);
|
|
126
|
+
if (realClaude) expected.set(`.claude/skills/${skill}/${name}`, bytes);
|
|
127
|
+
});
|
|
128
|
+
}));
|
|
129
|
+
const inventory = {};
|
|
130
|
+
await Promise.all([...expected].map(async ([name, bytes]) => {
|
|
131
|
+
const path = resolve(home, name);
|
|
132
|
+
const current = await state(path) === "missing" ? void 0 : await fs$1.readFile(path).catch((error) => {
|
|
133
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
|
|
134
|
+
throw error;
|
|
135
|
+
});
|
|
136
|
+
if (!(current === void 0 || current.equals(bytes) || digest(current) === previous[name] || name === "AGENTS.md" && current.toString() === agents)) {
|
|
137
|
+
if (!editedPaths.has(path)) console.warn(`${path} was edited; Hitch left it in place.`);
|
|
138
|
+
editedPaths.add(path);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
await fs$1.mkdir(dirname(path), { recursive: true });
|
|
142
|
+
await writeChangedFile(path, bytes);
|
|
143
|
+
inventory[name] = digest(bytes);
|
|
144
|
+
}));
|
|
145
|
+
await Promise.all(Object.entries(previous).filter(([name]) => !expected.has(name)).map(async ([name, hash]) => {
|
|
146
|
+
if ([...editedLinks].some((skill) => name.startsWith(`.agents/skills/${skill}/`))) return;
|
|
147
|
+
if (![".agents", ".claude"].some((directory) => GENERATED_SKILLS.some((skill) => name.startsWith(`${directory}/skills/${skill}/`)))) return;
|
|
148
|
+
const path = resolve(home, name);
|
|
149
|
+
if (await state(path) === "file" && digest(await fs$1.readFile(path)) === hash) await fs$1.rm(path, { force: true });
|
|
150
|
+
}));
|
|
151
|
+
const claude = resolve(home, "CLAUDE.md");
|
|
152
|
+
const claudeContents = await state(claude) === "missing" ? void 0 : await fs$1.readFile(claude, "utf8").catch((error) => {
|
|
153
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
|
|
154
|
+
throw error;
|
|
155
|
+
});
|
|
156
|
+
if (claudeContents === void 0 || claudeContents === agents || claudeContents === guide) await replaceLink(claude, "AGENTS.md");
|
|
157
|
+
else if (!editedPaths.has(claude)) {
|
|
158
|
+
console.warn(`${claude} was edited; Hitch left it in place.`);
|
|
159
|
+
editedPaths.add(claude);
|
|
160
|
+
}
|
|
161
|
+
await Promise.all(generated.map(async ({ skill, contents }) => {
|
|
162
|
+
const path = resolve(home, ".claude/skills", skill);
|
|
163
|
+
const kind = await state(path);
|
|
164
|
+
const target = `../../.agents/skills/${skill}`;
|
|
165
|
+
if (kind === "file") return;
|
|
166
|
+
if (kind === "link" && await fs$1.readlink(path) !== target) {
|
|
167
|
+
const current = await files(path).catch((error) => {
|
|
168
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
|
|
169
|
+
throw error;
|
|
170
|
+
});
|
|
171
|
+
if (current !== void 0 && (current.size !== contents.size || [...contents].some(([name, bytes]) => !current.get(name)?.equals(bytes)))) {
|
|
172
|
+
if (!editedPaths.has(path)) console.warn(`${path} was edited; Hitch left it in place.`);
|
|
173
|
+
editedPaths.add(path);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
await replaceLink(path, target, true);
|
|
178
|
+
}));
|
|
179
|
+
await fs$1.mkdir(dirname(inventoryPath), { recursive: true });
|
|
180
|
+
await writeChangedFile(inventoryPath, `${JSON.stringify(Object.fromEntries(Object.entries(inventory).sort(([a], [b]) => a.localeCompare(b))), null, 2)}\n`);
|
|
181
|
+
if (parent === void 0) return;
|
|
182
|
+
const paths = [
|
|
183
|
+
"AGENTS.md",
|
|
184
|
+
"CLAUDE.md",
|
|
185
|
+
...GENERATED_SKILLS.flatMap((skill) => [`.agents/skills/${skill}`, `.claude/skills/${skill}`])
|
|
186
|
+
];
|
|
187
|
+
for (const name of paths) {
|
|
188
|
+
const path = resolve(root, name);
|
|
189
|
+
const kind = await state(path);
|
|
190
|
+
const target = relative(dirname(path), resolve(home, name));
|
|
191
|
+
let equal = true;
|
|
192
|
+
if (kind === "file" || kind === "link" && existsSync(path)) {
|
|
193
|
+
if (name.endsWith(".md")) {
|
|
194
|
+
const current = await fs$1.readFile(path, "utf8");
|
|
195
|
+
equal = current === agents || current === guide;
|
|
196
|
+
} else {
|
|
197
|
+
const current = await files(path);
|
|
198
|
+
const expected = generated.find(({ skill }) => name.endsWith(`/${skill}`)).contents;
|
|
199
|
+
equal = current.size === expected.size && [...expected].every(([file, bytes]) => current.get(file)?.equals(bytes));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const action = agentFileAction({
|
|
203
|
+
child: true,
|
|
204
|
+
kind,
|
|
205
|
+
generated: equal,
|
|
206
|
+
dangling: kind === "link" && !existsSync(path),
|
|
207
|
+
correctLink: kind === "link" && await fs$1.readlink(path) === target
|
|
208
|
+
});
|
|
209
|
+
if (action === "edited") {
|
|
210
|
+
if (!editedPaths.has(path)) console.warn(`${path} was edited; Hitch left it in place.`);
|
|
211
|
+
editedPaths.add(path);
|
|
212
|
+
} else if (action === "link") await replaceLink(path, target, !name.endsWith(".md"));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
export { generatedAgentContents as n, writeGeneratedAgents as r, GENERATED_SKILLS as t };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { l as organizationInstanceUrl, p as resolveAuthForOrg, r as LoginRequiredError, t as AuthenticationError } from "./store-E5NhITHl.js";
|
|
2
|
+
// src/git-credential.ts
|
|
3
|
+
function parseGitCredentialHost(input, instanceUrl) {
|
|
4
|
+
const host = input.split(/\r?\n/).find((line) => line.startsWith("host="))?.slice(5);
|
|
5
|
+
if (host === void 0) throw new AuthenticationError("Git did not provide a host.");
|
|
6
|
+
const instance = new URL(instanceUrl);
|
|
7
|
+
const labels = instance.hostname.split(".");
|
|
8
|
+
const hostLabels = host.split(":")[0].split(".");
|
|
9
|
+
const orgCode = hostLabels[0];
|
|
10
|
+
if (labels[0] !== "app" || hostLabels.slice(1).join(".") !== labels.slice(1).join(".") || host.includes(":") && host.slice(host.lastIndexOf(":")) !== `:${instance.port}`) throw new AuthenticationError("Git requested credentials for a different Hitch host.");
|
|
11
|
+
if (new URL(organizationInstanceUrl(instanceUrl, orgCode)).host !== host) throw new AuthenticationError("Git requested credentials for a different Hitch host.");
|
|
12
|
+
return orgCode;
|
|
13
|
+
}
|
|
14
|
+
async function runGitCredential(action, instanceUrl) {
|
|
15
|
+
if (action !== "get" && action !== "store" && action !== "erase") throw new Error("Use applet git-credential <get|store|erase>.");
|
|
16
|
+
if (action !== "get") return;
|
|
17
|
+
let input = "";
|
|
18
|
+
for await (const chunk of process.stdin) input += String(chunk);
|
|
19
|
+
const orgCode = parseGitCredentialHost(input, instanceUrl);
|
|
20
|
+
const auth = await resolveAuthForOrg(instanceUrl, orgCode);
|
|
21
|
+
if (auth === void 0) throw new LoginRequiredError();
|
|
22
|
+
process.stdout.write(`username=hitch\npassword=${auth.accessToken}\n\n`);
|
|
23
|
+
}
|
|
24
|
+
export { runGitCredential };
|