@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.
Files changed (95) hide show
  1. package/dist/_internal/client.d.ts +0 -2
  2. package/dist/_internal/client.js +3 -5
  3. package/dist/_internal/log-context.d.ts +0 -2
  4. package/dist/_internal/log-context.js +1 -2
  5. package/dist/_internal/server.d.ts +2 -10
  6. package/dist/_internal/server.js +9 -14
  7. package/dist/applet.js +64 -23
  8. package/dist/auth-DuMRqSGe.js +49 -0
  9. package/dist/{batch-_ZjAg-Kk.js → batch-DwyWmiaE.js} +3 -4
  10. package/dist/build-C7hi2yg4.js +1 -0
  11. package/dist/{build-D47vK5aa.js → build-FAQSHJgm.js} +4 -3
  12. package/dist/{ci-BTFTCBgy.js → ci-oWlUJKm9.js} +5 -6
  13. package/dist/client/hitch/client.d.ts +1 -1
  14. package/dist/client/hitch/client.js +1 -2
  15. package/dist/client/hitch/phone.d.ts +1 -1
  16. package/dist/client/hitch/phone.js +1 -2
  17. package/dist/client/hitch.d.ts +2 -2
  18. package/dist/client/hitch.js +2 -2
  19. package/dist/client/react/markdown-editor.d.ts +1 -1
  20. package/dist/client/react/markdown-editor.js +1 -2
  21. package/dist/client/react/markdown.d.ts +1 -1
  22. package/dist/client/react/markdown.js +1 -2
  23. package/dist/client/react.d.ts +2 -2
  24. package/dist/client/react.js +2 -2
  25. package/dist/client.d.ts +2 -4
  26. package/dist/client.js +3 -5
  27. package/dist/{contract-CJv-n1l3.d.ts → contract-CUc0B2rl.d.ts} +1 -3
  28. package/dist/{contract-BeKz1Qcs.js → contract-D9LCNGjD.js} +1 -2
  29. package/dist/{create-C2UrZYSK.d.ts → create-BJqLT8Uq.d.ts} +0 -4
  30. package/dist/{deploy-BbqyK5Ik.js → deploy-BM55ZoSp.js} +160 -152
  31. package/dist/{device-BgIfytaR.js → device-CZWWckCq.js} +54 -34
  32. package/dist/{email-protocol-B9u_dh2p.d.ts → email-protocol-BWja_v7c.d.ts} +16 -16
  33. package/dist/generate-DG9vVkBO.js +1 -0
  34. package/dist/{generate-BLD0DoCk.js → generate-DNgO44RO.js} +32 -37
  35. package/dist/generated-agents-BUnJ0FQA.js +215 -0
  36. package/dist/git-credential-CU7-Erzs.js +24 -0
  37. package/dist/git-deploy-C12nMNB6.js +290 -0
  38. package/dist/git-deploy-CNz6mxiF.js +1 -0
  39. package/dist/git-migration-CIq-sN61.js +629 -0
  40. package/dist/git-safety-Ck3X7jvA.js +13 -0
  41. package/dist/{headers-CeRX-Xji.js → headers-BcEMIVCo.js} +1 -2
  42. package/dist/{hitch-client-Cw-WZ_8v.js → hitch-client-CNN-dU6d.js} +5 -7
  43. package/dist/{hitch-client-DtyTZzP5.d.ts → hitch-client-k7_jIjPw.d.ts} +5 -7
  44. package/dist/{hitch-file-url-BPKj9zVG.js → hitch-file-url--AMjDOzP.js} +1 -2
  45. package/dist/index.d.ts +13 -17
  46. package/dist/index.js +33 -38
  47. package/dist/{init-BKUBf6i9.js → init-BD5mC_9L.js} +70 -18
  48. package/dist/{lazy-client-CwIzYAoE.js → lazy-client--QCL0wiu.js} +1 -2
  49. package/dist/{load-config-DGALUExv.js → load-config-Cffvj-aM.js} +24 -26
  50. package/dist/{log-context-DWznGjfz.js → log-context-BepwdjrR.js} +1 -2
  51. package/dist/login-BWZKo7Ui.js +21 -0
  52. package/dist/{logs-Cv5z1e2w.js → logs-glCVHI-8.js} +6 -6
  53. package/dist/{manifest-BBHD_EY9.d.ts → manifest-CpghlaJc.d.ts} +6 -7
  54. package/dist/manifest-patterns-BfxqImlp.js +4 -0
  55. package/dist/{markdown-CwlqzBtP.js → markdown-BA_XzFxq.js} +2 -3
  56. package/dist/{markdown-DSHOQIOb.d.ts → markdown-CnB35mjc.d.ts} +1 -3
  57. package/dist/{markdown-editor-C5mLHGqu.js → markdown-editor-CaUuphfc.js} +3 -5
  58. package/dist/{markdown-editor-BmEaBzd7.d.ts → markdown-editor-xF3uATBp.d.ts} +1 -5
  59. package/dist/parent-D52Kxp8U.js +1 -0
  60. package/dist/parent-Zx8Eg1Ki.js +75 -0
  61. package/dist/{project-CrxdZR0B.js → project-DZGk765E.js} +63 -54
  62. package/dist/{prompt-ChS-grYO.js → prompt-CW98R-Un.js} +1 -2
  63. package/dist/{query-cache-CXmAyLv3.js → query-cache-DQJy45RT.js} +1 -2
  64. package/dist/{query-utils-zz9pVjgp.d.ts → query-utils-okxIoKM3.d.ts} +0 -2
  65. package/dist/{schedules-Dajgni_z.js → schedules-CSUb84e2.js} +5 -5
  66. package/dist/server.d.ts +5 -13
  67. package/dist/server.js +17 -20
  68. package/dist/source-hash-BbvtRaus.js +107 -0
  69. package/dist/store-E5NhITHl.js +448 -0
  70. package/dist/{upload-DRbVhuDm.js → upload-D1mzpsSk.js} +4 -6
  71. package/dist/{upload-D_kkmne_.d.ts → upload-wp-Ilsv6.d.ts} +6 -10
  72. package/dist/{use-phone-ug4B5gQp.js → use-phone-CB_idmrz.js} +9 -13
  73. package/dist/{use-phone-M7c_HsB7.d.ts → use-phone-DBAkasPq.d.ts} +0 -4
  74. package/dist/{variables-B-CLu8cY.js → variables-CgZstC7I.js} +7 -8
  75. package/dist/vite.d.ts +1 -3
  76. package/dist/vite.js +41 -50
  77. package/dist/{workflow-DurM6Fwx.d.ts → workflow-BnBrJIzu.d.ts} +0 -2
  78. package/dist/{workflow-engine-BOTzURKM.js → workflow-engine-CyyaVENo.js} +2 -4
  79. package/dist/{workflow-CTo2kZF1.js → workflow-l2SlVePB.js} +2 -4
  80. package/dist/workspace-CtIKSgMD.js +76 -0
  81. package/package.json +6 -5
  82. package/scaffold/.agents/skills/hitch-applets/SKILL.md +27 -9
  83. package/scaffold/.agents/skills/hitch-applets/references/email-tracking.md +4 -4
  84. package/scaffold/.agents/skills/hitch-applets/references/files.md +2 -2
  85. package/scaffold/.agents/skills/hitch-applets/references/manifest.md +8 -6
  86. package/scaffold/.agents/skills/hitch-applets/references/performance.md +2 -2
  87. package/scaffold/.agents/skills/hitch-applets/references/records.md +8 -8
  88. package/scaffold/.agents/skills/hitch-cli/SKILL.md +52 -43
  89. package/scaffold/AGENTS.md +6 -0
  90. package/dist/auth-D3CrCtZq.js +0 -21
  91. package/dist/build-JtbY8q2p.js +0 -2
  92. package/dist/generate-COCRy1Bs.js +0 -2
  93. package/dist/login-CceGvlMi.js +0 -14
  94. package/dist/store-B8N_8JIN.js +0 -196
  95. 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
