Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ tests/.tmp-compiler-tests/
# local scratch
tmp/
.axint/
.wwdc/

# Python
__pycache__/
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ the CLI fallback, then continue the same workflow check with `--ran-suggest`.

## Public truth

<!-- truth:readme-proof-line:start -->v0.4.29 · 36 MCP tools + 5 prompts · 204 diagnostic codes · 1341 tests · 58 live packages · 26 bundled templates<!-- truth:readme-proof-line:end -->
<!-- truth:readme-proof-line:start -->v0.4.29 · 36 MCP tools + 5 prompts · 214 diagnostic codes · 1350 tests · 58 live packages · 34 bundled templates<!-- truth:readme-proof-line:end -->

<!-- truth:readme-truth-source:start -->Public proof is generated from `../public-truth/public-truth.json` via `npm --prefix .. run truth:sync`.<!-- truth:readme-truth-source:end -->

Expand Down
45 changes: 45 additions & 0 deletions examples/wwdc26-apple-intelligence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { defineEntity, defineIntent, param } from "@axint/compiler";

defineEntity({
name: "TravelMessage",
schemaDomain: "messages",
schema: "AppSchema.MessagesEntity.message",
syncable: true,
indexed: true,
indexedQuery: true,
ownership: "shared",
display: {
title: "name",
subtitle: "thread",
image: "message",
},
properties: {
id: param.string("Stable message identifier"),
name: param.string("Message summary"),
thread: param.string("Conversation thread"),
},
query: "string",
});

export default defineIntent({
name: "SummarizeTravelMessage",
title: "Summarize Travel Message",
description:
"Summarizes a shared travel message and prepares it for an app workflow.",
schemaDomain: "messages",
schema: "AppSchema.MessagesIntent.sendMessage",
conformsTo: ["LongRunningIntent", "CancellableIntent"],
supportedModes: "[.foreground, .background]",
allowedExecutionTargets: ".main",
params: {
message: param.entity("TravelMessage", "Message to summarize"),
audience: param.string("Who the summary is for", { required: false }),
},
perform: async ({ message }) => {
// Swift implementation hint:
// import FoundationModels
// let session = LanguageModelSession()
// Run the prompt against the current OS model, then attach Cloud Check proof.
return { summary: `Replace with Foundation Models output for ${message}` };
},
});
42 changes: 42 additions & 0 deletions examples/wwdc26-p1-collections-and-progress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { defineEntity, defineIntent, param } from "@axint/compiler";

defineEntity({
name: "ResearchSource",
schemaDomain: "assistant",
schema: "AppSchema.AssistantEntity.document",
syncable: true,
indexed: true,
indexedQuery: true,
ownership: "shared",
display: {
title: "title",
subtitle: "origin",
},
properties: {
id: param.string("Stable source identifier"),
title: param.string("Source title"),
origin: param.string("Where this source came from"),
},
query: "string",
});

