@aident-ai/cli 0.1.8 → 0.2.0-rc.0
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 +9 -2
- package/dist/cli.mjs +145 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,8 +97,12 @@ providers to Loadout integrations, and starts selected Vault/OAuth connect flows
|
|
|
97
97
|
|
|
98
98
|
`skills favorite` saves the account preference and immediately synchronizes all current favorites. `skills sync`
|
|
99
99
|
reconciles each current public revision into `~/.agents/skills` and links it into supported harness-global Skill
|
|
100
|
-
directories, where the deterministic `loadout-<slug>-<id>` name is available as a slash command.
|
|
101
|
-
|
|
100
|
+
directories, where the deterministic `loadout-<slug>-<id>` name is available as a slash command. Its discovery
|
|
101
|
+
description uses the reviewed display name and summary for the CLI's system language, with English fallback. The CLI
|
|
102
|
+
tracks its owned paths in `~/.aident/favorite-skills.json` and never overwrites or removes unmanaged paths. During
|
|
103
|
+
normal authenticated commands, the server compares the manifest state with the user's current favorites. When they
|
|
104
|
+
differ, the CLI tells the agent to finish the current task and ask the user before running `aident skills sync`; it
|
|
105
|
+
never synchronizes favorite Skills automatically.
|
|
102
106
|
|
|
103
107
|
`billing balance` keeps `balance` and returns `currentCreditSource` for the currently selected wallet. The legacy
|
|
104
108
|
`creditSource` alias remains available for compatibility. The response also returns `wallets.personal` plus
|
|
@@ -109,6 +113,9 @@ uncharged and historical rows return `null`. Team owners can pass `--scope team`
|
|
|
109
113
|
active members instead of just their own: each entry adds `actingUserId`/`actingUserEmail`/`actingUserName`, and the
|
|
110
114
|
summary adds a `byActingUser` breakdown. `--scope team` is rejected for anyone who isn't the owner of a team with
|
|
111
115
|
credit sharing enabled; the default `--scope mine` behavior is unchanged.
|
|
116
|
+
Successful self-owned rows can include `resultFiles` with a direct `downloadUrl` and nullable `expiresAt`, allowing a
|
|
117
|
+
caller to recover persisted output after an interrupted response. Audit output does not expose internal asset IDs, and
|
|
118
|
+
team scope does not expose another member's result files.
|
|
112
119
|
|
|
113
120
|
## Configuration
|
|
114
121
|
|
package/dist/cli.mjs
CHANGED
|
@@ -88,12 +88,12 @@ async function login(options) {
|
|
|
88
88
|
const baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
89
89
|
const writeInfo = options.format === "json" ? logErr : logInfo;
|
|
90
90
|
if (options.oob)
|
|
91
|
-
return loginOob(baseUrl, writeInfo, options.format === "json" ? process.stderr : process.stdout);
|
|
91
|
+
return loginOob(baseUrl, writeInfo, options.format === "json" ? process.stderr : process.stdout, options.ref);
|
|
92
92
|
try {
|
|
93
|
-
return await loginLoopback(baseUrl, writeInfo);
|
|
93
|
+
return await loginLoopback(baseUrl, writeInfo, options.ref);
|
|
94
94
|
} catch (err) {
|
|
95
95
|
logErr(`Loopback OAuth failed (${err instanceof Error ? err.message : String(err)}). Falling back to OOB flow.`);
|
|
96
|
-
return loginOob(baseUrl, writeInfo, options.format === "json" ? process.stderr : process.stdout);
|
|
96
|
+
return loginOob(baseUrl, writeInfo, options.format === "json" ? process.stderr : process.stdout, options.ref);
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
async function refreshToken(creds) {
|
|
@@ -128,7 +128,7 @@ async function logout(creds) {
|
|
|
128
128
|
return;
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
|
-
async function loginLoopback(baseUrl, writeInfo) {
|
|
131
|
+
async function loginLoopback(baseUrl, writeInfo, ref) {
|
|
132
132
|
const verifier = base64UrlEncode(randomBytes(48));
|
|
133
133
|
const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
|
|
134
134
|
const state = base64UrlEncode(randomBytes(16));
|
|
@@ -143,6 +143,8 @@ async function loginLoopback(baseUrl, writeInfo) {
|
|
|
143
143
|
authorizeUrl.searchParams.set("code_challenge", challenge);
|
|
144
144
|
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
145
145
|
authorizeUrl.searchParams.set("state", state);
|
|
146
|
+
if (ref)
|
|
147
|
+
authorizeUrl.searchParams.set("via", ref);
|
|
146
148
|
const authorizeUrlString = authorizeUrl.toString();
|
|
147
149
|
setExpectedOpenRedirectUrl(authorizeUrlString);
|
|
148
150
|
const loginOpenUrl = buildLoginOpenUrl(port, state, authorizeUrlString);
|
|
@@ -158,7 +160,7 @@ async function loginLoopback(baseUrl, writeInfo) {
|
|
|
158
160
|
const tok = await exchangeCode(baseUrl, clientId, code, redirectUri, verifier);
|
|
159
161
|
return buildCreds(baseUrl, clientId, tok);
|
|
160
162
|
}
|
|
161
|
-
async function loginOob(baseUrl, writeInfo, promptOutput) {
|
|
163
|
+
async function loginOob(baseUrl, writeInfo, promptOutput, ref) {
|
|
162
164
|
const redirectUri = `${baseUrl}/mcp/oob`;
|
|
163
165
|
const verifier = base64UrlEncode(randomBytes(48));
|
|
164
166
|
const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
|
|
@@ -174,6 +176,8 @@ async function loginOob(baseUrl, writeInfo, promptOutput) {
|
|
|
174
176
|
authorizeUrl.searchParams.set("code_challenge", challenge);
|
|
175
177
|
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
176
178
|
authorizeUrl.searchParams.set("state", state);
|
|
179
|
+
if (ref)
|
|
180
|
+
authorizeUrl.searchParams.set("via", ref);
|
|
177
181
|
const authorizeUrlString = authorizeUrl.toString();
|
|
178
182
|
writeInfo(`Opening browser for Aident login...`);
|
|
179
183
|
writeInfo(`If the browser does not open, visit: ${authorizeUrlString}`);
|
|
@@ -598,7 +602,7 @@ function normalizeBaseUrl(url) {
|
|
|
598
602
|
}
|
|
599
603
|
|
|
600
604
|
// src/version.ts
|
|
601
|
-
var VERSION = "0.
|
|
605
|
+
var VERSION = "0.2.0-rc.0";
|
|
602
606
|
|
|
603
607
|
// src/catalogCache.ts
|
|
604
608
|
var CACHE_TTL_MS = 5 * 60 * 1000;
|
|
@@ -628,7 +632,13 @@ async function genWriteCachedCatalog(params, catalog) {
|
|
|
628
632
|
} catch {}
|
|
629
633
|
}
|
|
630
634
|
function getCacheFile(params) {
|
|
631
|
-
const key = crypto.createHash("sha256").update([
|
|
635
|
+
const key = crypto.createHash("sha256").update([
|
|
636
|
+
params.baseUrl,
|
|
637
|
+
params.packageName,
|
|
638
|
+
params.installedSkillVersion ?? "",
|
|
639
|
+
params.favoriteSkillsStateToken ?? "",
|
|
640
|
+
VERSION
|
|
641
|
+
].join("\x00")).digest("hex").slice(0, 16);
|
|
632
642
|
return join2(getAidentDir(), "cache", `catalog-${key}.json`);
|
|
633
643
|
}
|
|
634
644
|
function getCredentialFingerprint(accessToken) {
|
|
@@ -642,7 +652,7 @@ function isCommandCatalog(value) {
|
|
|
642
652
|
}
|
|
643
653
|
|
|
644
654
|
// src/loadoutSkill.ts
|
|
645
|
-
import { createHash as
|
|
655
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
646
656
|
import { lstat as lstat2, readdir as readdir2, readFile as readFile5, realpath as realpath2 } from "node:fs/promises";
|
|
647
657
|
import { basename, dirname as dirname2, join as join6 } from "node:path";
|
|
648
658
|
|
|
@@ -5552,6 +5562,20 @@ async function isExecutable(path) {
|
|
|
5552
5562
|
}
|
|
5553
5563
|
}
|
|
5554
5564
|
|
|
5565
|
+
// ../web/shared/integrations/LoadoutFavoriteSkillSyncState.ts
|
|
5566
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
5567
|
+
var AIDENT_FAVORITE_SKILLS_STATE_HEADER = "x-aident-favorite-skills-state";
|
|
5568
|
+
var LoadoutFavoriteSkillsStateTokenSchema = zod_default.string().regex(/^[a-f0-9]{64}$/);
|
|
5569
|
+
var LoadoutFavoriteSkillsUpdateSchema = zod_default.object({
|
|
5570
|
+
stateToken: LoadoutFavoriteSkillsStateTokenSchema,
|
|
5571
|
+
favoriteCount: zod_default.number().int().nonnegative(),
|
|
5572
|
+
syncRequired: zod_default.boolean()
|
|
5573
|
+
}).strict();
|
|
5574
|
+
function getLoadoutFavoriteSkillsStateToken(skills) {
|
|
5575
|
+
const state = skills.map(({ name, artifactVersionId }) => ({ name, artifactVersionId })).sort((left, right) => left.name.localeCompare(right.name));
|
|
5576
|
+
return createHash2("sha256").update(JSON.stringify(state)).digest("hex");
|
|
5577
|
+
}
|
|
5578
|
+
|
|
5555
5579
|
// ../web/shared/loadout/LoadoutUpdatePolicy.ts
|
|
5556
5580
|
var AIDENT_UPDATE_PROTOCOL_HEADER = "x-aident-update-protocol";
|
|
5557
5581
|
var AIDENT_UPDATE_PROTOCOL_VERSION = "1";
|
|
@@ -5712,6 +5736,40 @@ var KNOWN_CLEAN_LOADOUT_SKILL_REQUIRED_FILE_GIT_BLOB_SHA1 = {
|
|
|
5712
5736
|
"references/mcp.md": "4040ef157a84d9159bc8bbecd288741fd51dc751",
|
|
5713
5737
|
"references/troubleshooting.md": "f819915c8829b028630ef1f8f29ae9433a072ca8"
|
|
5714
5738
|
}
|
|
5739
|
+
],
|
|
5740
|
+
"0.4.12": [
|
|
5741
|
+
{
|
|
5742
|
+
"SKILL.md": "3808426c0802578a27e3ad984b24f546aa8cbe40",
|
|
5743
|
+
"references/api.md": "fdd5a23a72e0afd2809472d004961f11e1959bd4",
|
|
5744
|
+
"references/loadout.md": "3f6791826535bf458cb1ddcd24aee003af98a50d",
|
|
5745
|
+
"references/mcp.md": "3e92c88b1ef94e863bd4ce977a36abc3a0df2138",
|
|
5746
|
+
"references/troubleshooting.md": "f819915c8829b028630ef1f8f29ae9433a072ca8"
|
|
5747
|
+
},
|
|
5748
|
+
{
|
|
5749
|
+
"SKILL.md": "3808426c0802578a27e3ad984b24f546aa8cbe40",
|
|
5750
|
+
"references/api.md": "a6a4ff7e106245697a1a6527f0ff0d3df729bfb3",
|
|
5751
|
+
"references/loadout.md": "aa68ff08dafd97a268279b7cab532b3a4ce9d175",
|
|
5752
|
+
"references/mcp.md": "3e92c88b1ef94e863bd4ce977a36abc3a0df2138",
|
|
5753
|
+
"references/troubleshooting.md": "f819915c8829b028630ef1f8f29ae9433a072ca8"
|
|
5754
|
+
}
|
|
5755
|
+
],
|
|
5756
|
+
"0.4.13": [
|
|
5757
|
+
{
|
|
5758
|
+
"SKILL.md": "abf6057514737bbf3ca4cffc511919fc254c87c2",
|
|
5759
|
+
"references/api.md": "a6a4ff7e106245697a1a6527f0ff0d3df729bfb3",
|
|
5760
|
+
"references/loadout.md": "25a696a0107055e250424b117cee34d282784935",
|
|
5761
|
+
"references/mcp.md": "3e92c88b1ef94e863bd4ce977a36abc3a0df2138",
|
|
5762
|
+
"references/troubleshooting.md": "f819915c8829b028630ef1f8f29ae9433a072ca8"
|
|
5763
|
+
}
|
|
5764
|
+
],
|
|
5765
|
+
"0.4.14": [
|
|
5766
|
+
{
|
|
5767
|
+
"SKILL.md": "61d825a96dab110426d92cb80feb5fe40f7a010b",
|
|
5768
|
+
"references/api.md": "240b913e8c85492f2441326033db91747c54863e",
|
|
5769
|
+
"references/loadout.md": "be4dbd9e0aad75afe647800f64d2bb16c22d03a8",
|
|
5770
|
+
"references/mcp.md": "3e92c88b1ef94e863bd4ce977a36abc3a0df2138",
|
|
5771
|
+
"references/troubleshooting.md": "f819915c8829b028630ef1f8f29ae9433a072ca8"
|
|
5772
|
+
}
|
|
5715
5773
|
]
|
|
5716
5774
|
};
|
|
5717
5775
|
async function fetchLoadoutSkillMetadata(baseUrl) {
|
|
@@ -5734,7 +5792,7 @@ function isLoadoutSkillMetadata(value) {
|
|
|
5734
5792
|
if (!value || typeof value !== "object")
|
|
5735
5793
|
return false;
|
|
5736
5794
|
const body = value;
|
|
5737
|
-
return body.product === "loadout" && typeof body.skillUrl === "string" && typeof body.skillVersion === "string" && typeof body.updatedAt === "string" && typeof body.setupPrompt === "string" && typeof body.updatePrompt === "string" && typeof body.minCliVersion === "string" && typeof body.recommendedCliVersion === "string" && (body.localIntegrationMigrationPromptEnabled === undefined || typeof body.localIntegrationMigrationPromptEnabled === "boolean") && (body.updatePolicy === undefined || LoadoutUpdatePolicySchema.safeParse(body.updatePolicy).success) && Array.isArray(body.notices) && body.notices.every(isLoadoutSkillNotice);
|
|
5795
|
+
return body.product === "loadout" && typeof body.skillUrl === "string" && typeof body.skillVersion === "string" && typeof body.updatedAt === "string" && typeof body.setupPrompt === "string" && typeof body.updatePrompt === "string" && typeof body.minCliVersion === "string" && typeof body.recommendedCliVersion === "string" && (body.localIntegrationMigrationPromptEnabled === undefined || typeof body.localIntegrationMigrationPromptEnabled === "boolean") && (body.updatePolicy === undefined || LoadoutUpdatePolicySchema.safeParse(body.updatePolicy).success) && (body.favoriteSkills === undefined || LoadoutFavoriteSkillsUpdateSchema.safeParse(body.favoriteSkills).success) && Array.isArray(body.notices) && body.notices.every(isLoadoutSkillNotice);
|
|
5738
5796
|
}
|
|
5739
5797
|
function isLocalIntegrationMigrationPromptEnabled(metadata) {
|
|
5740
5798
|
return metadata?.localIntegrationMigrationPromptEnabled === true;
|
|
@@ -5844,7 +5902,7 @@ async function inspectLoadoutSkillDirectory(skillDirectory, managedReleasesRoot
|
|
|
5844
5902
|
};
|
|
5845
5903
|
}
|
|
5846
5904
|
function computeLoadoutSkillRequiredFileDigest(files) {
|
|
5847
|
-
const hash =
|
|
5905
|
+
const hash = createHash3("sha256");
|
|
5848
5906
|
for (const path of LOADOUT_SKILL_REQUIRED_FILES) {
|
|
5849
5907
|
const content = getFileContent(files, path);
|
|
5850
5908
|
if (content === undefined)
|
|
@@ -5867,7 +5925,7 @@ function computeLoadoutSkillArtifactSha256(files, version) {
|
|
|
5867
5925
|
return { path, content };
|
|
5868
5926
|
})
|
|
5869
5927
|
});
|
|
5870
|
-
return
|
|
5928
|
+
return createHash3("sha256").update(body).digest("hex");
|
|
5871
5929
|
}
|
|
5872
5930
|
function validateLoadoutSkillRequiredFileContents(files, expectedVersion) {
|
|
5873
5931
|
const frontmatter = parseSkillFrontmatter(getFileContent(files, "SKILL.md") ?? "");
|
|
@@ -5961,7 +6019,7 @@ function getFileContent(files, path) {
|
|
|
5961
6019
|
return files[path];
|
|
5962
6020
|
}
|
|
5963
6021
|
function computeGitBlobSha1(content) {
|
|
5964
|
-
return
|
|
6022
|
+
return createHash3("sha1").update(`blob ${content.byteLength}\x00`).update(content).digest("hex");
|
|
5965
6023
|
}
|
|
5966
6024
|
function isLoadoutSkillNotice(value) {
|
|
5967
6025
|
if (!value || typeof value !== "object")
|
|
@@ -5972,6 +6030,7 @@ function isLoadoutSkillNotice(value) {
|
|
|
5972
6030
|
|
|
5973
6031
|
// src/client.ts
|
|
5974
6032
|
var CLI_CATALOG_DURATION_HEADER = "x-aident-cli-catalog-duration-ms";
|
|
6033
|
+
var CLI_LOCALE = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
5975
6034
|
|
|
5976
6035
|
class CliClient {
|
|
5977
6036
|
creds;
|
|
@@ -5979,9 +6038,10 @@ class CliClient {
|
|
|
5979
6038
|
packages;
|
|
5980
6039
|
installedSkillVersion;
|
|
5981
6040
|
loadoutSkillInventory;
|
|
6041
|
+
favoriteSkillsStateToken;
|
|
5982
6042
|
commandOperations = new Map;
|
|
5983
6043
|
catalogDurationMs = null;
|
|
5984
|
-
constructor(creds, credentialSource = "stored", packages, installedSkillVersion = null, loadoutSkillInventory = null) {
|
|
6044
|
+
constructor(creds, credentialSource = "stored", packages, installedSkillVersion = null, loadoutSkillInventory = null, favoriteSkillsStateToken = null) {
|
|
5985
6045
|
this.creds = creds;
|
|
5986
6046
|
this.credentialSource = credentialSource;
|
|
5987
6047
|
if (packages.length === 0)
|
|
@@ -5989,6 +6049,7 @@ class CliClient {
|
|
|
5989
6049
|
this.packages = [...packages];
|
|
5990
6050
|
this.installedSkillVersion = installedSkillVersion;
|
|
5991
6051
|
this.loadoutSkillInventory = loadoutSkillInventory;
|
|
6052
|
+
this.favoriteSkillsStateToken = favoriteSkillsStateToken;
|
|
5992
6053
|
}
|
|
5993
6054
|
get baseUrl() {
|
|
5994
6055
|
return this.creds.base_url.replace(/\/+$/, "");
|
|
@@ -6059,13 +6120,15 @@ class CliClient {
|
|
|
6059
6120
|
accessToken: this.creds.access_token,
|
|
6060
6121
|
baseUrl: this.baseUrl,
|
|
6061
6122
|
packageName,
|
|
6062
|
-
installedSkillVersion: this.installedSkillVersion
|
|
6123
|
+
installedSkillVersion: this.installedSkillVersion,
|
|
6124
|
+
favoriteSkillsStateToken: this.favoriteSkillsStateToken
|
|
6063
6125
|
};
|
|
6064
6126
|
const cached = await genReadCachedCatalog(cacheParams);
|
|
6065
6127
|
if (cached)
|
|
6066
6128
|
return { status: 200, body: withValidLoadoutSkillMetadata(cached) };
|
|
6067
6129
|
const headers = packageName === "loadout" ? {
|
|
6068
|
-
...this.installedSkillVersion ? { "x-aident-skill-version": this.installedSkillVersion } : {}
|
|
6130
|
+
...this.installedSkillVersion ? { "x-aident-skill-version": this.installedSkillVersion } : {},
|
|
6131
|
+
...this.favoriteSkillsStateToken ? { [AIDENT_FAVORITE_SKILLS_STATE_HEADER]: this.favoriteSkillsStateToken } : {}
|
|
6069
6132
|
} : undefined;
|
|
6070
6133
|
const path = this.catalogPath(packageName);
|
|
6071
6134
|
let result;
|
|
@@ -6109,6 +6172,7 @@ class CliClient {
|
|
|
6109
6172
|
async fetchJson(method, path, body, extraHeaders) {
|
|
6110
6173
|
const headers = {
|
|
6111
6174
|
Authorization: `Bearer ${this.creds.access_token}`,
|
|
6175
|
+
"Accept-Language": CLI_LOCALE,
|
|
6112
6176
|
"User-Agent": `@aident-ai/cli/${VERSION}`,
|
|
6113
6177
|
[AIDENT_UPDATE_PROTOCOL_HEADER]: AIDENT_UPDATE_PROTOCOL_VERSION,
|
|
6114
6178
|
...extraHeaders
|
|
@@ -6474,7 +6538,7 @@ function getLocalHelp(version) {
|
|
|
6474
6538
|
"aident config get <key>",
|
|
6475
6539
|
"aident packages add <playbook|intern>",
|
|
6476
6540
|
"aident doctor",
|
|
6477
|
-
"aident setup [--client-name <name>]",
|
|
6541
|
+
"aident setup [--client-name <name>] [--ref <code>]",
|
|
6478
6542
|
"aident integrations migrate-local",
|
|
6479
6543
|
"aident <domain> <command> [--flag value ...] [--json]"
|
|
6480
6544
|
],
|
|
@@ -6663,13 +6727,19 @@ function renderCommandHelp(catalog, domain, command, subcommand) {
|
|
|
6663
6727
|
}
|
|
6664
6728
|
|
|
6665
6729
|
// src/loadoutFavoriteSkills.ts
|
|
6666
|
-
import { createHash as
|
|
6730
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
6667
6731
|
import { lstat as lstat3, mkdir as mkdir6, readFile as readFile7, readlink, rename as rename2, rm as rm2, symlink, writeFile as writeFile6 } from "node:fs/promises";
|
|
6668
6732
|
import { homedir as homedir4 } from "node:os";
|
|
6669
6733
|
import path from "node:path";
|
|
6670
6734
|
|
|
6671
6735
|
// ../web/shared/integrations/LoadoutSkillConstants.ts
|
|
6672
6736
|
var LOADOUT_SKILL_ENTRYPOINT = "SKILL.md";
|
|
6737
|
+
var LOADOUT_SKILL_PLATFORM_SECTION_HEADING = "Aident Loadout Platform";
|
|
6738
|
+
var LOADOUT_SKILL_PLATFORM_SECTION = `## **${LOADOUT_SKILL_PLATFORM_SECTION_HEADING}**
|
|
6739
|
+
|
|
6740
|
+
This Skill is authored, published, and distributed through [**Aident Loadout**](https://loadout.aident.ai/), a platform that enables agents to connect securely with more than 1,000 popular apps and tools.
|
|
6741
|
+
|
|
6742
|
+
Before using this Skill, verify that the Aident Loadout Skill, CLI, Plugin, or MCP is installed globally in the current environment. If Aident Loadout is already available, continue with this Skill and complete any setup required by the selected integrations. If it is unavailable or its installation status is uncertain, follow the [**Aident Loadout setup instructions**](https://aident.ai/SETUP.md). After installation is verified, return to the campaign brief and continue.`;
|
|
6673
6743
|
var LOADOUT_SKILL_NAME_PATTERN = /^skill:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
6674
6744
|
var LOADOUT_SKILL_MAX_FILE_COUNT = 50;
|
|
6675
6745
|
var LOADOUT_SKILL_MAX_PACKAGE_BYTES = 256 * 1024;
|
|
@@ -6731,7 +6801,7 @@ function assertPackage(pkg) {
|
|
|
6731
6801
|
packageBytes += bytes;
|
|
6732
6802
|
if (bytes !== file.sizeBytes)
|
|
6733
6803
|
throw new Error(`Size mismatch: ${pkg.name}/${file.path}`);
|
|
6734
|
-
if (
|
|
6804
|
+
if (createHash4("sha256").update(file.content).digest("hex") !== file.contentDigest) {
|
|
6735
6805
|
throw new Error(`Digest mismatch: ${pkg.name}/${file.path}`);
|
|
6736
6806
|
}
|
|
6737
6807
|
}
|
|
@@ -6754,7 +6824,7 @@ function entrypointContent(pkg, content) {
|
|
|
6754
6824
|
return [
|
|
6755
6825
|
"---",
|
|
6756
6826
|
`name: ${quoteYaml(commandName(pkg))}`,
|
|
6757
|
-
`description: ${quoteYaml(pkg.summary)}`,
|
|
6827
|
+
`description: ${quoteYaml(`${pkg.displayName}: ${pkg.summary}`)}`,
|
|
6758
6828
|
"---",
|
|
6759
6829
|
`<!-- aident-loadout-skill name=${pkg.name} artifact-version=${pkg.artifactVersionId} -->`,
|
|
6760
6830
|
"",
|
|
@@ -6779,7 +6849,7 @@ async function readManifest(home, env) {
|
|
|
6779
6849
|
throw new Error("Unsupported manifest");
|
|
6780
6850
|
const harnessRoots = new Set(getHarnessHosts(home, env).map(({ root }) => path.join(root, "skills")));
|
|
6781
6851
|
for (const skill of value.skills) {
|
|
6782
|
-
if (!LOADOUT_SKILL_NAME_PATTERN.test(skill.name) || !isCanonicalUuid(skill.artifactVersionId) || !/^loadout-[a-z0-9-]+-[0-9a-f]{8}$/.test(skill.commandName) || skill.installPath !== path.join(getCanonicalRoot(home, env), skill.commandName) || skill.linkPaths.some((linkPath) => !harnessRoots.has(path.dirname(linkPath)) || path.basename(linkPath) !== skill.commandName)) {
|
|
6852
|
+
if (!LOADOUT_SKILL_NAME_PATTERN.test(skill.name) || !isCanonicalUuid(skill.artifactVersionId) || skill.displayName !== undefined && typeof skill.displayName !== "string" || skill.summary !== undefined && typeof skill.summary !== "string" || !/^loadout-[a-z0-9-]+-[0-9a-f]{8}$/.test(skill.commandName) || skill.installPath !== path.join(getCanonicalRoot(home, env), skill.commandName) || skill.linkPaths.some((linkPath) => !harnessRoots.has(path.dirname(linkPath)) || path.basename(linkPath) !== skill.commandName)) {
|
|
6783
6853
|
throw new Error("Invalid favorite Skills ownership manifest");
|
|
6784
6854
|
}
|
|
6785
6855
|
}
|
|
@@ -6790,6 +6860,10 @@ async function readManifest(home, env) {
|
|
|
6790
6860
|
throw error;
|
|
6791
6861
|
}
|
|
6792
6862
|
}
|
|
6863
|
+
async function getInstalledLoadoutFavoriteSkillsStateToken(home = getHome(), env = process.env) {
|
|
6864
|
+
const manifest = await readManifest(home, env);
|
|
6865
|
+
return getLoadoutFavoriteSkillsStateToken(manifest.skills);
|
|
6866
|
+
}
|
|
6793
6867
|
async function writeManifest(home, manifest) {
|
|
6794
6868
|
const manifestPath = getManifestPath(home);
|
|
6795
6869
|
const temporaryPath = `${manifestPath}.${process.pid}.tmp`;
|
|
@@ -6865,7 +6939,7 @@ async function reconcileLoadoutFavoriteSkills(payload, home = getHome(), env = p
|
|
|
6865
6939
|
continue;
|
|
6866
6940
|
}
|
|
6867
6941
|
const allLinksExist = (await Promise.all(linkPaths.map(pathExists))).every(Boolean);
|
|
6868
|
-
if (previous?.artifactVersionId === pkg.artifactVersionId && previous.installPath === installPath && previous.linkPaths.length === linkPaths.length && previous.linkPaths.every((linkPath) => linkPaths.includes(linkPath)) && await pathExists(installPath) && allLinksExist) {
|
|
6942
|
+
if (previous?.artifactVersionId === pkg.artifactVersionId && previous.displayName === pkg.displayName && previous.summary === pkg.summary && previous.installPath === installPath && previous.linkPaths.length === linkPaths.length && previous.linkPaths.every((linkPath) => linkPaths.includes(linkPath)) && await pathExists(installPath) && allLinksExist) {
|
|
6869
6943
|
result.unchanged.push(pkg.name);
|
|
6870
6944
|
nextSkills.push(previous);
|
|
6871
6945
|
continue;
|
|
@@ -6910,6 +6984,8 @@ async function reconcileLoadoutFavoriteSkills(payload, home = getHome(), env = p
|
|
|
6910
6984
|
nextSkills.push({
|
|
6911
6985
|
name: pkg.name,
|
|
6912
6986
|
artifactVersionId: pkg.artifactVersionId,
|
|
6987
|
+
displayName: pkg.displayName,
|
|
6988
|
+
summary: pkg.summary,
|
|
6913
6989
|
commandName: nextCommandName,
|
|
6914
6990
|
installPath,
|
|
6915
6991
|
linkPaths
|
|
@@ -6962,7 +7038,7 @@ async function genReconcileFavoriteSkills(resolved, result, dependencies) {
|
|
|
6962
7038
|
}
|
|
6963
7039
|
|
|
6964
7040
|
// src/localIntegrationMigration.ts
|
|
6965
|
-
import { createHash as
|
|
7041
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
6966
7042
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
6967
7043
|
import { homedir as homedir5 } from "node:os";
|
|
6968
7044
|
import { basename as basename2, join as join8 } from "node:path";
|
|
@@ -7364,7 +7440,7 @@ function withoutMatchText(candidate) {
|
|
|
7364
7440
|
};
|
|
7365
7441
|
}
|
|
7366
7442
|
function buildCandidateId(candidate) {
|
|
7367
|
-
return `local_${
|
|
7443
|
+
return `local_${createHash5("sha256").update([candidate.localSource, candidate.localLabel, candidate.redactedLocator].join("\x00")).digest("hex").slice(0, 12)}`;
|
|
7368
7444
|
}
|
|
7369
7445
|
function dedupeRawCandidates(candidates) {
|
|
7370
7446
|
const byKey = new Map;
|
|
@@ -7569,6 +7645,16 @@ function buildCommandArgs(params) {
|
|
|
7569
7645
|
continue;
|
|
7570
7646
|
delete args[reserved];
|
|
7571
7647
|
}
|
|
7648
|
+
const unsupportedField = Object.keys(args).find((key) => !(key in props) && !(params.subcommand && key === "action"));
|
|
7649
|
+
if (unsupportedField) {
|
|
7650
|
+
const directField = unsupportedField.endsWith("File") ? unsupportedField.slice(0, -"File".length) : undefined;
|
|
7651
|
+
return {
|
|
7652
|
+
error: {
|
|
7653
|
+
code: "invalid-input",
|
|
7654
|
+
message: unsupportedField.includes("-") ? `Use camelCase input fields; --${unsupportedField} is not supported.` : `Unknown input field --${unsupportedField}.${directField && directField in props ? ` Pass --${directField} with the value directly.` : ""}`
|
|
7655
|
+
}
|
|
7656
|
+
};
|
|
7657
|
+
}
|
|
7572
7658
|
if (positionalJson?.args)
|
|
7573
7659
|
remaining.pop();
|
|
7574
7660
|
if (params.subcommand) {
|
|
@@ -7710,7 +7796,7 @@ import { homedir as homedir6 } from "node:os";
|
|
|
7710
7796
|
import { basename as basename3, dirname as dirname4, isAbsolute as isAbsolute3, join as join9, relative as relative2, resolve as resolve2, sep } from "node:path";
|
|
7711
7797
|
|
|
7712
7798
|
// src/loadoutSkillArtifact.ts
|
|
7713
|
-
import { createHash as
|
|
7799
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
7714
7800
|
var MAX_LOADOUT_SKILL_ARTIFACT_BYTES = 512 * 1024;
|
|
7715
7801
|
async function fetchLoadoutSkillArtifact(descriptorValue, expectedVersion, deps = {}) {
|
|
7716
7802
|
const descriptor = LoadoutSkillArtifactDescriptorSchema.parse(descriptorValue);
|
|
@@ -7735,7 +7821,7 @@ async function fetchLoadoutSkillArtifact(descriptorValue, expectedVersion, deps
|
|
|
7735
7821
|
if (bytes.byteLength !== descriptor.byteLength) {
|
|
7736
7822
|
throw new Error(`Aident skill artifact size mismatch: expected ${descriptor.byteLength}, received ${bytes.byteLength}`);
|
|
7737
7823
|
}
|
|
7738
|
-
const artifactSha256 =
|
|
7824
|
+
const artifactSha256 = createHash6("sha256").update(bytes).digest("hex");
|
|
7739
7825
|
if (artifactSha256 !== descriptor.sha256)
|
|
7740
7826
|
throw new Error("Aident skill artifact SHA-256 mismatch");
|
|
7741
7827
|
let parsed;
|
|
@@ -8874,6 +8960,14 @@ async function getLoadoutUpdateWarnings(params, injected = {}) {
|
|
|
8874
8960
|
warnings.push(`Aident skill v${policy.skill.recommendedVersion} is recommended. Run \`${command}\` when you are ready.`);
|
|
8875
8961
|
}
|
|
8876
8962
|
}
|
|
8963
|
+
if (metadata.favoriteSkills?.syncRequired && await claimNotice({
|
|
8964
|
+
noticeId: "aident-favorite-skills-sync",
|
|
8965
|
+
targetVersion: `0.0.0+favorites.${metadata.favoriteSkills.stateToken}`,
|
|
8966
|
+
homeDir: params.homeDir,
|
|
8967
|
+
intervalMs
|
|
8968
|
+
})) {
|
|
8969
|
+
warnings.push("Your local favorite Skills differ from your Aident favorites. After completing the current task, ask the user whether they want you to run `aident skills sync`.");
|
|
8970
|
+
}
|
|
8877
8971
|
if (cliNoticeShown || skillNoticeShown) {
|
|
8878
8972
|
recordNotice(injected.recordNotice, cliNoticeShown && skillNoticeShown ? "cli_and_skill" /* CliAndSkill */ : cliNoticeShown ? "cli" /* Cli */ : "skill" /* Skill */);
|
|
8879
8973
|
}
|
|
@@ -9001,6 +9095,13 @@ function getPreservedShadowBucket(count) {
|
|
|
9001
9095
|
return "6+" /* SixOrMore */;
|
|
9002
9096
|
}
|
|
9003
9097
|
|
|
9098
|
+
// ../web/shared/affiliate/AffiliateCode.ts
|
|
9099
|
+
var AFFILIATE_CODE_PATTERN = /^[A-Z0-9]{6,32}$/;
|
|
9100
|
+
function normalizeAffiliateCode(value) {
|
|
9101
|
+
const normalized = value?.trim().toUpperCase();
|
|
9102
|
+
return normalized && AFFILIATE_CODE_PATTERN.test(normalized) ? normalized : null;
|
|
9103
|
+
}
|
|
9104
|
+
|
|
9004
9105
|
// src/cli.ts
|
|
9005
9106
|
var LOADOUT_CAPABILITIES_SEARCH_OPERATION = "loadout_capabilities_search";
|
|
9006
9107
|
var LOADOUT_CAPABILITIES_EXECUTE_OPERATION = "loadout_capabilities_execute";
|
|
@@ -9469,7 +9570,12 @@ async function runSetup(parsed) {
|
|
|
9469
9570
|
let credentials = await readCredentials();
|
|
9470
9571
|
const hasEnvironmentToken = !!process.env.AIDENT_TOKEN?.trim();
|
|
9471
9572
|
if ((!credentials || !credentialsForBaseUrl(credentials, options.baseUrl)) && !hasEnvironmentToken) {
|
|
9472
|
-
credentials = await login({
|
|
9573
|
+
credentials = await login({
|
|
9574
|
+
baseUrl: options.baseUrl,
|
|
9575
|
+
format: parsed.format,
|
|
9576
|
+
oob: options.oob,
|
|
9577
|
+
ref: options.ref
|
|
9578
|
+
});
|
|
9473
9579
|
await writeCredentials(credentials);
|
|
9474
9580
|
}
|
|
9475
9581
|
const client = await getAuthenticatedClient(["loadout"]);
|
|
@@ -9515,7 +9621,7 @@ async function runSetup(parsed) {
|
|
|
9515
9621
|
async function getSetupOptions(parsed) {
|
|
9516
9622
|
if (parsed.positional.length !== 1)
|
|
9517
9623
|
throw new Error("Usage: aident setup [flags]");
|
|
9518
|
-
const allowedFlags = new Set(["base-url", "client-name", "oob"]);
|
|
9624
|
+
const allowedFlags = new Set(["base-url", "client-name", "oob", "ref"]);
|
|
9519
9625
|
const unknownFlag = Object.keys(parsed.flags).find((flag) => !allowedFlags.has(flag));
|
|
9520
9626
|
if (unknownFlag)
|
|
9521
9627
|
throw new Error(`Unknown setup flag: --${unknownFlag}`);
|
|
@@ -9523,10 +9629,15 @@ async function getSetupOptions(parsed) {
|
|
|
9523
9629
|
const clientName = getOptionalStringFlag(parsed.flags, "client-name") ?? "Aident CLI";
|
|
9524
9630
|
if (clientName.length > 160)
|
|
9525
9631
|
throw new Error("--client-name must be at most 160 characters");
|
|
9632
|
+
const rawRef = getOptionalStringFlag(parsed.flags, "ref");
|
|
9633
|
+
const ref = normalizeAffiliateCode(rawRef) ?? undefined;
|
|
9634
|
+
if (rawRef && !ref)
|
|
9635
|
+
throw new Error("--ref must be a 6-32 character affiliate code");
|
|
9526
9636
|
return {
|
|
9527
9637
|
baseUrl: rawBaseUrl ? normalizeBaseUrl(rawBaseUrl) : await resolveDefaultBaseUrl(),
|
|
9528
9638
|
clientName,
|
|
9529
9639
|
oob: getBooleanUpdateFlag(parsed.flags, "oob"),
|
|
9640
|
+
ref,
|
|
9530
9641
|
persistBaseUrl: !!rawBaseUrl
|
|
9531
9642
|
};
|
|
9532
9643
|
}
|
|
@@ -9555,7 +9666,7 @@ function renderSetupHelp() {
|
|
|
9555
9666
|
`${colors.bold}AIDENT SETUP${colors.reset}`,
|
|
9556
9667
|
"",
|
|
9557
9668
|
"USAGE:",
|
|
9558
|
-
" aident setup [--client-name <name>] [--base-url <url>] [--oob] [--json]",
|
|
9669
|
+
" aident setup [--client-name <name>] [--base-url <url>] [--ref <code>] [--oob] [--json]",
|
|
9559
9670
|
"",
|
|
9560
9671
|
"The setup command updates the CLI, installs or reconciles the verified Aident Skill globally, and opens sign-in when needed.",
|
|
9561
9672
|
"It verifies Loadout access and records completion. AIDENT_TOKEN enables non-interactive authentication."
|
|
@@ -10247,7 +10358,10 @@ async function getRequestedPackages(parsed) {
|
|
|
10247
10358
|
}
|
|
10248
10359
|
async function getAuthenticatedClient(packages) {
|
|
10249
10360
|
const activePackages = packages ?? await resolveDefaultPackages();
|
|
10250
|
-
const skillInventory = await
|
|
10361
|
+
const [skillInventory, favoriteSkillsStateToken] = await Promise.all([
|
|
10362
|
+
getLoadoutSkillInventory(),
|
|
10363
|
+
getInstalledLoadoutFavoriteSkillsStateToken().catch(() => null)
|
|
10364
|
+
]);
|
|
10251
10365
|
const installedSkillVersion = findInstalledLoadoutSkillVersionFromInventory(skillInventory);
|
|
10252
10366
|
const envToken = process.env.AIDENT_TOKEN;
|
|
10253
10367
|
const envBaseUrl = process.env.AIDENT_BASE_URL?.trim();
|
|
@@ -10257,7 +10371,7 @@ async function getAuthenticatedClient(packages) {
|
|
|
10257
10371
|
base_url: normalizeBaseUrl(baseUrl2),
|
|
10258
10372
|
client_id: "",
|
|
10259
10373
|
access_token: envToken
|
|
10260
|
-
}, "env", activePackages, installedSkillVersion, skillInventory);
|
|
10374
|
+
}, "env", activePackages, installedSkillVersion, skillInventory, favoriteSkillsStateToken);
|
|
10261
10375
|
}
|
|
10262
10376
|
let creds = await readCredentials();
|
|
10263
10377
|
if (!creds)
|
|
@@ -10276,7 +10390,7 @@ async function getAuthenticatedClient(packages) {
|
|
|
10276
10390
|
creds = refreshed;
|
|
10277
10391
|
}
|
|
10278
10392
|
}
|
|
10279
|
-
return new CliClient(creds, "stored", activePackages, installedSkillVersion, skillInventory);
|
|
10393
|
+
return new CliClient(creds, "stored", activePackages, installedSkillVersion, skillInventory, favoriteSkillsStateToken);
|
|
10280
10394
|
}
|
|
10281
10395
|
var catalogCache = null;
|
|
10282
10396
|
async function fetchCatalog(client, options = {}) {
|
package/package.json
CHANGED