@autohq/cli 0.1.138 → 0.1.140
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/agent-bridge.js +1 -1
- package/dist/index.js +323 -143
- package/package.json +1 -1
package/dist/agent-bridge.js
CHANGED
|
@@ -26268,7 +26268,7 @@ Object.assign(lookup, {
|
|
|
26268
26268
|
// package.json
|
|
26269
26269
|
var package_default = {
|
|
26270
26270
|
name: "@autohq/cli",
|
|
26271
|
-
version: "0.1.
|
|
26271
|
+
version: "0.1.140",
|
|
26272
26272
|
license: "SEE LICENSE IN README.md",
|
|
26273
26273
|
publishConfig: {
|
|
26274
26274
|
access: "public"
|
package/dist/index.js
CHANGED
|
@@ -21204,7 +21204,7 @@ var init_package = __esm({
|
|
|
21204
21204
|
"package.json"() {
|
|
21205
21205
|
package_default = {
|
|
21206
21206
|
name: "@autohq/cli",
|
|
21207
|
-
version: "0.1.
|
|
21207
|
+
version: "0.1.140",
|
|
21208
21208
|
license: "SEE LICENSE IN README.md",
|
|
21209
21209
|
publishConfig: {
|
|
21210
21210
|
access: "public"
|
|
@@ -21386,9 +21386,10 @@ function compileAgentFile(path2) {
|
|
|
21386
21386
|
const context = { graph: /* @__PURE__ */ new Map(), removals: [] };
|
|
21387
21387
|
const document = readSingleDocument(path2);
|
|
21388
21388
|
const compiled = finalizeAgentApplyShape(
|
|
21389
|
-
compileAgentDocument(document, path2, [], context)
|
|
21389
|
+
compileAgentDocument(document, path2, [], context),
|
|
21390
|
+
path2
|
|
21390
21391
|
);
|
|
21391
|
-
const parsed = ProjectApplyResourceSchema.safeParse(compiled);
|
|
21392
|
+
const parsed = ProjectApplyResourceSchema.safeParse(compiled.resource);
|
|
21392
21393
|
if (!parsed.success) {
|
|
21393
21394
|
throw new Error(`Invalid compiled agent ${path2}: ${parsed.error.message}`);
|
|
21394
21395
|
}
|
|
@@ -21399,6 +21400,7 @@ function compileAgentFile(path2) {
|
|
|
21399
21400
|
}
|
|
21400
21401
|
return {
|
|
21401
21402
|
resource: parsed.data,
|
|
21403
|
+
resources: [...compiled.resources, parsed.data],
|
|
21402
21404
|
graph: [...context.graph.values()],
|
|
21403
21405
|
removals: context.removals
|
|
21404
21406
|
};
|
|
@@ -21406,9 +21408,10 @@ function compileAgentFile(path2) {
|
|
|
21406
21408
|
function compileAgentDocumentValue(document, path2) {
|
|
21407
21409
|
const context = { graph: /* @__PURE__ */ new Map(), removals: [] };
|
|
21408
21410
|
const compiled = finalizeAgentApplyShape(
|
|
21409
|
-
compileAgentDocument(document, path2, [], context)
|
|
21411
|
+
compileAgentDocument(document, path2, [], context),
|
|
21412
|
+
path2
|
|
21410
21413
|
);
|
|
21411
|
-
const parsed = ProjectApplyResourceSchema.safeParse(compiled);
|
|
21414
|
+
const parsed = ProjectApplyResourceSchema.safeParse(compiled.resource);
|
|
21412
21415
|
if (!parsed.success) {
|
|
21413
21416
|
throw new Error(`Invalid compiled agent ${path2}: ${parsed.error.message}`);
|
|
21414
21417
|
}
|
|
@@ -21419,6 +21422,7 @@ function compileAgentDocumentValue(document, path2) {
|
|
|
21419
21422
|
}
|
|
21420
21423
|
return {
|
|
21421
21424
|
resource: parsed.data,
|
|
21425
|
+
resources: [...compiled.resources, parsed.data],
|
|
21422
21426
|
graph: [...context.graph.values()],
|
|
21423
21427
|
removals: context.removals
|
|
21424
21428
|
};
|
|
@@ -21452,21 +21456,9 @@ function readLocalAgentAuthoringStatuses(input) {
|
|
|
21452
21456
|
input?.directory ?? join3(process.cwd(), ".auto"),
|
|
21453
21457
|
"agents"
|
|
21454
21458
|
);
|
|
21455
|
-
|
|
21456
|
-
|
|
21457
|
-
|
|
21458
|
-
(entry) => AGENT_FILE_EXTENSIONS.includes(
|
|
21459
|
-
extname(
|
|
21460
|
-
entry
|
|
21461
|
-
).toLowerCase()
|
|
21462
|
-
)
|
|
21463
|
-
).sort((left, right) => left.localeCompare(right));
|
|
21464
|
-
} catch {
|
|
21465
|
-
return [];
|
|
21466
|
-
}
|
|
21467
|
-
return entries.map((entry) => {
|
|
21468
|
-
const path2 = join3(agentsDirectory, entry);
|
|
21469
|
-
const fallbackName = basename2(entry, extname(entry));
|
|
21459
|
+
const paths = agentAuthoringFiles(agentsDirectory);
|
|
21460
|
+
return paths.map((path2) => {
|
|
21461
|
+
const fallbackName = basename2(path2, extname(path2));
|
|
21470
21462
|
try {
|
|
21471
21463
|
const result = compileAgentFile(path2);
|
|
21472
21464
|
return {
|
|
@@ -21491,14 +21483,32 @@ function readLocalAgentAuthoringStatuses(input) {
|
|
|
21491
21483
|
}
|
|
21492
21484
|
});
|
|
21493
21485
|
}
|
|
21494
|
-
function
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21486
|
+
function validateAgentFragmentFile(path2) {
|
|
21487
|
+
validateAgentFragmentDocument(readSingleDocument(path2), path2, []);
|
|
21488
|
+
}
|
|
21489
|
+
function agentAuthoringFiles(directory) {
|
|
21490
|
+
let entries;
|
|
21491
|
+
try {
|
|
21492
|
+
entries = readdirSync2(directory, { withFileTypes: true });
|
|
21493
|
+
} catch {
|
|
21494
|
+
return [];
|
|
21495
|
+
}
|
|
21496
|
+
const files = [];
|
|
21497
|
+
for (const entry of entries) {
|
|
21498
|
+
const path2 = join3(directory, entry.name);
|
|
21499
|
+
if (entry.isDirectory()) {
|
|
21500
|
+
files.push(...agentAuthoringFiles(path2));
|
|
21501
|
+
continue;
|
|
21502
|
+
}
|
|
21503
|
+
if (entry.isFile() && AGENT_FILE_EXTENSIONS.includes(
|
|
21504
|
+
extname(
|
|
21505
|
+
entry.name
|
|
21506
|
+
).toLowerCase()
|
|
21507
|
+
)) {
|
|
21508
|
+
files.push(path2);
|
|
21499
21509
|
}
|
|
21500
21510
|
}
|
|
21501
|
-
return
|
|
21511
|
+
return files.sort((left, right) => left.localeCompare(right));
|
|
21502
21512
|
}
|
|
21503
21513
|
function resolveAgentAuthoringPath(input) {
|
|
21504
21514
|
const candidate = resolve(input.agent);
|
|
@@ -21519,27 +21529,6 @@ function resolveAgentAuthoringPath(input) {
|
|
|
21519
21529
|
`Agent authoring file not found for "${input.agent}" under ${agentsDirectory}`
|
|
21520
21530
|
);
|
|
21521
21531
|
}
|
|
21522
|
-
function discoverImports(document, path2, stack, imported) {
|
|
21523
|
-
const resolvedPath = resolve(path2);
|
|
21524
|
-
if (stack.includes(resolvedPath)) {
|
|
21525
|
-
throw new Error(
|
|
21526
|
-
`Agent import cycle detected: ${[...stack, resolvedPath].join(" -> ")}`
|
|
21527
|
-
);
|
|
21528
|
-
}
|
|
21529
|
-
if (!isRecord(document)) {
|
|
21530
|
-
return;
|
|
21531
|
-
}
|
|
21532
|
-
for (const importPath of importPaths(document)) {
|
|
21533
|
-
const resolvedImport = resolveImportPath(importPath, resolvedPath);
|
|
21534
|
-
imported.add(resolvedImport);
|
|
21535
|
-
discoverImports(
|
|
21536
|
-
readSingleDocument(resolvedImport),
|
|
21537
|
-
resolvedImport,
|
|
21538
|
-
[...stack, resolvedPath],
|
|
21539
|
-
imported
|
|
21540
|
-
);
|
|
21541
|
-
}
|
|
21542
|
-
}
|
|
21543
21532
|
function compileAgentDocument(document, path2, stack, context) {
|
|
21544
21533
|
const resolvedPath = resolve(path2);
|
|
21545
21534
|
if (stack.includes(resolvedPath)) {
|
|
@@ -21579,6 +21568,29 @@ function compileAgentDocument(document, path2, stack, context) {
|
|
|
21579
21568
|
[]
|
|
21580
21569
|
);
|
|
21581
21570
|
}
|
|
21571
|
+
function validateAgentFragmentDocument(document, path2, stack) {
|
|
21572
|
+
const resolvedPath = resolve(path2);
|
|
21573
|
+
if (stack.includes(resolvedPath)) {
|
|
21574
|
+
throw new Error(
|
|
21575
|
+
`Agent import cycle detected: ${[...stack, resolvedPath].join(" -> ")}`
|
|
21576
|
+
);
|
|
21577
|
+
}
|
|
21578
|
+
if (!isRecord(document)) {
|
|
21579
|
+
throw new Error(`Invalid agent fragment file ${path2}: expected object`);
|
|
21580
|
+
}
|
|
21581
|
+
for (const imported of importPaths(document).map(
|
|
21582
|
+
(importPath) => resolveImportPath(importPath, resolvedPath)
|
|
21583
|
+
)) {
|
|
21584
|
+
validateAgentFragmentDocument(readSingleDocument(imported), imported, [
|
|
21585
|
+
...stack,
|
|
21586
|
+
resolvedPath
|
|
21587
|
+
]);
|
|
21588
|
+
}
|
|
21589
|
+
for (const removal of removalDirectives(document, resolvedPath)) {
|
|
21590
|
+
assertSupportedRemovalTarget(removal.target);
|
|
21591
|
+
}
|
|
21592
|
+
authoringDocumentApplyShape(document, resolvedPath);
|
|
21593
|
+
}
|
|
21582
21594
|
function readSingleDocument(path2) {
|
|
21583
21595
|
const documents = readDocuments(path2);
|
|
21584
21596
|
if (documents.length !== 1) {
|
|
@@ -21590,7 +21602,12 @@ function readSingleDocument(path2) {
|
|
|
21590
21602
|
}
|
|
21591
21603
|
function readDocuments(path2) {
|
|
21592
21604
|
const source = readFileSync3(path2, "utf8");
|
|
21593
|
-
|
|
21605
|
+
const documents = parseYamlDocuments(source);
|
|
21606
|
+
const parseError = documents.flatMap((document) => document.errors).at(0);
|
|
21607
|
+
if (parseError) {
|
|
21608
|
+
throw new Error(parseError.message);
|
|
21609
|
+
}
|
|
21610
|
+
return documents.filter((document) => document.contents !== null).map((document) => document.toJSON());
|
|
21594
21611
|
}
|
|
21595
21612
|
function importPaths(document) {
|
|
21596
21613
|
const value = document.imports ?? document.import;
|
|
@@ -21641,14 +21658,13 @@ function authoringDocumentApplyShape(document, path2) {
|
|
|
21641
21658
|
continue;
|
|
21642
21659
|
}
|
|
21643
21660
|
if (AGENT_METADATA_FIELDS.has(key)) {
|
|
21644
|
-
const metadataKey = key === "name" ? "name" : key;
|
|
21645
21661
|
assertNoDuplicateFacadeField({
|
|
21646
21662
|
path: path2,
|
|
21647
21663
|
field: key,
|
|
21648
|
-
target: `metadata.${
|
|
21649
|
-
targetValue: metadata[
|
|
21664
|
+
target: `metadata.${key}`,
|
|
21665
|
+
targetValue: metadata[key]
|
|
21650
21666
|
});
|
|
21651
|
-
metadata[
|
|
21667
|
+
metadata[key] = value;
|
|
21652
21668
|
continue;
|
|
21653
21669
|
}
|
|
21654
21670
|
if (AGENT_SPEC_FIELDS.has(key)) {
|
|
@@ -21667,12 +21683,18 @@ function authoringDocumentApplyShape(document, path2) {
|
|
|
21667
21683
|
spec: resolveFileBackedFields(spec, path2)
|
|
21668
21684
|
};
|
|
21669
21685
|
}
|
|
21670
|
-
function finalizeAgentApplyShape(document) {
|
|
21686
|
+
function finalizeAgentApplyShape(document, path2) {
|
|
21671
21687
|
if (!isRecord(document) || !isRecord(document.spec)) {
|
|
21672
|
-
return document;
|
|
21688
|
+
return { resource: document, resources: [] };
|
|
21673
21689
|
}
|
|
21674
21690
|
const next = structuredClone(document);
|
|
21675
21691
|
const spec = next.spec;
|
|
21692
|
+
const resources = [];
|
|
21693
|
+
if (isRecord(spec.environment)) {
|
|
21694
|
+
const environment = inlineEnvironmentResource(spec.environment, path2);
|
|
21695
|
+
spec.environment = environment.metadata.name;
|
|
21696
|
+
resources.push(environment);
|
|
21697
|
+
}
|
|
21676
21698
|
if (Array.isArray(spec.triggers)) {
|
|
21677
21699
|
spec.triggers = spec.triggers.map((trigger) => {
|
|
21678
21700
|
if (!isRecord(trigger) || !("name" in trigger)) {
|
|
@@ -21683,7 +21705,32 @@ function finalizeAgentApplyShape(document) {
|
|
|
21683
21705
|
return compiledTrigger;
|
|
21684
21706
|
});
|
|
21685
21707
|
}
|
|
21686
|
-
return next;
|
|
21708
|
+
return { resource: next, resources };
|
|
21709
|
+
}
|
|
21710
|
+
function inlineEnvironmentResource(document, path2) {
|
|
21711
|
+
const metadata = {};
|
|
21712
|
+
const spec = {};
|
|
21713
|
+
for (const [key, value] of Object.entries(document)) {
|
|
21714
|
+
if (value === void 0) {
|
|
21715
|
+
continue;
|
|
21716
|
+
}
|
|
21717
|
+
if (AGENT_METADATA_FIELDS.has(key)) {
|
|
21718
|
+
metadata[key] = value;
|
|
21719
|
+
continue;
|
|
21720
|
+
}
|
|
21721
|
+
spec[key] = value;
|
|
21722
|
+
}
|
|
21723
|
+
const parsed = EnvironmentApplyRequestSchema.safeParse({ metadata, spec });
|
|
21724
|
+
if (!parsed.success) {
|
|
21725
|
+
throw new Error(
|
|
21726
|
+
`Invalid inline environment in ${path2}: ${parsed.error.message}`
|
|
21727
|
+
);
|
|
21728
|
+
}
|
|
21729
|
+
return {
|
|
21730
|
+
kind: RESOURCE_KIND_ENVIRONMENT,
|
|
21731
|
+
metadata: parsed.data.metadata,
|
|
21732
|
+
spec: parsed.data.spec
|
|
21733
|
+
};
|
|
21687
21734
|
}
|
|
21688
21735
|
function assertNoDuplicateFacadeField(input) {
|
|
21689
21736
|
if (input.targetValue !== void 0) {
|
|
@@ -21784,9 +21831,15 @@ function applyRemoval(value, removal) {
|
|
|
21784
21831
|
return next;
|
|
21785
21832
|
}
|
|
21786
21833
|
default:
|
|
21787
|
-
|
|
21788
|
-
|
|
21789
|
-
|
|
21834
|
+
assertSupportedRemovalTarget(removal.target);
|
|
21835
|
+
return next;
|
|
21836
|
+
}
|
|
21837
|
+
}
|
|
21838
|
+
function assertSupportedRemovalTarget(target) {
|
|
21839
|
+
if (target !== "tools" && target !== "triggers") {
|
|
21840
|
+
throw new Error(
|
|
21841
|
+
`Unsupported agent remove target "${target}"; supported targets are tools, triggers`
|
|
21842
|
+
);
|
|
21790
21843
|
}
|
|
21791
21844
|
}
|
|
21792
21845
|
function mergeValues2(base, override, path2) {
|
|
@@ -21919,32 +21972,99 @@ function readProjectApplyRequest(options) {
|
|
|
21919
21972
|
}
|
|
21920
21973
|
if (options.file) {
|
|
21921
21974
|
const request = readApplyDocumentFile(options.file);
|
|
21975
|
+
const resources2 = dedupeGeneratedResources(request.resourceRecords);
|
|
21922
21976
|
const assets2 = readApplyAssets(
|
|
21923
|
-
|
|
21977
|
+
resources2,
|
|
21924
21978
|
applyFileProjectRoot(options.file)
|
|
21925
21979
|
);
|
|
21926
|
-
return {
|
|
21980
|
+
return {
|
|
21981
|
+
delete: request.delete,
|
|
21982
|
+
dryRun: request.dryRun,
|
|
21983
|
+
prune: request.prune,
|
|
21984
|
+
resources: resources2,
|
|
21985
|
+
assets: assets2
|
|
21986
|
+
};
|
|
21927
21987
|
}
|
|
21928
21988
|
const directory = options.directory ?? join4(process.cwd(), ".auto");
|
|
21929
21989
|
assertNoLegacySessionFiles(directory);
|
|
21990
|
+
assertNoStandaloneResourceFiles(directory);
|
|
21991
|
+
assertValidFragmentFiles(directory);
|
|
21930
21992
|
const files = applyFiles(directory);
|
|
21931
21993
|
if (files.length === 0) {
|
|
21932
21994
|
throw new Error(`No resource files found in ${directory}`);
|
|
21933
21995
|
}
|
|
21934
|
-
const
|
|
21996
|
+
const resourceRecords = [];
|
|
21935
21997
|
for (const { kind, path: path2 } of files) {
|
|
21936
21998
|
const request = readApplyDocumentFile(path2);
|
|
21937
|
-
for (const resource of request.
|
|
21938
|
-
if (
|
|
21999
|
+
for (const { resource, generatedFromAgent } of request.resourceRecords) {
|
|
22000
|
+
if (!isAllowedDirectoryResourceKind(kind, resource, generatedFromAgent)) {
|
|
21939
22001
|
throw new Error(
|
|
21940
22002
|
`Resource kind "${resource.kind}" in ${path2} does not match .auto/${primaryApplyDirectory(kind)}`
|
|
21941
22003
|
);
|
|
21942
22004
|
}
|
|
21943
|
-
|
|
22005
|
+
resourceRecords.push({ resource, generatedFromAgent });
|
|
21944
22006
|
}
|
|
21945
22007
|
}
|
|
22008
|
+
const resources = dedupeGeneratedResources(resourceRecords);
|
|
21946
22009
|
const assets = readApplyAssets(resources, applyProjectRoot(directory));
|
|
21947
|
-
return {
|
|
22010
|
+
return {
|
|
22011
|
+
delete: [],
|
|
22012
|
+
dryRun: false,
|
|
22013
|
+
prune: true,
|
|
22014
|
+
resources,
|
|
22015
|
+
assets
|
|
22016
|
+
};
|
|
22017
|
+
}
|
|
22018
|
+
function isAllowedDirectoryResourceKind(directoryKind, resource, generatedFromAgent) {
|
|
22019
|
+
if (resource.kind === directoryKind) {
|
|
22020
|
+
return true;
|
|
22021
|
+
}
|
|
22022
|
+
return directoryKind === RESOURCE_KIND_SESSION && resource.kind === RESOURCE_KIND_ENVIRONMENT && generatedFromAgent;
|
|
22023
|
+
}
|
|
22024
|
+
function dedupeGeneratedResources(records) {
|
|
22025
|
+
const recordsByKey = /* @__PURE__ */ new Map();
|
|
22026
|
+
const deduped = [];
|
|
22027
|
+
for (const record2 of records) {
|
|
22028
|
+
const { resource } = record2;
|
|
22029
|
+
const key = `${resource.kind}/${resource.metadata.name}`;
|
|
22030
|
+
const existing = recordsByKey.get(key);
|
|
22031
|
+
if (!existing) {
|
|
22032
|
+
recordsByKey.set(key, record2);
|
|
22033
|
+
deduped.push(record2);
|
|
22034
|
+
continue;
|
|
22035
|
+
}
|
|
22036
|
+
if (!record2.generatedFromAgent && !existing.generatedFromAgent) {
|
|
22037
|
+
deduped.push(record2);
|
|
22038
|
+
continue;
|
|
22039
|
+
}
|
|
22040
|
+
if (stableResource(resource) !== stableResource(existing.resource)) {
|
|
22041
|
+
throw new Error(
|
|
22042
|
+
`Conflicting generated resource "${key}" from agent authoring. Inline environment definitions must be identical when they share a name.`
|
|
22043
|
+
);
|
|
22044
|
+
}
|
|
22045
|
+
}
|
|
22046
|
+
return deduped.map((record2) => record2.resource);
|
|
22047
|
+
}
|
|
22048
|
+
function stableResource(resource) {
|
|
22049
|
+
return JSON.stringify({
|
|
22050
|
+
kind: resource.kind,
|
|
22051
|
+
metadata: metadataComparable(resource.metadata),
|
|
22052
|
+
spec: sortJson(resource.spec)
|
|
22053
|
+
});
|
|
22054
|
+
}
|
|
22055
|
+
function metadataComparable(metadata) {
|
|
22056
|
+
return sortJson(metadata);
|
|
22057
|
+
}
|
|
22058
|
+
function sortJson(value) {
|
|
22059
|
+
if (Array.isArray(value)) {
|
|
22060
|
+
return value.map(sortJson);
|
|
22061
|
+
}
|
|
22062
|
+
if (isRecord2(value)) {
|
|
22063
|
+
return Object.fromEntries(
|
|
22064
|
+
Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, sortJson(nested)])
|
|
22065
|
+
);
|
|
22066
|
+
}
|
|
22067
|
+
return value;
|
|
21948
22068
|
}
|
|
21949
22069
|
function appliedResourceKind(request, response, index) {
|
|
21950
22070
|
const plannedResources = response.plan.filter(
|
|
@@ -21976,29 +22096,17 @@ function mcpOAuthSessionToolConnectionsFromAppliedResources(resources) {
|
|
|
21976
22096
|
});
|
|
21977
22097
|
}
|
|
21978
22098
|
function applyFiles(root) {
|
|
21979
|
-
const
|
|
21980
|
-
|
|
21981
|
-
|
|
21982
|
-
|
|
21983
|
-
|
|
21984
|
-
|
|
21985
|
-
entries = readdirSync3(path2, { withFileTypes: true });
|
|
21986
|
-
} catch {
|
|
21987
|
-
continue;
|
|
21988
|
-
}
|
|
21989
|
-
kindFiles.push(...resourceApplyFiles(path2, entries));
|
|
21990
|
-
const importedFiles = kind === RESOURCE_KIND_SESSION ? importedAgentAuthoringPaths(kindFiles) : /* @__PURE__ */ new Set();
|
|
21991
|
-
const appliedFiles = kind === RESOURCE_KIND_SESSION ? kindFiles.filter(
|
|
21992
|
-
(path3) => !importedFiles.has(resolve2(path3)) && !isSharedAgentAuthoringFile(root, path3)
|
|
21993
|
-
) : kindFiles;
|
|
21994
|
-
files.push(...appliedFiles.map((path3) => ({ kind, path: path3 })));
|
|
22099
|
+
const agentsRoot = join4(root, primaryApplyDirectory(RESOURCE_KIND_SESSION));
|
|
22100
|
+
let entries;
|
|
22101
|
+
try {
|
|
22102
|
+
entries = readdirSync3(agentsRoot, { withFileTypes: true });
|
|
22103
|
+
} catch {
|
|
22104
|
+
return [];
|
|
21995
22105
|
}
|
|
21996
|
-
return
|
|
21997
|
-
|
|
21998
|
-
|
|
21999
|
-
|
|
22000
|
-
const resolvedPath = resolve2(path2);
|
|
22001
|
-
return resolvedPath.startsWith(`${agentsSharedRoot}/`);
|
|
22106
|
+
return resourceApplyFiles(agentsRoot, entries).map((path2) => ({
|
|
22107
|
+
kind: RESOURCE_KIND_SESSION,
|
|
22108
|
+
path: path2
|
|
22109
|
+
}));
|
|
22002
22110
|
}
|
|
22003
22111
|
function assertNoLegacySessionFiles(root) {
|
|
22004
22112
|
const path2 = join4(root, "sessions");
|
|
@@ -22016,6 +22124,53 @@ function assertNoLegacySessionFiles(root) {
|
|
|
22016
22124
|
`Legacy .auto/sessions files are no longer supported. Move ${files.length === 1 ? "this file" : "these files"} to .auto/agents and use the root-level Agent facade format: ${files.join(", ")}`
|
|
22017
22125
|
);
|
|
22018
22126
|
}
|
|
22127
|
+
function assertNoStandaloneResourceFiles(root) {
|
|
22128
|
+
for (const { directory, kind, guidance } of [
|
|
22129
|
+
{
|
|
22130
|
+
directory: "environments",
|
|
22131
|
+
kind: RESOURCE_KIND_ENVIRONMENT,
|
|
22132
|
+
guidance: "Define environments inline in .auto/agents YAML, using fragment imports under .auto/fragments/environments for reused runtimes."
|
|
22133
|
+
},
|
|
22134
|
+
{
|
|
22135
|
+
directory: "identities",
|
|
22136
|
+
kind: RESOURCE_KIND_IDENTITY,
|
|
22137
|
+
guidance: "Define identities inline on the owning .auto/agents YAML file."
|
|
22138
|
+
}
|
|
22139
|
+
]) {
|
|
22140
|
+
const path2 = join4(root, directory);
|
|
22141
|
+
let entries;
|
|
22142
|
+
try {
|
|
22143
|
+
entries = readdirSync3(path2, { withFileTypes: true });
|
|
22144
|
+
} catch {
|
|
22145
|
+
continue;
|
|
22146
|
+
}
|
|
22147
|
+
const files = resourceApplyFiles(path2, entries);
|
|
22148
|
+
if (files.length === 0) {
|
|
22149
|
+
continue;
|
|
22150
|
+
}
|
|
22151
|
+
throw new Error(
|
|
22152
|
+
`Standalone .auto/${directory} ${kind} resources are no longer supported. ${guidance} Move ${files.length === 1 ? "this file" : "these files"}: ${files.join(", ")}`
|
|
22153
|
+
);
|
|
22154
|
+
}
|
|
22155
|
+
}
|
|
22156
|
+
function assertValidFragmentFiles(root) {
|
|
22157
|
+
const fragmentsRoot = join4(root, "fragments");
|
|
22158
|
+
let entries;
|
|
22159
|
+
try {
|
|
22160
|
+
entries = readdirSync3(fragmentsRoot, { withFileTypes: true });
|
|
22161
|
+
} catch {
|
|
22162
|
+
return;
|
|
22163
|
+
}
|
|
22164
|
+
for (const path2 of resourceApplyFiles(fragmentsRoot, entries)) {
|
|
22165
|
+
try {
|
|
22166
|
+
validateAgentFragmentFile(path2);
|
|
22167
|
+
} catch (error51) {
|
|
22168
|
+
throw new Error(
|
|
22169
|
+
`Invalid fragment file ${path2}: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
22170
|
+
);
|
|
22171
|
+
}
|
|
22172
|
+
}
|
|
22173
|
+
}
|
|
22019
22174
|
function mcpOAuthSessionToolConnectionsFromSessionTools(input) {
|
|
22020
22175
|
return Object.entries(input.tools).flatMap(([alias, tool]) => {
|
|
22021
22176
|
if (tool.kind !== "mcp_remote" || tool.disabled || tool.auth.kind !== "mcp_oauth") {
|
|
@@ -22034,7 +22189,12 @@ function readApplyDocumentFile(path2) {
|
|
|
22034
22189
|
const source = readFileSync4(path2, "utf8");
|
|
22035
22190
|
let documents;
|
|
22036
22191
|
try {
|
|
22037
|
-
|
|
22192
|
+
const parsedDocuments = parseYamlDocuments2(source);
|
|
22193
|
+
const parseError = parsedDocuments.flatMap((document) => document.errors).at(0);
|
|
22194
|
+
if (parseError) {
|
|
22195
|
+
throw parseError;
|
|
22196
|
+
}
|
|
22197
|
+
documents = parsedDocuments.filter((document) => document.contents !== null).map((document) => document.toJSON());
|
|
22038
22198
|
} catch (error51) {
|
|
22039
22199
|
throw new Error(
|
|
22040
22200
|
`Invalid apply file: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
@@ -22046,33 +22206,44 @@ function readApplyDocumentFile(path2) {
|
|
|
22046
22206
|
if (documents.length === 1) {
|
|
22047
22207
|
const system = ProjectApplySystemConfigSchema.safeParse(documents[0]);
|
|
22048
22208
|
if (system.success) {
|
|
22049
|
-
|
|
22209
|
+
const resources = system.data.spec.resources;
|
|
22210
|
+
assertNoExplicitStandaloneResources(resources, path2);
|
|
22211
|
+
return {
|
|
22212
|
+
...system.data.spec,
|
|
22213
|
+
resourceRecords: resources.map((resource) => ({
|
|
22214
|
+
resource,
|
|
22215
|
+
generatedFromAgent: false
|
|
22216
|
+
}))
|
|
22217
|
+
};
|
|
22050
22218
|
}
|
|
22051
22219
|
}
|
|
22220
|
+
const resourceRecords = documents.flatMap(
|
|
22221
|
+
(document) => readApplyDocument(document, path2)
|
|
22222
|
+
);
|
|
22052
22223
|
return {
|
|
22053
22224
|
delete: [],
|
|
22054
22225
|
dryRun: false,
|
|
22055
22226
|
prune: false,
|
|
22056
|
-
resources:
|
|
22227
|
+
resources: resourceRecords.map((record2) => record2.resource),
|
|
22228
|
+
resourceRecords,
|
|
22057
22229
|
assets: {}
|
|
22058
22230
|
};
|
|
22059
22231
|
}
|
|
22060
22232
|
function readApplyDocument(document, path2) {
|
|
22061
|
-
|
|
22062
|
-
|
|
22063
|
-
|
|
22064
|
-
|
|
22065
|
-
|
|
22066
|
-
|
|
22067
|
-
|
|
22068
|
-
|
|
22069
|
-
|
|
22233
|
+
assertAgentAuthoringDocument(document, path2);
|
|
22234
|
+
const result = compileAgentDocumentValue(document, path2);
|
|
22235
|
+
return result.resources.map((resource) => ({
|
|
22236
|
+
resource,
|
|
22237
|
+
generatedFromAgent: resource !== result.resource
|
|
22238
|
+
}));
|
|
22239
|
+
}
|
|
22240
|
+
function assertNoExplicitStandaloneResources(resources, path2) {
|
|
22241
|
+
for (const resource of resources) {
|
|
22242
|
+
if (resource.kind !== RESOURCE_KIND_ENVIRONMENT && resource.kind !== RESOURCE_KIND_IDENTITY) {
|
|
22243
|
+
continue;
|
|
22244
|
+
}
|
|
22245
|
+
throw standaloneResourceError(resource.kind, path2);
|
|
22070
22246
|
}
|
|
22071
|
-
return {
|
|
22072
|
-
kind: candidate.kind,
|
|
22073
|
-
metadata: parsed.data.metadata,
|
|
22074
|
-
spec: parsed.data.spec
|
|
22075
|
-
};
|
|
22076
22247
|
}
|
|
22077
22248
|
function readApplyAssets(resources, projectRoot) {
|
|
22078
22249
|
const assets = {};
|
|
@@ -22102,10 +22273,6 @@ function readApplyAssets(resources, projectRoot) {
|
|
|
22102
22273
|
return assets;
|
|
22103
22274
|
}
|
|
22104
22275
|
function avatarAssetTarget(resource) {
|
|
22105
|
-
if (resource.kind === RESOURCE_KIND_IDENTITY) {
|
|
22106
|
-
const asset = resource.spec.avatar?.asset;
|
|
22107
|
-
return asset ? { asset, resourceName: resource.metadata.name } : void 0;
|
|
22108
|
-
}
|
|
22109
22276
|
if (resource.kind === RESOURCE_KIND_SESSION && typeof resource.spec.identity === "object" && resource.spec.identity !== null && !Array.isArray(resource.spec.identity)) {
|
|
22110
22277
|
const asset = resource.spec.identity.avatar?.asset;
|
|
22111
22278
|
return asset ? { asset, resourceName: resource.metadata.name } : void 0;
|
|
@@ -22187,30 +22354,42 @@ function applyFileProjectRoot(file2) {
|
|
|
22187
22354
|
function isInside(path2, parent) {
|
|
22188
22355
|
return path2.startsWith(`${parent}/`);
|
|
22189
22356
|
}
|
|
22190
|
-
function
|
|
22357
|
+
function assertAgentAuthoringDocument(document, path2) {
|
|
22191
22358
|
if (!isRecord2(document) || !("kind" in document)) {
|
|
22192
|
-
return
|
|
22359
|
+
return;
|
|
22193
22360
|
}
|
|
22194
22361
|
if (document.kind === "session") {
|
|
22195
22362
|
throw new Error(
|
|
22196
22363
|
'Legacy resource kind "session" is no longer supported. Use .auto/agents with the root-level Agent facade format.'
|
|
22197
22364
|
);
|
|
22198
22365
|
}
|
|
22199
|
-
if (
|
|
22200
|
-
document.kind
|
|
22201
|
-
|
|
22366
|
+
if (document.kind === RESOURCE_KIND_ENVIRONMENT || document.kind === RESOURCE_KIND_IDENTITY) {
|
|
22367
|
+
throw standaloneResourceError(document.kind, path2);
|
|
22368
|
+
}
|
|
22369
|
+
if (document.kind !== RESOURCE_KIND_SESSION) {
|
|
22202
22370
|
throw new Error(
|
|
22203
|
-
`Unsupported apply resource kind "${String(document.kind)}"; supported
|
|
22371
|
+
`Unsupported apply resource kind "${String(document.kind)}"; supported kind is "${RESOURCE_KIND_SESSION}"`
|
|
22372
|
+
);
|
|
22373
|
+
}
|
|
22374
|
+
const parsed = SessionApplyRequestSchema.safeParse({
|
|
22375
|
+
metadata: document.metadata,
|
|
22376
|
+
spec: document.spec
|
|
22377
|
+
});
|
|
22378
|
+
if (parsed.success) {
|
|
22379
|
+
throw new Error(
|
|
22380
|
+
`Legacy agent resource envelopes are no longer supported in ${path2}. Use the root-level Agent facade format under .auto/agents.`
|
|
22204
22381
|
);
|
|
22205
22382
|
}
|
|
22206
|
-
|
|
22207
|
-
|
|
22208
|
-
|
|
22209
|
-
|
|
22210
|
-
|
|
22211
|
-
|
|
22212
|
-
|
|
22213
|
-
|
|
22383
|
+
}
|
|
22384
|
+
function standaloneResourceError(kind, path2) {
|
|
22385
|
+
if (kind === RESOURCE_KIND_ENVIRONMENT) {
|
|
22386
|
+
return new Error(
|
|
22387
|
+
`Standalone environment resources are no longer supported in ${path2}. Define environments inline in .auto/agents YAML, using fragment imports under .auto/fragments/environments for reused runtimes.`
|
|
22388
|
+
);
|
|
22389
|
+
}
|
|
22390
|
+
return new Error(
|
|
22391
|
+
`Standalone identity resources are no longer supported in ${path2}. Define identities inline on the owning .auto/agents YAML file.`
|
|
22392
|
+
);
|
|
22214
22393
|
}
|
|
22215
22394
|
function primaryApplyDirectory(kind) {
|
|
22216
22395
|
return APPLY_DIRECTORIES[kind];
|
|
@@ -22234,22 +22413,15 @@ function resourceApplyFiles(directory, entries) {
|
|
|
22234
22413
|
}
|
|
22235
22414
|
return files.sort((left, right) => left.localeCompare(right));
|
|
22236
22415
|
}
|
|
22237
|
-
var APPLY_DIRECTORIES,
|
|
22416
|
+
var APPLY_DIRECTORIES, ALLOWED_AVATAR_EXTENSIONS;
|
|
22238
22417
|
var init_files = __esm({
|
|
22239
22418
|
"src/commands/apply/files.ts"() {
|
|
22240
22419
|
"use strict";
|
|
22241
22420
|
init_src();
|
|
22242
22421
|
init_authoring();
|
|
22243
22422
|
APPLY_DIRECTORIES = {
|
|
22244
|
-
environment: "environments",
|
|
22245
|
-
identity: "identities",
|
|
22246
22423
|
agent: "agents"
|
|
22247
22424
|
};
|
|
22248
|
-
APPLY_SCHEMAS = {
|
|
22249
|
-
environment: EnvironmentApplyRequestSchema,
|
|
22250
|
-
identity: IdentityApplyRequestSchema,
|
|
22251
|
-
[RESOURCE_KIND_SESSION]: SessionApplyRequestSchema
|
|
22252
|
-
};
|
|
22253
22425
|
ALLOWED_AVATAR_EXTENSIONS = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png"]);
|
|
22254
22426
|
}
|
|
22255
22427
|
});
|
|
@@ -22631,6 +22803,11 @@ import { join as join5 } from "path";
|
|
|
22631
22803
|
import { parseAllDocuments as parseYamlDocuments3, stringify as stringify3 } from "yaml";
|
|
22632
22804
|
async function editResource(input) {
|
|
22633
22805
|
const reference = parseProjectResourceReference(input.resource);
|
|
22806
|
+
if (reference.kind !== RESOURCE_KIND_SESSION) {
|
|
22807
|
+
throw new Error(
|
|
22808
|
+
`Resource kind "${reference.kind}" can no longer be edited directly. Edit .auto/agents YAML instead; identities and environments are authored inline on agents.`
|
|
22809
|
+
);
|
|
22810
|
+
}
|
|
22634
22811
|
const editor = resolveEditor({
|
|
22635
22812
|
canFallbackToVi: input.canFallbackToVi,
|
|
22636
22813
|
env: input.env,
|
|
@@ -26092,14 +26269,17 @@ function agentAuthoringHeaderLabel(status) {
|
|
|
26092
26269
|
return `local ok, ${status.imports} imports, ${status.removals} removals`;
|
|
26093
26270
|
}
|
|
26094
26271
|
function editableResourceForSelection(input) {
|
|
26095
|
-
if (
|
|
26096
|
-
|
|
26097
|
-
}
|
|
26272
|
+
if (input.activeSection !== "sessions") return null;
|
|
26273
|
+
const selected = input.selectedSession;
|
|
26274
|
+
return selected ? { kind: "agent", name: selected.metadata.name } : null;
|
|
26275
|
+
}
|
|
26276
|
+
function inspectableResourceForSelection(input) {
|
|
26277
|
+
if (!isApplyResourceSection(input.activeSection)) return null;
|
|
26098
26278
|
const definition = PROJECT_RESOURCE_TUI_DEFINITIONS_BY_SECTION.get(
|
|
26099
26279
|
input.activeSection
|
|
26100
26280
|
);
|
|
26101
26281
|
const selected = selectedNamedResourceForSection(input);
|
|
26102
|
-
return definition && selected ? { kind: definition.kind, name: selected.metadata.name } : null;
|
|
26282
|
+
return definition && selected ? { kind: definition.kind, name: selected.metadata.name, spec: null } : null;
|
|
26103
26283
|
}
|
|
26104
26284
|
function HomeView({ apiUrl, notice, returnToSession }) {
|
|
26105
26285
|
const client = useApiClient();
|
|
@@ -26264,32 +26444,32 @@ function HomeView({ apiUrl, notice, returnToSession }) {
|
|
|
26264
26444
|
const selectedEnvironment = environments[environmentIndex];
|
|
26265
26445
|
const selectedIdentity = identities[identityIndex];
|
|
26266
26446
|
const selectedInspectableResource = useMemo3(() => {
|
|
26267
|
-
const
|
|
26447
|
+
const selectedInspectable = inspectableResourceForSelection({
|
|
26268
26448
|
activeSection,
|
|
26269
26449
|
selectedEnvironment,
|
|
26270
26450
|
selectedIdentity,
|
|
26271
26451
|
selectedSession
|
|
26272
26452
|
});
|
|
26273
|
-
if (!
|
|
26453
|
+
if (!selectedInspectable) {
|
|
26274
26454
|
return null;
|
|
26275
26455
|
}
|
|
26276
26456
|
switch (activeSection) {
|
|
26277
26457
|
case "sessions":
|
|
26278
26458
|
return selectedSession ? {
|
|
26279
|
-
kind:
|
|
26280
|
-
name:
|
|
26459
|
+
kind: selectedInspectable.kind,
|
|
26460
|
+
name: selectedInspectable.name,
|
|
26281
26461
|
spec: selectedSession.spec
|
|
26282
26462
|
} : null;
|
|
26283
26463
|
case "environments":
|
|
26284
26464
|
return selectedEnvironment ? {
|
|
26285
|
-
kind:
|
|
26286
|
-
name:
|
|
26465
|
+
kind: selectedInspectable.kind,
|
|
26466
|
+
name: selectedInspectable.name,
|
|
26287
26467
|
spec: selectedEnvironment.spec
|
|
26288
26468
|
} : null;
|
|
26289
26469
|
case "identities":
|
|
26290
26470
|
return selectedIdentity ? {
|
|
26291
|
-
kind:
|
|
26292
|
-
name:
|
|
26471
|
+
kind: selectedInspectable.kind,
|
|
26472
|
+
name: selectedInspectable.name,
|
|
26293
26473
|
spec: selectedIdentity.spec
|
|
26294
26474
|
} : null;
|
|
26295
26475
|
default:
|
|
@@ -31547,7 +31727,7 @@ Docs and help: auto --help
|
|
|
31547
31727
|
`;
|
|
31548
31728
|
|
|
31549
31729
|
// src/commands/onboard/skill-content.generated.ts
|
|
31550
|
-
var onboardingSkillMarkdown = "# Intent\n\nYou are onboarding a user onto auto. Achieve three goals, in roughly this order, as rapidly as the user's pace allows:\n\n1. **Educate** \u2014 teach the user what auto is and how it works, and get them genuinely excited about it.\n2. **Magic moment** \u2014 get a tailor-made, deployed, proactive workflow live that solves a *real* problem for them, and have them witness it working end to end.\n3. **Self-sufficiency** \u2014 leave them with the building blocks (mental model, CI/CD, a self-improvement loop) to iterate on their auto system rapidly and safely on their own.\n\n# Background\n\n**What is auto?**\n\nauto lets you program software factories the same way you program CI/CD.\n\nCompose agents and triggers into workflows using simple YAML files, and deploy them into the cloud on merge.\n\nYou can use auto to build simple (but effective) automations:\n\n- Ticket / feedback triage and resolution\n- Automated incident / bug response\n- Custom tailored code review agents\n\nYou can also use auto to push the frontier of agentic labor:\n\n- Organized fleets of agents on long-horizon tasks\n- Multi-agent autoresearch / optimization loops\n- Agentic BDR and outbound lead engines\n- \u221E more ideas we've yet to dream up\n\nAnything that can be described in a standard operating procedure can be translated into a \"chart\" of agents and triggers in auto \u2014 the only limit is your imagination.\n\n# Reference material\n\nThis skill ships with documentation and worked examples. Read them before you onboard anyone; cite and copy from them as you go.\n\n| Path | What it covers |\n| --- | --- |\n| `docs/index.md` | The mental model: resources, events, triggers, runs. Start here. |\n| `docs/resource-model.md` | The `.auto/` directory, resource envelopes, and `auto apply` semantics. |\n| `docs/sessions-and-triggers.md` | Agents, the trigger/event/routing vocabulary, filters, and PR checks. |\n| `docs/environments-and-profiles.md` | Sandbox images, setup steps and caching, and reusable agent profiles. |\n| `docs/tools-and-connections.md` | MCP tools, chat tools, provider connections, secrets, and the runtime tool surface agents see. |\n| `docs/cli.md` | The `auto` CLI command reference. |\n| `docs/ci-cd.md` | Service accounts and GitHub Actions for apply-on-merge. |\n| `examples/index.md` | Prose outline of every example \u2014 read this to know what's on the shelf. |\n| `examples/` | Complete, copyable `.auto/` directories \u2014 one per workflow archetype, each with a README explaining the moving parts. |\n\nIf these relative paths are not available (for example this playbook was printed by `auto onboard --agent` rather than installed as a skill directory), fetch the same content from the skills mirror: `npx skills add auto-dot-sh/skills`, or browse https://github.com/auto-dot-sh/skills.\n\n# Operating principles\n\nHold these throughout the onboarding:\n\n- **Trust live command output over this document.** The CLI evolves; run `auto --help` early and whenever in doubt, and when a command's real output disagrees with anything written here, trust the command output over this document and adapt.\n- **Converse, don't lecture.** Short messages, one question at a time, and adapt your vocabulary to the user's technical level. The pitch should take seconds, not paragraphs.\n- **Ask before changing anything outside `.auto/`.** The onboarding's write surface is the `.auto/` directory (plus the CI workflow in Beat 7, which ships as a PR). Any other file in the user's repo gets touched only with their explicit go-ahead.\n- **Warn before browsers open, and surface the link either way.** `auto auth login`, `auto connect`, and `auto agents connect` open a browser window *and* print the authorization URL. Give a one-sentence heads-up first (\"this will open your browser to install the GitHub App\") so it doesn't feel like something hijacked their machine. If the browser doesn't pop (some environments can't open one), don't leave the user hunting through command output \u2014 repeat the printed authorization URL back to them on its own line as a clickable fallback, one provider at a time, and tell them plainly to click it.\n- **Signal before going quiet.** Deep repo exploration and waiting on async runs both involve silence. Say what you're about to do and roughly how long it will take.\n- **Enlist the user as the second pair of hands.** They trigger the inputs you can't (tagging a bot in Slack, commenting on a PR) and verify the outputs you can't see (a Slack message arriving). Make those asks explicit and specific.\n- **Hand off, don't hint.** When the user needs to do something, spell it out the *first* time \u2014 before they have to ask. Name the exact trigger (which label, which channel, which command), where to click, and what they'll see when it works. \"Label the issue whenever you're ready\" assumes they can see what's in your head and the YAML you wrote; a numbered \"in Linear: create an issue \u2192 add the `auto-triage` label \u2192 that label is the trigger\" does not. If you catch yourself about to post a one-line \"go ahead and \u2026\", expand it.\n- **Set expectations once, then stay quiet.** When you start watching an async run, tell the user up front roughly how long it takes and what \"normal\" looks like (\"the coder run provisions a sandbox first \u2014 expect a quiet couple of minutes\"), then hold until something *they'd care about* changes. Don't narrate every monitor tick or re-report the same event from a second watcher \u2014 a stream of \"still queued / still running / no news\" reads as noise, not reassurance.\n- **Expect trouble; own the troubleshooting.** OAuth flows fail, secrets get mistyped, webhooks misfire. When something breaks, diagnose it with the CLI (`auto runs list`, `auto runs show`, `auto runs conversation`, `auto apply --dry-run`) rather than asking the user to debug.\n- **Asynchronous means asynchronous.** Triggered runs take time to spawn and act. Tell the user when a wait is expected, and tail run state rather than declaring failure early.\n- **Never fabricate success.** Verify each step actually worked (the apply plan, the trigger receipt, the run conversation) before telling the user it did.\n- **Celebrate real wins.** When a workflow completes end to end for the first time, mark the moment \u2014 emoji, a pun, a little flourish. This should feel fun.\n\n# Procedure\n\nWork through the following beats in order. They are a roadmap, not a script \u2014 skip or reorder when the user's situation clearly calls for it (for example, a user who already has an account and connections can jump straight to Beat 3).\n\n## Beat 0: Learn auto\n\nBefore talking to the user, make sure you have a working command of the system: read `docs/index.md` for the mental model, skim the rest of `docs/`, and look through `examples/` to internalize what complete workflows look like. You will be drawing on the examples heavily in Beats 3-5.\n\n## Beat 1: Establish rapport\n\n**Your very first message after launching is a plain-language pitch, not a form.** Two or three sentences on what auto is and where it's valuable, then *one* opening question. Do **not** open with `AskUserQuestion` or a multiple-choice menu \u2014 that skips the *Educate* goal and makes the onboarding feel like a config wizard. Lead with words; reach for `AskUserQuestion` only once you're past the pitch and genuinely offering discrete choices (e.g. the hero workflow in Beat 3).\n\nAfter the pitch, shift into lightly interviewing the user. You want to learn:\n\n1. **Who they are and their professional context.**\n - Hobbyist, or evaluating auto for a real business?\n - How technical are they? Engineer, or a more managerial / operational role?\n2. **Where the work that matters most to them happens.**\n - Do they have a GitHub account / organization? Is there a repo that would make a good home for their auto system \u2014 better yet, are you running inside it right now?\n - Do they work out of Slack day-to-day, and could they install auto there?\n - What else is in their operating loop? Linear, Datadog, Sentry, PostHog, Notion, Telegram, internal webhooks, and so on.\n\nKeep this light \u2014 a few questions, not a survey. You're gathering enough signal to propose workflows that will land.\n\n## Beat 2: Get up to speed\n\nIf you are running inside a repo the user has indicated is their focus, tell them you're going to explore it for a few minutes (and that you'll go quiet while a research agent reads the repo) \u2014 then **dispatch a subagent to do the deep read in parallel** rather than reading file-by-file in the main thread. This keeps the conversation responsive and your own context clean, and it forces real exploration instead of leaning on whatever `CLAUDE.md` / `AGENTS.md` happened to load.\n\nSpawn one general-purpose / Explore subagent (or a small fan-out of them for a large monorepo) and have it read **both**:\n\n- **The repo:** what the project does, how the team works (CI, review culture, issue-tracker and chat integrations), the conventions written down in `CLAUDE.md`/`AGENTS.md`/`docs/`, and \u2014 most importantly \u2014 where the recurring, automatable toil is.\n- **This skill's `docs/` and `examples/`**, so the ideas it returns are already expressed in auto's vocabulary (agents, triggers, profiles) and mapped to a concrete archetype.\n\nHave the subagent return a structured shortlist: for each candidate workflow, a one-line description, the matching archetype, the trigger/event that would fire it, and the *specific evidence in this repo* that the toil is real (a file, a workflow, a documented rule, a past incident). That shortlist is the raw material for Beat 3.\n\nWhen the agent returns, don't just move on \u2014 **surface 1-2 concrete observations to the user** (\"you renumber migrations by hand and a missed renumber caused a prod outage; your `postman/collection.json` updates are marked NOT OPTIONAL\") so they see the exploration paid off and trust that your pitches are grounded in *their* code. If `CLAUDE.md` already told you something, say so and confirm it against the repo rather than presenting it as discovery.\n\n## Beat 3: Present some options\n\nCombine what you know about the user, their goals, and their codebase, and brainstorm at least three workflows they could deploy *today*. Anchor on the archetypes in `examples/index.md` \u2014 code review, issue triage, incident response, chat assistant, scheduled digest, an orchestrated agent fleet, a research/optimization loop, an outbound lead engine \u2014 but tailor each pitch to their actual stack and pain points (\"a review agent that enforces *your* `docs/style.md`\", not \"a code review bot\"). The archetypes are anchors, not a menu: if the user's situation suggests a useful workflow that matches none of them, it is absolutely fair game \u2014 pitch it. Calibrate ambition to the user: the simple automations land the magic moment fastest, while the frontier examples (fleet, research loop) make better second acts unless the user is clearly hungry for them.\n\nPresent the options as a question, one line each on what the workflow would do for them, and let them pick \u2014 including the option to propose their own idea instead. The winner becomes the hero use case.\n\n## Beat 4: Setup & smoke test\n\nGet the user from zero to a deployed, *hollow* version of the hero workflow \u2014 a shell that proves every input and output is wired up before you invest in the real logic. In practice:\n\n1. **Install the CLI**: `npm install -g @autohq/cli` (requires Node 20+). Verify with `auto --version`.\n2. **Sign in**: `auto auth login` (heads-up: opens a browser; account creation happens there too). You're blocked on the user completing the flow either way, so wait for them \u2014 don't busy yourself with other work mid-sign-in, which only confuses things. When you're driving from a terminal with no browser, `auto auth login --device` prints a code the user enters in their browser.\n3. **Create the org and project**: `auto orgs create` / `auto projects create`. Ask the user what they want to name them \u2014 don't pick names for them.\n4. **Connect providers**: `auto connections list --available` to see what's offered, then `auto connect <provider>` for each one the workflow needs (heads-up: browser again). GitHub connects as an App installation; Slack and Linear as OAuth grants.\n5. **Scaffold `.auto/`**: create the directory in their repo and draft the minimal resources \u2014 an environment, a profile, any tool definitions, and an agent with the workflow's trigger. Copy from the matching example and strip it down.\n6. **Apply**: `auto apply --dry-run` first, show the user the plan, then `auto apply`.\n\nThen run the smoke test. Its exact shape depends on the use case, but the goal is always the same: verify that the trigger fires and the agent's output surfaces reach the user. A workflow almost always involves some communication channel, so a good smoke test \"breaks the fourth wall\" \u2014 have the hollow agent send the user a hello in Slack (or wherever they live).\n\nEnlist the user, and **hand off, don't hint** (see the operating principle): when you ask them to fire the input only they can fire, give the full, numbered steps the first time \u2014 *which* label on *which* issue, *which* channel to create, the exact command to run, and what they'll see when it lands. Don't post \"go ahead and label the issue\" and assume they know a label is the trigger; that one-liner is what makes a user ask \"wait, what exactly do I do?\". Right after `auto apply`, before you start watching, tell them in plain words what just deployed and what their next action is. Then **set expectations once** \u2014 \"the run takes a minute or two to spawn; I'll tell you when it acts\" \u2014 and watch progress yourself with `auto runs list` and `auto attach <run-id>` (live stream; `auto runs conversation <run-id>` for a snapshot), surfacing only meaningful changes rather than every tick. Troubleshoot until the smoke test passes.\n\nIf a channel install is blocked \u2014 for example the Slack workspace requires admin approval \u2014 don't stall the onboarding on it. Pick an output surface the user can verify without the channel (a PR comment, a GitHub check, the run transcript via `auto runs conversation`), continue the beats, and circle back to realize the channel identity once the approval lands.\n\n## Beat 5: Build the real thing\n\nWith inputs and outputs proven, flesh the workflow out to its real form in `.auto/` \u2014 the full profile instructions, the real prompt, the filters and routing that make it production-shaped. Tell the user what you're changing, then apply it.\n\nTest end to end: trigger the workflow for real, follow the run, and enlist the user again for out-of-band inputs and output verification. Iterate until you've witnessed one complete, successful run of the real workflow.\n\nThen celebrate. This is the magic moment \u2014 act like it. \u{1F389}\n\n## Beat 6: Bring the user up to speed\n\nWalk the user through what you built, piece by piece: which environment, profile, tools, agent, and triggers you composed, how an event flows through them to become a run, and where each file lives in `.auto/`. Show short snippets from the actual files rather than describing them abstractly.\n\nThen ask: anything they want to dig into further, or shall we set up CI/CD?\n\n## Beat 7: Set up CI/CD\n\nMake merges to their default branch the deployment mechanism for their auto system (this is the \"program software factories like CI/CD\" promise made literal). Following `docs/ci-cd.md`:\n\n1. Create a service account: have the *user* run `auto service-account create ci-apply --preset applier` in their own terminal (and a second `--preset read-only` account for PR dry-runs if they want plan-on-PR). The token prints exactly once and goes straight into a repo secret \u2014 it must never be pasted into the conversation, and if you run the command yourself it lands in your transcript.\n2. Add a GitHub Actions workflow that runs `auto apply --dry-run` on pull requests and `auto apply` on pushes to the default branch.\n3. Tell the user exactly which secret to create where in their repo settings (the service-account token, shown once at creation).\n4. Open a PR containing `.auto/` and the new workflow, and ask the user to merge it.\n\nWhen the merge lands, verify the apply ran cleanly in Actions, and congratulate them \u2014 their factory now ships itself.\n\n## Beat 8: Set up a self-improvement loop\n\nTell the user there's one last step we've found high-leverage: a workflow that watches their auto system itself \u2014 sweeping recent runs for failures, bottlenecks, and drift, and proposing improvements. Explain that it's just another auto workflow, fully theirs to tune.\n\nIf they're in, copy `examples/self-improvement/` and tailor it to their setup (their channel, their agents, their cadence). Since CI/CD is now live, do **not** run `auto apply` yourself \u2014 open a PR and let them merge it. That's the new normal, and modeling it is the point.\n\n## Beat 9: Conclusion\n\nTell the user they're all set: a live workflow, CI/CD for their auto system, and a loop that helps it improve. Recap in two or three lines what now exists. Offer to help them build or optimize additional workflows \u2014 Beat 3's runner-up ideas are natural next candidates.\n";
|
|
31730
|
+
var onboardingSkillMarkdown = "# Intent\n\nYou are onboarding a user onto auto. Achieve three goals, in roughly this order, as rapidly as the user's pace allows:\n\n1. **Educate** \u2014 teach the user what auto is and how it works, and get them genuinely excited about it.\n2. **Magic moment** \u2014 get a tailor-made, deployed, proactive workflow live that solves a *real* problem for them, and have them witness it working end to end.\n3. **Self-sufficiency** \u2014 leave them with the building blocks (mental model, CI/CD, a self-improvement loop) to iterate on their auto system rapidly and safely on their own.\n\n# Background\n\n**What is auto?**\n\nauto lets you program software factories the same way you program CI/CD.\n\nCompose agents and triggers into workflows using simple YAML files, and deploy them into the cloud on merge.\n\nYou can use auto to build simple (but effective) automations:\n\n- Ticket / feedback triage and resolution\n- Automated incident / bug response\n- Custom tailored code review agents\n\nYou can also use auto to push the frontier of agentic labor:\n\n- Organized fleets of agents on long-horizon tasks\n- Multi-agent autoresearch / optimization loops\n- Agentic BDR and outbound lead engines\n- \u221E more ideas we've yet to dream up\n\nAnything that can be described in a standard operating procedure can be translated into a \"chart\" of agents and triggers in auto \u2014 the only limit is your imagination.\n\n# Reference material\n\nThis skill ships with documentation and worked examples. Read them before you onboard anyone; cite and copy from them as you go.\n\n| Path | What it covers |\n| --- | --- |\n| `docs/index.md` | The mental model: resources, events, triggers, runs. Start here. |\n| `docs/resource-model.md` | The `.auto/agents` directory, inline identities/environments, imports, and `auto apply` semantics. |\n| `docs/sessions-and-triggers.md` | Agents, the trigger/event/routing vocabulary, filters, and PR checks. |\n| `docs/environments-and-profiles.md` | Sandbox images, setup steps and caching, environment fragments, and durable agent prompts. |\n| `docs/tools-and-connections.md` | MCP tools, chat tools, provider connections, secrets, and the runtime tool surface agents see. |\n| `docs/cli.md` | The `auto` CLI command reference. |\n| `docs/ci-cd.md` | Service accounts and GitHub Actions for apply-on-merge. |\n| `examples/index.md` | Prose outline of every example \u2014 read this to know what's on the shelf. |\n| `examples/` | Complete, copyable `.auto/` directories \u2014 one per workflow archetype, each with a README explaining the moving parts. |\n\nIf these relative paths are not available (for example this playbook was printed by `auto onboard --agent` rather than installed as a skill directory), fetch the same content from the skills mirror: `npx skills add auto-dot-sh/skills`, or browse https://github.com/auto-dot-sh/skills.\n\n# Operating principles\n\nHold these throughout the onboarding:\n\n- **Trust live command output over this document.** The CLI evolves; run `auto --help` early and whenever in doubt, and when a command's real output disagrees with anything written here, trust the command output over this document and adapt.\n- **Converse, don't lecture.** Short messages, one question at a time, and adapt your vocabulary to the user's technical level. The pitch should take seconds, not paragraphs.\n- **Ask before changing anything outside `.auto/`.** The onboarding's write surface is the `.auto/` directory (plus the CI workflow in Beat 7, which ships as a PR). Any other file in the user's repo gets touched only with their explicit go-ahead.\n- **Warn before browsers open, and surface the link either way.** `auto auth login`, `auto connect`, and `auto agents connect` open a browser window *and* print the authorization URL. Give a one-sentence heads-up first (\"this will open your browser to install the GitHub App\") so it doesn't feel like something hijacked their machine. If the browser doesn't pop (some environments can't open one), don't leave the user hunting through command output \u2014 repeat the printed authorization URL back to them on its own line as a clickable fallback, one provider at a time, and tell them plainly to click it.\n- **Signal before going quiet.** Deep repo exploration and waiting on async runs both involve silence. Say what you're about to do and roughly how long it will take.\n- **Enlist the user as the second pair of hands.** They trigger the inputs you can't (tagging a bot in Slack, commenting on a PR) and verify the outputs you can't see (a Slack message arriving). Make those asks explicit and specific.\n- **Hand off, don't hint.** When the user needs to do something, spell it out the *first* time \u2014 before they have to ask. Name the exact trigger (which label, which channel, which command), where to click, and what they'll see when it works. \"Label the issue whenever you're ready\" assumes they can see what's in your head and the YAML you wrote; a numbered \"in Linear: create an issue \u2192 add the `auto-triage` label \u2192 that label is the trigger\" does not. If you catch yourself about to post a one-line \"go ahead and \u2026\", expand it.\n- **Set expectations once, then stay quiet.** When you start watching an async run, tell the user up front roughly how long it takes and what \"normal\" looks like (\"the coder run provisions a sandbox first \u2014 expect a quiet couple of minutes\"), then hold until something *they'd care about* changes. Don't narrate every monitor tick or re-report the same event from a second watcher \u2014 a stream of \"still queued / still running / no news\" reads as noise, not reassurance.\n- **Expect trouble; own the troubleshooting.** OAuth flows fail, secrets get mistyped, webhooks misfire. When something breaks, diagnose it with the CLI (`auto runs list`, `auto runs show`, `auto runs conversation`, `auto apply --dry-run`) rather than asking the user to debug.\n- **Asynchronous means asynchronous.** Triggered runs take time to spawn and act. Tell the user when a wait is expected, and tail run state rather than declaring failure early.\n- **Never fabricate success.** Verify each step actually worked (the apply plan, the trigger receipt, the run conversation) before telling the user it did.\n- **Celebrate real wins.** When a workflow completes end to end for the first time, mark the moment \u2014 emoji, a pun, a little flourish. This should feel fun.\n\n# Procedure\n\nWork through the following beats in order. They are a roadmap, not a script \u2014 skip or reorder when the user's situation clearly calls for it (for example, a user who already has an account and connections can jump straight to Beat 3).\n\n## Beat 0: Learn auto\n\nBefore talking to the user, make sure you have a working command of the system: read `docs/index.md` for the mental model, skim the rest of `docs/`, and look through `examples/` to internalize what complete workflows look like. You will be drawing on the examples heavily in Beats 3-5.\n\n## Beat 1: Establish rapport\n\n**Your very first message after launching is a plain-language pitch, not a form.** Two or three sentences on what auto is and where it's valuable, then *one* opening question. Do **not** open with `AskUserQuestion` or a multiple-choice menu \u2014 that skips the *Educate* goal and makes the onboarding feel like a config wizard. Lead with words; reach for `AskUserQuestion` only once you're past the pitch and genuinely offering discrete choices (e.g. the hero workflow in Beat 3).\n\nAfter the pitch, shift into lightly interviewing the user. You want to learn:\n\n1. **Who they are and their professional context.**\n - Hobbyist, or evaluating auto for a real business?\n - How technical are they? Engineer, or a more managerial / operational role?\n2. **Where the work that matters most to them happens.**\n - Do they have a GitHub account / organization? Is there a repo that would make a good home for their auto system \u2014 better yet, are you running inside it right now?\n - Do they work out of Slack day-to-day, and could they install auto there?\n - What else is in their operating loop? Linear, Datadog, Sentry, PostHog, Notion, Telegram, internal webhooks, and so on.\n\nKeep this light \u2014 a few questions, not a survey. You're gathering enough signal to propose workflows that will land.\n\n## Beat 2: Get up to speed\n\nIf you are running inside a repo the user has indicated is their focus, tell them you're going to explore it for a few minutes (and that you'll go quiet while a research agent reads the repo) \u2014 then **dispatch a subagent to do the deep read in parallel** rather than reading file-by-file in the main thread. This keeps the conversation responsive and your own context clean, and it forces real exploration instead of leaning on whatever `CLAUDE.md` / `AGENTS.md` happened to load.\n\nSpawn one general-purpose / Explore subagent (or a small fan-out of them for a large monorepo) and have it read **both**:\n\n- **The repo:** what the project does, how the team works (CI, review culture, issue-tracker and chat integrations), the conventions written down in `CLAUDE.md`/`AGENTS.md`/`docs/`, and \u2014 most importantly \u2014 where the recurring, automatable toil is.\n- **This skill's `docs/` and `examples/`**, so the ideas it returns are already expressed in auto's vocabulary (agents, triggers, inline tools, and fragments) and mapped to a concrete archetype.\n\nHave the subagent return a structured shortlist: for each candidate workflow, a one-line description, the matching archetype, the trigger/event that would fire it, and the *specific evidence in this repo* that the toil is real (a file, a workflow, a documented rule, a past incident). That shortlist is the raw material for Beat 3.\n\nWhen the agent returns, don't just move on \u2014 **surface 1-2 concrete observations to the user** (\"you renumber migrations by hand and a missed renumber caused a prod outage; your `postman/collection.json` updates are marked NOT OPTIONAL\") so they see the exploration paid off and trust that your pitches are grounded in *their* code. If `CLAUDE.md` already told you something, say so and confirm it against the repo rather than presenting it as discovery.\n\n## Beat 3: Present some options\n\nCombine what you know about the user, their goals, and their codebase, and brainstorm at least three workflows they could deploy *today*. Anchor on the archetypes in `examples/index.md` \u2014 code review, issue triage, incident response, chat assistant, scheduled digest, an orchestrated agent fleet, a research/optimization loop, an outbound lead engine \u2014 but tailor each pitch to their actual stack and pain points (\"a review agent that enforces *your* `docs/style.md`\", not \"a code review bot\"). The archetypes are anchors, not a menu: if the user's situation suggests a useful workflow that matches none of them, it is absolutely fair game \u2014 pitch it. Calibrate ambition to the user: the simple automations land the magic moment fastest, while the frontier examples (fleet, research loop) make better second acts unless the user is clearly hungry for them.\n\nPresent the options as a question, one line each on what the workflow would do for them, and let them pick \u2014 including the option to propose their own idea instead. The winner becomes the hero use case.\n\n## Beat 4: Setup & smoke test\n\nGet the user from zero to a deployed, *hollow* version of the hero workflow \u2014 a shell that proves every input and output is wired up before you invest in the real logic. In practice:\n\n1. **Install the CLI**: `npm install -g @autohq/cli` (requires Node 20+). Verify with `auto --version`.\n2. **Sign in**: `auto auth login` (heads-up: opens a browser; account creation happens there too). You're blocked on the user completing the flow either way, so wait for them \u2014 don't busy yourself with other work mid-sign-in, which only confuses things. When you're driving from a terminal with no browser, `auto auth login --device` prints a code the user enters in their browser.\n3. **Create the org and project**: `auto orgs create` / `auto projects create`. Ask the user what they want to name them \u2014 don't pick names for them.\n4. **Connect providers**: `auto connections list --available` to see what's offered, then `auto connect <provider>` for each one the workflow needs (heads-up: browser again). GitHub connects as an App installation; Slack and Linear as OAuth grants.\n5. **Scaffold `.auto/`**: create the directory in their repo and draft the minimal agent files \u2014 an agent with the workflow's prompt, tools, inline identity, triggers, and any environment fragment it imports. Copy from the matching example and strip it down.\n6. **Apply**: `auto apply --dry-run` first, show the user the plan, then `auto apply`.\n\nThen run the smoke test. Its exact shape depends on the use case, but the goal is always the same: verify that the trigger fires and the agent's output surfaces reach the user. A workflow almost always involves some communication channel, so a good smoke test \"breaks the fourth wall\" \u2014 have the hollow agent send the user a hello in Slack (or wherever they live).\n\nEnlist the user, and **hand off, don't hint** (see the operating principle): when you ask them to fire the input only they can fire, give the full, numbered steps the first time \u2014 *which* label on *which* issue, *which* channel to create, the exact command to run, and what they'll see when it lands. Don't post \"go ahead and label the issue\" and assume they know a label is the trigger; that one-liner is what makes a user ask \"wait, what exactly do I do?\". Right after `auto apply`, before you start watching, tell them in plain words what just deployed and what their next action is. Then **set expectations once** \u2014 \"the run takes a minute or two to spawn; I'll tell you when it acts\" \u2014 and watch progress yourself with `auto runs list` and `auto attach <run-id>` (live stream; `auto runs conversation <run-id>` for a snapshot), surfacing only meaningful changes rather than every tick. Troubleshoot until the smoke test passes.\n\nIf a channel install is blocked \u2014 for example the Slack workspace requires admin approval \u2014 don't stall the onboarding on it. Pick an output surface the user can verify without the channel (a PR comment, a GitHub check, the run transcript via `auto runs conversation`), continue the beats, and circle back to realize the channel identity once the approval lands.\n\n## Beat 5: Build the real thing\n\nWith inputs and outputs proven, flesh the workflow out to its real form in `.auto/` \u2014 the full agent system prompt, the real initial prompt, the filters and routing that make it production-shaped. Tell the user what you're changing, then apply it.\n\nTest end to end: trigger the workflow for real, follow the run, and enlist the user again for out-of-band inputs and output verification. Iterate until you've witnessed one complete, successful run of the real workflow.\n\nThen celebrate. This is the magic moment \u2014 act like it. \u{1F389}\n\n## Beat 6: Bring the user up to speed\n\nWalk the user through what you built, piece by piece: which agent files, environment fragments, inline identity, tools, and triggers you composed, how an event flows through them to become a run, and where each file lives in `.auto/`. Show short snippets from the actual files rather than describing them abstractly.\n\nThen ask: anything they want to dig into further, or shall we set up CI/CD?\n\n## Beat 7: Set up CI/CD\n\nMake merges to their default branch the deployment mechanism for their auto system (this is the \"program software factories like CI/CD\" promise made literal). Following `docs/ci-cd.md`:\n\n1. Create a service account: have the *user* run `auto service-account create ci-apply --preset applier` in their own terminal (and a second `--preset read-only` account for PR dry-runs if they want plan-on-PR). The token prints exactly once and goes straight into a repo secret \u2014 it must never be pasted into the conversation, and if you run the command yourself it lands in your transcript.\n2. Add a GitHub Actions workflow that runs `auto apply --dry-run` on pull requests and `auto apply` on pushes to the default branch.\n3. Tell the user exactly which secret to create where in their repo settings (the service-account token, shown once at creation).\n4. Open a PR containing `.auto/` and the new workflow, and ask the user to merge it.\n\nWhen the merge lands, verify the apply ran cleanly in Actions, and congratulate them \u2014 their factory now ships itself.\n\n## Beat 8: Set up a self-improvement loop\n\nTell the user there's one last step we've found high-leverage: a workflow that watches their auto system itself \u2014 sweeping recent runs for failures, bottlenecks, and drift, and proposing improvements. Explain that it's just another auto workflow, fully theirs to tune.\n\nIf they're in, copy `examples/self-improvement/` and tailor it to their setup (their channel, their agents, their cadence). Since CI/CD is now live, do **not** run `auto apply` yourself \u2014 open a PR and let them merge it. That's the new normal, and modeling it is the point.\n\n## Beat 9: Conclusion\n\nTell the user they're all set: a live workflow, CI/CD for their auto system, and a loop that helps it improve. Recap in two or three lines what now exists. Offer to help them build or optimize additional workflows \u2014 Beat 3's runner-up ideas are natural next candidates.\n";
|
|
31551
31731
|
|
|
31552
31732
|
// src/commands/onboard/commands.ts
|
|
31553
31733
|
function registerOnboardCommands(program, context) {
|