- id: string;
12
+ trackerId: string;
14
13
  };
15
14
  type MarkEmailTrackerSentInput = {
16
- id: string;
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<HitchEmailIdInput, HitchEmailIdInput>, Schema<HitchEmailThread, HitchEmailThread>, Record<never, never>, Meta>;
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<HitchEmailIdInput, HitchEmailIdInput>, Schema<HitchEmailMessage, HitchEmailMessage>, Record<never, never>, Meta>;
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<HitchEmailIdInput, HitchEmailIdInput>, Schema<HitchEmailRawOutput, HitchEmailRawOutput>, Record<never, never>, Meta>;
53
+ raw: ContractProcedure<Schema<HitchEmailMessageInput, HitchEmailMessageInput>, Schema<HitchEmailRawOutput, HitchEmailRawOutput>, Record<never, never>, Meta>;
55
54
  };
56
55
  attachments: {
57
- get: ContractProcedure<Schema<HitchEmailIdInput, HitchEmailIdInput>, Schema<HitchEmailAttachmentOutput, HitchEmailAttachmentOutput>, Record<never, never>, Meta>;
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 HitchEmailIdInput = {
156
- id: string;
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({ id: messageId }). */
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({ id: messageId }). */
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 { a as organizationInstanceUrl, c as resolveInstanceUrl } from "./store-B8N_8JIN.js";
2
- import { t as fetchWithOrgAuth } from "./auth-D3CrCtZq.js";
3
- import { t as loadAppletConfig } from "./load-config-DGALUExv.js";
4
- import { a as userAgent, r as prepareAppletProject } from "./project-CrxdZR0B.js";
5
- import { i as loadGitHubActionsBuildInputs, n as githubActionsContext, r as hitchResponseError } from "./ci-BTFTCBgy.js";
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
- //#region src/generated.ts
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
- //#endregion
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
- //#endregion
75
- //#region src/typegen/operations.ts
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:{id}": "get",
85
- "get:{id}/history": "history",
86
- "patch:{id}": "update",
87
- "delete:{id}": "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 === "batch") return void 0;
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] === "batch" ? void 0 : 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 && create[1] !== "batch") return {
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}/{id}`;
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
- //#endregion
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
- //#endregion
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
- //#endregion
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
- //#endregion
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("./.hitch");
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("./.hitch.tmp-"));
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 };