@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/README.md +41 -13
- package/dist/cli/index.js +465 -158
- package/dist/cli/index.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +133 -8
- package/dist/core/index.js.map +1 -1
- package/package.json +4 -4
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
2224
|
-
await mkdir(
|
|
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
|
|
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(
|
|
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://
|
|
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 =
|
|
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(
|
|
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:
|
|
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
|
-
|
|
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 () => {
|