@axintai/compiler 0.3.0 → 0.3.2

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/cli/index.js CHANGED
@@ -1163,6 +1163,142 @@ var init_compiler = __esm({
1163
1163
  }
1164
1164
  });
1165
1165
 
1166
+ // src/core/format.ts
1167
+ var format_exports = {};
1168
+ __export(format_exports, {
1169
+ SWIFT_FORMAT_CONFIG: () => SWIFT_FORMAT_CONFIG,
1170
+ formatSwift: () => formatSwift
1171
+ });
1172
+ import { spawn } from "child_process";
1173
+ import { writeFile, unlink } from "fs/promises";
1174
+ import { join } from "path";
1175
+ import { tmpdir } from "os";
1176
+ async function formatSwift(source, options = {}) {
1177
+ const available = await hasSwiftFormat();
1178
+ if (!available) {
1179
+ if (options.strict) {
1180
+ throw new Error(
1181
+ "swift-format not found on $PATH. Install Xcode + Command Line Tools, or drop --format."
1182
+ );
1183
+ }
1184
+ return {
1185
+ formatted: source,
1186
+ ran: false,
1187
+ reason: "swift-format not found on $PATH"
1188
+ };
1189
+ }
1190
+ const configPath = join(
1191
+ tmpdir(),
1192
+ `axint-swift-format-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
1193
+ );
1194
+ await writeFile(configPath, JSON.stringify(SWIFT_FORMAT_CONFIG, null, 2));
1195
+ try {
1196
+ const result = await runSwiftFormat(source, configPath, options.timeoutMs ?? 8e3);
1197
+ if (result.code === 0) {
1198
+ return { formatted: result.stdout, ran: true };
1199
+ }
1200
+ if (options.strict) {
1201
+ throw new Error(`swift-format failed: ${result.stderr}`);
1202
+ }
1203
+ return {
1204
+ formatted: source,
1205
+ ran: false,
1206
+ reason: `swift-format exited ${result.code}: ${result.stderr}`
1207
+ };
1208
+ } finally {
1209
+ await unlink(configPath).catch(() => void 0);
1210
+ }
1211
+ }
1212
+ function hasSwiftFormat() {
1213
+ return new Promise((resolve3) => {
1214
+ const child = spawn("swift-format", ["--version"], { stdio: "pipe" });
1215
+ child.on("error", () => resolve3(false));
1216
+ child.on("exit", (code) => resolve3(code === 0));
1217
+ });
1218
+ }
1219
+ function runSwiftFormat(source, configPath, timeoutMs) {
1220
+ return new Promise((resolve3) => {
1221
+ const child = spawn("swift-format", ["format", "--configuration", configPath], {
1222
+ stdio: ["pipe", "pipe", "pipe"]
1223
+ });
1224
+ let stdout = "";
1225
+ let stderr = "";
1226
+ child.stdout?.on("data", (d) => stdout += d.toString());
1227
+ child.stderr?.on("data", (d) => stderr += d.toString());
1228
+ const timer = setTimeout(() => {
1229
+ child.kill("SIGKILL");
1230
+ resolve3({
1231
+ stdout,
1232
+ stderr: stderr + `
1233
+ [format] killed after ${timeoutMs}ms`,
1234
+ code: 124
1235
+ });
1236
+ }, timeoutMs);
1237
+ child.on("exit", (code) => {
1238
+ clearTimeout(timer);
1239
+ resolve3({ stdout, stderr, code: code ?? 1 });
1240
+ });
1241
+ child.stdin?.write(source);
1242
+ child.stdin?.end();
1243
+ });
1244
+ }
1245
+ var SWIFT_FORMAT_CONFIG;
1246
+ var init_format = __esm({
1247
+ "src/core/format.ts"() {
1248
+ "use strict";
1249
+ SWIFT_FORMAT_CONFIG = {
1250
+ version: 1,
1251
+ lineLength: 100,
1252
+ indentation: { spaces: 4 },
1253
+ tabWidth: 4,
1254
+ maximumBlankLines: 1,
1255
+ respectsExistingLineBreaks: true,
1256
+ lineBreakBeforeControlFlowKeywords: false,
1257
+ lineBreakBeforeEachArgument: false,
1258
+ lineBreakBeforeEachGenericRequirement: false,
1259
+ prioritizeKeepingFunctionOutputTogether: false,
1260
+ indentConditionalCompilationBlocks: true,
1261
+ lineBreakAroundMultilineExpressionChainComponents: false,
1262
+ fileScopedDeclarationPrivacy: { accessLevel: "private" },
1263
+ rules: {
1264
+ AllPublicDeclarationsHaveDocumentation: false,
1265
+ AlwaysUseLowerCamelCase: true,
1266
+ AmbiguousTrailingClosureOverload: true,
1267
+ BeginDocumentationCommentWithOneLineSummary: false,
1268
+ DoNotUseSemicolons: true,
1269
+ DontRepeatTypeInStaticProperties: true,
1270
+ FileScopedDeclarationPrivacy: true,
1271
+ FullyIndirectEnum: true,
1272
+ GroupNumericLiterals: true,
1273
+ IdentifiersMustBeASCII: true,
1274
+ NeverForceUnwrap: false,
1275
+ NeverUseForceTry: false,
1276
+ NeverUseImplicitlyUnwrappedOptionals: false,
1277
+ NoBlockComments: false,
1278
+ NoCasesWithOnlyFallthrough: true,
1279
+ NoEmptyTrailingClosureParentheses: true,
1280
+ NoLabelsInCasePatterns: true,
1281
+ NoLeadingUnderscores: false,
1282
+ NoParensAroundConditions: true,
1283
+ NoVoidReturnOnFunctionSignature: true,
1284
+ OneCasePerLine: true,
1285
+ OneVariableDeclarationPerLine: true,
1286
+ OnlyOneTrailingClosureArgument: true,
1287
+ OrderedImports: true,
1288
+ ReturnVoidInsteadOfEmptyTuple: true,
1289
+ UseEarlyExits: false,
1290
+ UseLetInEveryBoundCaseVariable: true,
1291
+ UseShorthandTypeNames: true,
1292
+ UseSingleLinePropertyGetter: true,
1293
+ UseSynthesizedInitializer: true,
1294
+ UseTripleSlashForDocumentationComments: true,
1295
+ UseWhereClausesInForLoops: false,
1296
+ ValidateDocumentationComments: false
1297
+ }
1298
+ };
1299
+ }
1300
+ });
1301
+
1166
1302
  // src/templates/index.ts
1167
1303
  function getTemplate(id) {
1168
1304
  return TEMPLATES.find((t) => t.id === id);
@@ -1525,142 +1661,6 @@ export default defineIntent({
1525
1661
  }
1526
1662
  });
1527
1663
 
1528
- // src/core/format.ts
1529
- var format_exports = {};
1530
- __export(format_exports, {
1531
- SWIFT_FORMAT_CONFIG: () => SWIFT_FORMAT_CONFIG,
1532
- formatSwift: () => formatSwift
1533
- });
1534
- import { spawn as spawn2 } from "child_process";
1535
- import { writeFile as writeFile2, unlink } from "fs/promises";
1536
- import { join as join2 } from "path";
1537
- import { tmpdir } from "os";
1538
- async function formatSwift(source, options = {}) {
1539
- const available = await hasSwiftFormat();
1540
- if (!available) {
1541
- if (options.strict) {
1542
- throw new Error(
1543
- "swift-format not found on $PATH. Install Xcode + Command Line Tools, or drop --format."
1544
- );
1545
- }
1546
- return {
1547
- formatted: source,
1548
- ran: false,
1549
- reason: "swift-format not found on $PATH"
1550
- };
1551
- }
1552
- const configPath = join2(
1553
- tmpdir(),
1554
- `axint-swift-format-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
1555
- );
1556
- await writeFile2(configPath, JSON.stringify(SWIFT_FORMAT_CONFIG, null, 2));
1557
- try {
1558
- const result = await runSwiftFormat(source, configPath, options.timeoutMs ?? 8e3);
1559
- if (result.code === 0) {
1560
- return { formatted: result.stdout, ran: true };
1561
- }
1562
- if (options.strict) {
1563
- throw new Error(`swift-format failed: ${result.stderr}`);
1564
- }
1565
- return {
1566
- formatted: source,
1567
- ran: false,
1568
- reason: `swift-format exited ${result.code}: ${result.stderr}`
1569
- };
1570
- } finally {
1571
- await unlink(configPath).catch(() => void 0);
1572
- }
1573
- }
1574
- function hasSwiftFormat() {
1575
- return new Promise((resolve3) => {
1576
- const child = spawn2("swift-format", ["--version"], { stdio: "pipe" });
1577
- child.on("error", () => resolve3(false));
1578
- child.on("exit", (code) => resolve3(code === 0));
1579
- });
1580
- }
1581
- function runSwiftFormat(source, configPath, timeoutMs) {
1582
- return new Promise((resolve3) => {
1583
- const child = spawn2("swift-format", ["format", "--configuration", configPath], {
1584
- stdio: ["pipe", "pipe", "pipe"]
1585
- });
1586
- let stdout = "";
1587
- let stderr = "";
1588
- child.stdout?.on("data", (d) => stdout += d.toString());
1589
- child.stderr?.on("data", (d) => stderr += d.toString());
1590
- const timer = setTimeout(() => {
1591
- child.kill("SIGKILL");
1592
- resolve3({
1593
- stdout,
1594
- stderr: stderr + `
1595
- [format] killed after ${timeoutMs}ms`,
1596
- code: 124
1597
- });
1598
- }, timeoutMs);
1599
- child.on("exit", (code) => {
1600
- clearTimeout(timer);
1601
- resolve3({ stdout, stderr, code: code ?? 1 });
1602
- });
1603
- child.stdin?.write(source);
1604
- child.stdin?.end();
1605
- });
1606
- }
1607
- var SWIFT_FORMAT_CONFIG;
1608
- var init_format = __esm({
1609
- "src/core/format.ts"() {
1610
- "use strict";
1611
- SWIFT_FORMAT_CONFIG = {
1612
- version: 1,
1613
- lineLength: 100,
1614
- indentation: { spaces: 4 },
1615
- tabWidth: 4,
1616
- maximumBlankLines: 1,
1617
- respectsExistingLineBreaks: true,
1618
- lineBreakBeforeControlFlowKeywords: false,
1619
- lineBreakBeforeEachArgument: false,
1620
- lineBreakBeforeEachGenericRequirement: false,
1621
- prioritizeKeepingFunctionOutputTogether: false,
1622
- indentConditionalCompilationBlocks: true,
1623
- lineBreakAroundMultilineExpressionChainComponents: false,
1624
- fileScopedDeclarationPrivacy: { accessLevel: "private" },
1625
- rules: {
1626
- AllPublicDeclarationsHaveDocumentation: false,
1627
- AlwaysUseLowerCamelCase: true,
1628
- AmbiguousTrailingClosureOverload: true,
1629
- BeginDocumentationCommentWithOneLineSummary: false,
1630
- DoNotUseSemicolons: true,
1631
- DontRepeatTypeInStaticProperties: true,
1632
- FileScopedDeclarationPrivacy: true,
1633
- FullyIndirectEnum: true,
1634
- GroupNumericLiterals: true,
1635
- IdentifiersMustBeASCII: true,
1636
- NeverForceUnwrap: false,
1637
- NeverUseForceTry: false,
1638
- NeverUseImplicitlyUnwrappedOptionals: false,
1639
- NoBlockComments: false,
1640
- NoCasesWithOnlyFallthrough: true,
1641
- NoEmptyTrailingClosureParentheses: true,
1642
- NoLabelsInCasePatterns: true,
1643
- NoLeadingUnderscores: false,
1644
- NoParensAroundConditions: true,
1645
- NoVoidReturnOnFunctionSignature: true,
1646
- OneCasePerLine: true,
1647
- OneVariableDeclarationPerLine: true,
1648
- OnlyOneTrailingClosureArgument: true,
1649
- OrderedImports: true,
1650
- ReturnVoidInsteadOfEmptyTuple: true,
1651
- UseEarlyExits: false,
1652
- UseLetInEveryBoundCaseVariable: true,
1653
- UseShorthandTypeNames: true,
1654
- UseSingleLinePropertyGetter: true,
1655
- UseSynthesizedInitializer: true,
1656
- UseTripleSlashForDocumentationComments: true,
1657
- UseWhereClausesInForLoops: false,
1658
- ValidateDocumentationComments: false
1659
- }
1660
- };
1661
- }
1662
- });
1663
-
1664
1664
  // src/core/sandbox.ts