export default defineIntent({
name: "BuildResearchBrief",
title: "Build Research Brief",
description:
"Builds a research brief from a selected collection of assistant sources.",
schemaDomain: "assistant",
schema: "AppSchema.AssistantIntent.summarize",
conformsTo: ["LongRunningIntent", "ProgressReportingIntent"],
supportedModes: "[.foreground, .background]",
params: {
sources: param.entityCollection("ResearchSource", "Sources to include"),
tags: param.array(param.string("Tag"), "Tags", { required: false }),
},
perform: async ({ sources }) => {
// Swift implementation hint:
// Use performBackgroundTask(options: LongRunningTaskOptions(...)) and
// report progress as each source is processed.
return { sourceCount: Array.isArray(sources) ? sources.length : 0 };
},
});
6 changes: 3 additions & 3 deletions metrics.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
"axint.create-widget",
"axint.create-intent"
],
"bundledTemplates": 26,
"diagnostics": 204,
"bundledTemplates": 34,
"diagnostics": 214,
"xcodeFixRules": 33,
"xcodeFixRuleCodes": [
"AX701",
Expand Down Expand Up @@ -86,7 +86,7 @@
"AX748"
],
"tests": {
"typescript": 1227,
"typescript": 1236,
"python": 114
},
"registryPackages": 58,
Expand Down
152 changes: 152 additions & 0 deletions src/cloud/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,7 @@ function inferEvidenceDiagnostics(input: {
diagnostics.push(
...diagnosticsFromStateTransitionHangEvidence(evidenceText, source, file)
);
diagnostics.push(...diagnosticsFromWwdc26Readiness(source, evidenceText, file));

if (
input.input.expectedBehavior &&
Expand Down Expand Up @@ -1196,6 +1197,157 @@ function inferEvidenceDiagnostics(input: {
return dedupeDiagnostics(diagnostics);
}

function diagnosticsFromWwdc26Readiness(
source: string,
evidenceText: string,
file: string
): Diagnostic[] {
const diagnostics: Diagnostic[] = [];
const lower = source.toLowerCase();
const touchesAppleIntelligence =
/@App(Intent|Entity|Enum)\(schema:/.test(source) ||
/\b(AppSchema|SyncableEntity|OwnershipProvidingEntity|IndexedEntityQuery|IntentValueQuery|FoundationModels|LanguageModelSession|SystemLanguageModel|PrivateCloudComputeLanguageModel|GenerationSchema|ToolCallingMode)\b/.test(
source
) ||
/@(?:Generable|UnionValue)\b/.test(source) ||
/\b(LongRunningIntent|ProgressReportingIntent|SnippetIntent|ShowsSnippetIntent|ShowsSnippetView|ResultsCollection|IntentItemCollection|AppUnionValue|AppUnionValueCasesProviding)\b/.test(
source
);

if (!touchesAppleIntelligence) return diagnostics;

if (
/@AppEntity\(schema:/.test(source) &&
!/\bSyncableEntity\b/.test(source) &&
!/\bTransientAppEntity\b/.test(source)
) {
diagnostics.push({
code: "AXCLOUD-WWDC26-SYNCABLE-ENTITY",
severity: "warning",
file,
message:
"This entity adopts an Apple app schema but does not declare SyncableEntity for stable cross-device identifiers.",
suggestion:
"If the entity represents durable user content, adopt SyncableEntity and make sure id values remain stable across devices.",
});
}

if (
/@AppIntent\(schema:/.test(source) &&
/\b(delete|remove|archive|send|update|publish|share)\b/.test(lower) &&
!/\bOwnershipProvidingEntity\b/.test(source)
) {
diagnostics.push({
code: "AXCLOUD-WWDC26-OWNERSHIP-GUARD",
severity: "warning",
file,
message:
"This schema-backed intent appears to perform a sensitive or destructive action without an OwnershipProvidingEntity guard.",
suggestion:
"For shared or public entities, adopt OwnershipProvidingEntity and return EntityOwnership so the system can ask for confirmation when needed.",
});
}

if (/\bIndexedEntity\b/.test(source) && !/\bIndexedEntityQuery\b/.test(source)) {
diagnostics.push({
code: "AXCLOUD-WWDC26-INDEXED-QUERY",
severity: "warning",
file,
message:
"This entity is indexed for Spotlight, but its query does not adopt IndexedEntityQuery for SDK-level reindex support.",
suggestion:
"Adopt IndexedEntityQuery on the entity query when the entity should be retrieved from Spotlight by identifier.",
});
}

if (
/\b(FoundationModels|LanguageModelSession|SystemLanguageModel|PrivateCloudComputeLanguageModel)\b/.test(
source
) &&
!/\b(xcode\s*27|ios\s*27|ipados\s*27|macos\s*27|visionos\s*27|model version|prompt version|tokenCount|contextSize)\b/.test(
evidenceText
)
) {
diagnostics.push({
code: "AXCLOUD-WWDC26-MODEL-PROOF",
severity: "warning",
file,
message:
"Foundation Models code needs prompt/model-version proof against the current OS model before it is safe to call demo-ready.",
suggestion:
"Attach Xcode 27 build proof plus prompt-version notes, token/context checks, or a focused model behavior test.",
});
}

if (
/\bLongRunningIntent\b/.test(source) &&
!/\b(performBackgroundTask|LongRunningTaskOptions)\b/.test(
source + "\n" + evidenceText
)
) {
diagnostics.push({
code: "AXCLOUD-WWDC26-LONG-RUNNING-PROOF",
severity: "warning",
file,
message:
"LongRunningIntent code needs proof that work is wrapped in the SDK long-running background task API.",
suggestion:
"Use performBackgroundTask(options:operation:) with LongRunningTaskOptions, then attach clean Xcode build/run proof for the target OS.",
});
}

if (
/\bProgressReportingIntent\b/.test(source) &&
!/(?:\bcompletedUnitCount\b|\btotalUnitCount\b|\bProgress\s*\(|\bprogress\.)/.test(
source + "\n" + evidenceText
)
) {
diagnostics.push({
code: "AXCLOUD-WWDC26-PROGRESS-PROOF",
severity: "warning",
file,
message:
"ProgressReportingIntent code needs observable progress proof before it is demo-ready.",
suggestion:
"Report progress milestones during the long-running operation and attach a focused run log or test showing progress updates.",
});
}

if (
/\b(SnippetIntent|ShowsSnippetIntent|ShowsSnippetView)\b/.test(source) &&
!/\b(requestConfirmation|snippetIntent|ShowsSnippetIntent|ShowsSnippetView)\b/.test(
source + "\n" + evidenceText
)
) {
diagnostics.push({
code: "AXCLOUD-WWDC26-SNIPPET-PROOF",
severity: "warning",
file,
message:
"Snippet-backed App Intents need proof that the snippet is actually returned or requested from perform().",
suggestion:
"Return a result that conforms to ShowsSnippetIntent or ShowsSnippetView, or call requestConfirmation(..., snippetIntent: ...), then attach simulator/device proof.",
});
}

if (
/(?:@UnionValue\b|\bAppUnionValue\b)/.test(source) &&
!/\bAppUnionValueCasesProviding\b/.test(source)
) {
diagnostics.push({
code: "AXCLOUD-WWDC26-UNION-VALUE-CASES",
severity: "warning",
file,
message:
"Union value code needs an AppUnionValueCasesProviding cases type so the system can enumerate supported cases.",
suggestion:
"Define a cases enum that adopts AppUnionValueCasesProviding and attach Xcode proof that the union value resolves in App Intents.",
});
}

return diagnostics;
}

function compactCloudCheckReport(report: CloudCheckReport): Omit<
CloudCheckReport,
"swiftCode"
Expand Down
3 changes: 3 additions & 0 deletions src/core/app-enum-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export function generateSwiftAppEnum(appEnum: IRAppEnum): string {
lines.push(``);
lines.push(`import AppIntents`);
lines.push(``);
if (appEnum.schema) {
lines.push(`@AppEnum(schema: ${appEnum.schema})`);
}
lines.push(`enum ${appEnum.name}: String, AppEnum {`);

for (const c of appEnum.cases) {
Expand Down
6 changes: 5 additions & 1 deletion src/core/app-enum-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

import ts from "typescript";
import type { IRAppEnum, IRAppEnumCase } from "./types.js";
import type { IRAppEnum, IRAppEnumCase, IRAppSchemaDomain } from "./types.js";
import { ParserError } from "./parser.js";
import {
findCallExpression,
Expand Down Expand Up @@ -68,6 +68,8 @@ export function parseAppEnumSource(
}

const title = readStringLiteral(props.get("title")) ?? name;
const schema = readStringLiteral(props.get("schema"));
const schemaDomain = readStringLiteral(props.get("schemaDomain"));
const cases = parseCases(props.get("cases"), filePath, sourceFile);

if (cases.length === 0) {
Expand All @@ -83,6 +85,8 @@ export function parseAppEnumSource(
return {
name,
title,
schema: schema || undefined,
schemaDomain: (schemaDomain as IRAppSchemaDomain | null) || undefined,
cases,
sourceFile: filePath,
};
Expand Down
Loading