1665
1665
  var sandbox_exports = {};
1666
1666
  __export(sandbox_exports, {
@@ -2077,13 +2077,22 @@ var init_server = __esm({
2077
2077
  // src/cli/index.ts
2078
2078
  init_compiler();
2079
2079
  import { Command } from "commander";
2080
- import { readFileSync as readFileSync3, writeFileSync, mkdirSync, existsSync as existsSync3 } from "fs";
2080
+ import {
2081
+ readFileSync as readFileSync3,
2082
+ writeFileSync,
2083
+ mkdirSync,
2084
+ existsSync as existsSync3,
2085
+ watch as fsWatch,
2086
+ statSync
2087
+ } from "fs";
2081
2088
  import { resolve as resolve2, dirname as dirname2, basename } from "path";
2089
+ import { spawn as spawn4 } from "child_process";
2082
2090
  import { fileURLToPath as fileURLToPath2 } from "url";
2083
2091
 
2084
2092
  // src/core/eject.ts
2085
2093
  init_compiler();
2086
- function ejectIntent(source, fileName, options = {}) {
2094
+ init_format();
2095
+ async function ejectIntent(source, fileName, options = {}) {
2087
2096
  const compileResult = compileSource(source, fileName, {
2088
2097
  validate: true,
2089
2098
  emitInfoPlist: true,
@@ -2096,7 +2105,11 @@ function ejectIntent(source, fileName, options = {}) {
2096
2105
  }
2097
2106
  const { ir, swiftCode, infoPlistFragment, entitlementsFragment } = compileResult.output;
2098
2107
  const outDir = options.outDir ?? ".";
2099
- const ejectedSwift = transformSwiftForEject(swiftCode, ir);
2108
+ let ejectedSwift = transformSwiftForEject(swiftCode, ir);
2109
+ if (options.format) {
2110
+ const { formatted, ran } = await formatSwift(ejectedSwift);
2111
+ if (ran) ejectedSwift = formatted;
2112
+ }
2100
2113
  const intentFileName = `${ir.name}Intent.swift`;
2101
2114
  const swiftPath = `${outDir}/${intentFileName}`;
2102
2115
  const plistPath = infoPlistFragment ? `${outDir}/${ir.name}Intent.plist.fragment.xml` : null;
@@ -2153,12 +2166,8 @@ function transformSwiftForEject(swiftCode, ir) {
2153
2166
  if (line.includes("// TODO: Implement your intent logic here.")) {
2154
2167
  result.push(` // TODO: Implement your intent logic here.`);
2155
2168
  result.push(` //`);
2156
- result.push(
2157
- ` // For more information about App Intents, see:`
2158
- );
2159
- result.push(
2160
- ` // https://developer.apple.com/documentation/appintents`
2161
- );
2169
+ result.push(` // For more information about App Intents, see:`);
2170
+ result.push(` // https://developer.apple.com/documentation/appintents`);
2162
2171
  } else {
2163
2172
  result.push(line);
2164
2173
  }
@@ -2195,10 +2204,10 @@ function generateTestFile(ir) {
2195
2204
 
2196
2205
  // src/cli/scaffold.ts
2197
2206
  init_templates();
2198
- import { mkdir, writeFile, readdir } from "fs/promises";
2207
+ import { mkdir, writeFile as writeFile2, readdir } from "fs/promises";
2199
2208
  import { existsSync } from "fs";
2200
- import { join, relative } from "path";
2201
- import { spawn } from "child_process";
2209
+ import { join as join2, relative } from "path";
2210
+ import { spawn as spawn2 } from "child_process";
2202
2211
  async function scaffoldProject(opts) {
2203
2212
  const { targetDir, projectName, template, version, install } = opts;
2204
2213
  const tpl = getTemplate(template);
@@ -2220,8 +2229,8 @@ async function scaffoldProject(opts) {
2220
2229
  }
2221
2230
  const files = [];
2222
2231
  const write = async (rel, content) => {
2223
- const abs = join(targetDir, rel);
2224
- await mkdir(join(abs, "..").replace(/[/\\][^/\\]+$/, ""), { recursive: true }).catch(
2232
+ const abs = join2(targetDir, rel);
2233
+ await mkdir(join2(abs, "..").replace(/[/\\][^/\\]+$/, ""), { recursive: true }).catch(
2225
2234
  () => void 0
2226
2235
  );
2227
2236
  const parent = abs.substring(
@@ -2231,7 +2240,7 @@ async function scaffoldProject(opts) {
2231
2240
  if (parent && parent !== abs) {
2232
2241
  await mkdir(parent, { recursive: true }).catch(() => void 0);
2233
2242
  }
2234
- await writeFile(abs, content, "utf-8");
2243
+ await writeFile2(abs, content, "utf-8");
2235
2244
  files.push(relative(targetDir, abs));
2236
2245
  };
2237
2246
  await write(
@@ -2299,7 +2308,7 @@ async function scaffoldProject(opts) {
2299
2308
  ) + "\n"
2300
2309
  );
2301
2310
  await write("README.md", scaffoldReadme(projectName, template, tpl.title, version));
2302
- await mkdir(join(targetDir, "ios", "Intents"), { recursive: true });
2311
+ await mkdir(join2(targetDir, "ios", "Intents"), { recursive: true });
2303
2312
  await write("ios/Intents/.gitkeep", "");
2304
2313
  if (install) {
2305
2314
  await runNpmInstall(targetDir);
@@ -2343,7 +2352,7 @@ Any agent that supports MCP can now call \`axint_compile\`, \`axint_validate\`,
2343
2352
  - Edit \`intents/${template}.ts\` \u2014 this is your App Intent source of truth.
2344
2353
  - Add more intents in the \`intents/\` folder.
2345
2354
  - Run \`axint templates\` to see every bundled starter.
2346
- - Read the docs at https://axint.ai/docs
2355
+ - Read the docs at https://github.com/agenticempire/axint#readme
2347
2356
 
2348
2357
  ---
2349
2358
 
@@ -2352,7 +2361,7 @@ _Generated by \`axint init\`_
2352
2361
  }
2353
2362
  function runNpmInstall(cwd) {
2354
2363
  return new Promise((resolve3, reject) => {
2355
- const child = spawn("npm", ["install"], { cwd, stdio: "inherit" });
2364
+ const child = spawn2("npm", ["install"], { cwd, stdio: "inherit" });
2356
2365
  child.on("exit", (code) => {
2357
2366
  if (code === 0) resolve3();
2358
2367
  else reject(new Error(`npm install exited with code ${code}`));
@@ -2406,7 +2415,9 @@ program.command("init").description("Scaffold a new Axint project (zero-config,
2406
2415
  );
2407
2416
  }
2408
2417
  console.log();
2409
- console.log(` \x1B[2mDocs: https://axint.ai/docs\x1B[0m`);
2418
+ console.log(
2419
+ ` \x1B[2mDocs: https://github.com/agenticempire/axint#readme\x1B[0m`
2420
+ );
2410
2421
  console.log(
2411
2422
  ` \x1B[2mMCP: npx axint-mcp (add to Claude Code, Cursor, Windsurf)\x1B[0m`
2412
2423
  );
@@ -2654,7 +2665,7 @@ program.command("eject").description("Eject an intent to standalone Swift with n
2654
2665
  console.error(`\x1B[31merror:\x1B[0m Cannot read file: ${filePath}`);
2655
2666
  process.exit(1);
2656
2667
  }
2657
- const result = ejectIntent(source, basename(filePath), {
2668
+ const result = await ejectIntent(source, basename(filePath), {
2658
2669
  outDir: options.out,
2659
2670
  includeTests: options.includeTests,
2660
2671
  format: options.format
@@ -2731,7 +2742,7 @@ program.command("templates").description("List bundled intent templates").argume
2731
2742
  program.command("login").description("Authenticate with the Axint Registry via GitHub").action(async () => {
2732
2743
  const { homedir } = await import("os");
2733
2744
  const { join: join4 } = await import("path");
2734
- const { spawn: spawn4 } = await import("child_process");
2745
+ const { spawn: spawn5 } = await import("child_process");
2735
2746
  const configDir = join4(homedir(), ".axint");
2736
2747
  const credPath = join4(configDir, "credentials.json");
2737
2748
  const registryUrl = process.env.AXINT_REGISTRY_URL ?? "https://registry.axint.ai";
@@ -2760,7 +2771,7 @@ program.command("login").description("Authenticate with the Axint Registry via G
2760
2771
  console.log(` \x1B[2mWaiting for authorization\u2026\x1B[0m`);
2761
2772
  try {
2762
2773
  const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
2763
- spawn4(openCmd, [verification_uri], { stdio: "ignore", detached: true }).unref();
2774
+ spawn5(openCmd, [verification_uri], { stdio: "ignore", detached: true }).unref();
2764
2775
  } catch {
2765
2776
  }
2766
2777
  const pollInterval = (interval ?? 5) * 1e3;
@@ -3006,6 +3017,302 @@ program.command("add").description("Install a template from the Axint Registry")
3006
3017
  process.exit(1);
3007
3018
  }
3008
3019
  });
3020
+ program.command("search").description("Search the Axint Registry for intent templates").argument("[query]", "Search term (lists popular packages if omitted)").option("--limit <n>", "Max results", "20").option("--json", "Output as JSON").action(
3021
+ async (query, options) => {
3022
+ const registryUrl = process.env.AXINT_REGISTRY_URL ?? "https://registry.axint.ai";
3023
+ const limit = Math.max(1, Math.min(100, parseInt(options.limit, 10) || 20));
3024
+ console.log();
3025
+ if (!options.json) {
3026
+ console.log(
3027
+ ` \x1B[38;5;208m\u25C6\x1B[0m \x1B[1mAxint\x1B[0m \xB7 search ${query ? `"${query}"` : ""}`
3028
+ );
3029
+ console.log();
3030
+ }
3031
+ try {
3032
+ const params = new URLSearchParams({ limit: String(limit) });
3033
+ if (query) params.set("q", query);
3034
+ const res = await fetch(`${registryUrl}/api/v1/search?${params}`, {
3035
+ headers: { "X-Axint-Version": VERSION }
3036
+ });
3037
+ if (!res.ok) {
3038
+ console.error(`\x1B[31merror:\x1B[0m Search failed (HTTP ${res.status})`);
3039
+ process.exit(1);
3040
+ }
3041
+ const data = await res.json();
3042
+ if (options.json) {
3043
+ console.log(JSON.stringify(data, null, 2));
3044
+ return;
3045
+ }
3046
+ if (data.results.length === 0) {
3047
+ console.log(` No packages found`);
3048
+ console.log();
3049
+ return;
3050
+ }
3051
+ for (const pkg3 of data.results) {
3052
+ const downloads = pkg3.downloads > 0 ? `\u25BC ${pkg3.downloads}` : "";
3053
+ const dl = downloads ? ` \x1B[2m${downloads}\x1B[0m` : "";
3054
+ console.log(
3055
+ ` \x1B[38;5;208m\u25C6\x1B[0m ${pkg3.package_name.padEnd(30)} ${pkg3.description.substring(0, 35).padEnd(35)}${dl}`
3056
+ );
3057
+ }
3058
+ console.log();
3059
+ console.log(
3060
+ ` ${data.results.length} package${data.results.length === 1 ? "" : "s"} found`
3061
+ );
3062
+ console.log();
3063
+ console.log(
3064
+ ` \x1B[2mInstall:\x1B[0m axint add ${data.results[0]?.package_name ?? "@namespace/slug"}`
3065
+ );
3066
+ console.log();
3067
+ } catch (err) {
3068
+ console.error(`\x1B[31merror:\x1B[0m ${err.message ?? err}`);
3069
+ process.exit(1);
3070
+ }
3071
+ }
3072
+ );
3073
+ async function runSwiftBuild2(projectPath) {
3074
+ return new Promise((resolve3) => {
3075
+ const t0 = performance.now();
3076
+ const proc = spawn4("swift", ["build"], {
3077
+ cwd: projectPath,
3078
+ stdio: ["ignore", "inherit", "inherit"]
3079
+ });
3080
+ proc.on("close", (code) => {
3081
+ if (code === 0) {
3082
+ const dt = (performance.now() - t0).toFixed(0);
3083
+ console.log();
3084
+ console.log(`\x1B[38;5;208m\u2500 swift build\x1B[0m`);
3085
+ console.log(`\x1B[32m\u2713\x1B[0m Build succeeded \x1B[90m(${dt}ms)\x1B[0m`);
3086
+ console.log();
3087
+ resolve3(true);
3088
+ } else {
3089
+ console.log();
3090
+ console.log(`\x1B[38;5;208m\u2500 swift build\x1B[0m`);
3091
+ console.log(`\x1B[31m\u2717\x1B[0m Build failed (exit code: ${code})`);
3092
+ console.log("\x1B[90mContinuing to watch for changes\u2026\x1B[0m");
3093
+ console.log();
3094
+ resolve3(false);
3095
+ }
3096
+ });
3097
+ proc.on("error", (err) => {
3098
+ console.log();
3099
+ console.log(`\x1B[38;5;208m\u2500 swift build\x1B[0m`);
3100
+ console.error(`\x1B[31m\u2717\x1B[0m Error: ${err.message}`);
3101
+ console.log("\x1B[90mContinuing to watch for changes\u2026\x1B[0m");
3102
+ console.log();
3103
+ resolve3(false);
3104
+ });
3105
+ });
3106
+ }
3107
+ program.command("watch").description("Watch intent files and recompile on change").argument("<file>", "Path to a TypeScript intent file or directory of intents").option("-o, --out <dir>", "Output directory for generated Swift", ".").option("--no-validate", "Skip validation of generated Swift").option("--emit-info-plist", "Emit Info.plist fragments alongside Swift files").option("--emit-entitlements", "Emit entitlements fragments alongside Swift files").option("--format", "Pipe generated Swift through swift-format").option(
3108
+ "--strict-format",
3109
+ "Fail if swift-format is missing or errors (implies --format)"
3110
+ ).option(
3111
+ "--swift-build",
3112
+ "Run `swift build` in the project after successful compilation"
3113
+ ).option(
3114
+ "--swift-project <path>",
3115
+ "Path to the Swift project root (defaults to --out parent directory)"
3116
+ ).action(
3117
+ async (file, options) => {
3118
+ const target = resolve2(file);
3119
+ const isDir = existsSync3(target) && statSync(target).isDirectory();
3120
+ const filesToWatch = [];
3121
+ if (isDir) {
3122
+ const { readdirSync } = await import("fs");
3123
+ for (const entry of readdirSync(target)) {
3124
+ if (entry.endsWith(".ts") && !entry.endsWith(".d.ts")) {
3125
+ filesToWatch.push(resolve2(target, entry));
3126
+ }
3127
+ }
3128
+ if (filesToWatch.length === 0) {
3129
+ console.error(`\x1B[31merror:\x1B[0m No .ts files found in ${target}`);
3130
+ process.exit(1);
3131
+ }
3132
+ } else {
3133
+ if (!existsSync3(target)) {
3134
+ console.error(`\x1B[31merror:\x1B[0m File not found: ${target}`);
3135
+ process.exit(1);
3136
+ }
3137
+ filesToWatch.push(target);
3138
+ }
3139
+ const swiftProjectPath = options.swiftProject ?? dirname2(resolve2(options.out));
3140
+ function compileOne(filePath) {
3141
+ const t0 = performance.now();
3142
+ const result = compileFile(filePath, {
3143
+ outDir: options.out,
3144
+ validate: options.validate,
3145
+ emitInfoPlist: options.emitInfoPlist,
3146
+ emitEntitlements: options.emitEntitlements
3147
+ });
3148
+ for (const d of result.diagnostics) {
3149
+ const prefix = d.severity === "error" ? "\x1B[31merror\x1B[0m" : d.severity === "warning" ? "\x1B[33mwarning\x1B[0m" : "\x1B[36minfo\x1B[0m";
3150
+ console.error(` ${prefix}[${d.code}]: ${d.message}`);
3151
+ if (d.file) console.error(` --> ${d.file}${d.line ? `:${d.line}` : ""}`);
3152
+ if (d.suggestion) console.error(` = help: ${d.suggestion}`);
3153
+ }
3154
+ if (!result.success || !result.output) {
3155
+ const errors = result.diagnostics.filter((d) => d.severity === "error").length;
3156
+ console.error(`\x1B[31m\u2717\x1B[0m ${basename(filePath)} \u2014 ${errors} error(s)`);
3157
+ return false;
3158
+ }
3159
+ const swiftCode = result.output.swiftCode;
3160
+ if (options.format || options.strictFormat) {
3161
+ }
3162
+ const outPath = resolve2(result.output.outputPath);
3163
+ mkdirSync(dirname2(outPath), { recursive: true });
3164
+ writeFileSync(outPath, swiftCode, "utf-8");
3165
+ if (options.emitInfoPlist && result.output.infoPlistFragment) {
3166
+ const plistPath = outPath.replace(/\.swift$/, ".plist.fragment.xml");
3167
+ writeFileSync(plistPath, result.output.infoPlistFragment, "utf-8");
3168
+ }
3169
+ if (options.emitEntitlements && result.output.entitlementsFragment) {
3170
+ const entPath = outPath.replace(/\.swift$/, ".entitlements.fragment.xml");
3171
+ writeFileSync(entPath, result.output.entitlementsFragment, "utf-8");
3172
+ }
3173
+ const dt = (performance.now() - t0).toFixed(1);
3174
+ console.log(
3175
+ `\x1B[32m\u2713\x1B[0m ${result.output.ir.name} \u2192 ${outPath} \x1B[90m(${dt}ms)\x1B[0m`
3176
+ );
3177
+ return true;
3178
+ }
3179
+ async function compileWithFormat(filePath) {
3180
+ if (!options.format && !options.strictFormat) {
3181
+ return compileOne(filePath);
3182
+ }
3183
+ const t0 = performance.now();
3184
+ const result = compileFile(filePath, {
3185
+ outDir: options.out,
3186
+ validate: options.validate,
3187
+ emitInfoPlist: options.emitInfoPlist,
3188
+ emitEntitlements: options.emitEntitlements
3189
+ });
3190
+ for (const d of result.diagnostics) {
3191
+ const prefix = d.severity === "error" ? "\x1B[31merror\x1B[0m" : d.severity === "warning" ? "\x1B[33mwarning\x1B[0m" : "\x1B[36minfo\x1B[0m";
3192
+ console.error(` ${prefix}[${d.code}]: ${d.message}`);
3193
+ if (d.file) console.error(` --> ${d.file}${d.line ? `:${d.line}` : ""}`);
3194
+ if (d.suggestion) console.error(` = help: ${d.suggestion}`);
3195
+ }
3196
+ if (!result.success || !result.output) {
3197
+ const errors = result.diagnostics.filter((d) => d.severity === "error").length;
3198
+ console.error(`\x1B[31m\u2717\x1B[0m ${basename(filePath)} \u2014 ${errors} error(s)`);
3199
+ return false;
3200
+ }
3201
+ let swiftCode = result.output.swiftCode;
3202
+ try {
3203
+ const { formatSwift: formatSwift2 } = await Promise.resolve().then(() => (init_format(), format_exports));
3204
+ const fmt = await formatSwift2(swiftCode, { strict: options.strictFormat });
3205
+ if (fmt.ran) swiftCode = fmt.formatted;
3206
+ } catch (fmtErr) {
3207
+ if (options.strictFormat) {
3208
+ console.error(`\x1B[31merror:\x1B[0m ${fmtErr.message}`);
3209
+ return false;
3210
+ }
3211
+ }
3212
+ const outPath = resolve2(result.output.outputPath);
3213
+ mkdirSync(dirname2(outPath), { recursive: true });
3214
+ writeFileSync(outPath, swiftCode, "utf-8");
3215
+ if (options.emitInfoPlist && result.output.infoPlistFragment) {
3216
+ writeFileSync(
3217
+ outPath.replace(/\.swift$/, ".plist.fragment.xml"),
3218
+ result.output.infoPlistFragment,
3219
+ "utf-8"
3220
+ );
3221
+ }
3222
+ if (options.emitEntitlements && result.output.entitlementsFragment) {
3223
+ writeFileSync(
3224
+ outPath.replace(/\.swift$/, ".entitlements.fragment.xml"),
3225
+ result.output.entitlementsFragment,
3226
+ "utf-8"
3227
+ );
3228
+ }
3229
+ const dt = (performance.now() - t0).toFixed(1);
3230
+ console.log(
3231
+ `\x1B[32m\u2713\x1B[0m ${result.output.ir.name} \u2192 ${outPath} \x1B[90m(${dt}ms)\x1B[0m`
3232
+ );
3233
+ return true;
3234
+ }
3235
+ console.log(`\x1B[1maxint watch\x1B[0m \u2014 ${filesToWatch.length} file(s)
3236
+ `);
3237
+ let ok = 0;
3238
+ let fail = 0;
3239
+ for (const f of filesToWatch) {
3240
+ if (await compileWithFormat(f)) {
3241
+ ok++;
3242
+ } else {
3243
+ fail++;
3244
+ }
3245
+ }
3246
+ console.log();
3247
+ if (fail > 0) {
3248
+ console.log(
3249
+ `\x1B[33m\u26A0\x1B[0m ${ok} compiled, ${fail} failed \u2014 watching for changes\u2026
3250
+ `
3251
+ );
3252
+ } else {
3253
+ console.log(`\x1B[32m\u2713\x1B[0m ${ok} compiled \u2014 watching for changes\u2026
3254
+ `);
3255
+ if (options.swiftBuild) {
3256
+ await runSwiftBuild2(swiftProjectPath);
3257
+ }
3258
+ }
3259
+ const pending = /* @__PURE__ */ new Map();
3260
+ const DEBOUNCE_MS = 150;
3261
+ let batchInProgress = false;
3262
+ function onFileChange(filePath) {
3263
+ const existing = pending.get(filePath);
3264
+ if (existing) clearTimeout(existing);
3265
+ pending.set(
3266
+ filePath,
3267
+ setTimeout(async () => {
3268
+ pending.delete(filePath);
3269
+ if (batchInProgress) return;
3270
+ batchInProgress = true;
3271
+ try {
3272
+ const now = (/* @__PURE__ */ new Date()).toLocaleTimeString();
3273
+ console.log(`\x1B[90m[${now}]\x1B[0m ${basename(filePath)} changed`);
3274
+ const compiled = await compileWithFormat(filePath);
3275
+ console.log();
3276
+ if (compiled && options.swiftBuild) {
3277
+ await runSwiftBuild2(swiftProjectPath);
3278
+ }
3279
+ } finally {
3280
+ batchInProgress = false;
3281
+ }
3282
+ }, DEBOUNCE_MS)
3283
+ );
3284
+ }
3285
+ if (isDir) {
3286
+ const dirWatcher = fsWatch(target, { persistent: true }, (_event, filename) => {
3287
+ if (filename && typeof filename === "string" && filename.endsWith(".ts") && !filename.endsWith(".d.ts")) {
3288
+ onFileChange(resolve2(target, filename));
3289
+ }
3290
+ });
3291
+ dirWatcher.on("error", (err) => {
3292
+ console.error(`\x1B[31m\u2717\x1B[0m watcher error: ${err.message}`);
3293
+ });
3294
+ } else {
3295
+ const parentDir = dirname2(target);
3296
+ const targetBase = basename(target);
3297
+ const fileWatcher = fsWatch(
3298
+ parentDir,
3299
+ { persistent: true },
3300
+ (_event, filename) => {
3301
+ if (filename === targetBase) {
3302
+ onFileChange(target);
3303
+ }
3304
+ }
3305
+ );
3306
+ fileWatcher.on("error", (err) => {
3307
+ console.error(`\x1B[31m\u2717\x1B[0m watcher error: ${err.message}`);
3308
+ });
3309
+ }
3310
+ process.on("SIGINT", () => {
3311
+ console.log("\n\x1B[90mStopped watching.\x1B[0m");
3312
+ process.exit(0);
3313
+ });
3314
+ }
3315
+ );
3009
3316
  program.command("mcp").description(
3010
3317
  "Start the Axint MCP server (stdio) for Claude Code, Cursor, Windsurf, Zed, or any MCP client"
3011
3318
  ).action(async () => {