yourskills 0.3.0 → 0.4.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/dist/main.js +345 -64
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -611,6 +611,7 @@ async function localAccount(server) {
|
|
|
611
611
|
return {
|
|
612
612
|
signedIn: Boolean(config.token),
|
|
613
613
|
email: config.userEmail ?? null,
|
|
614
|
+
organization: config.orgName ?? null,
|
|
614
615
|
server: serverUrl(config, server)
|
|
615
616
|
};
|
|
616
617
|
}
|
|
@@ -924,15 +925,24 @@ function flattenCommands(groups) {
|
|
|
924
925
|
}
|
|
925
926
|
var POINTER = 2;
|
|
926
927
|
var GAP2 = 2;
|
|
928
|
+
var LABEL_CAP = 22;
|
|
929
|
+
function valueColumn(items) {
|
|
930
|
+
return Math.min(items.reduce((wide, item) => Math.max(wide, item.label.length), 0), LABEL_CAP);
|
|
931
|
+
}
|
|
927
932
|
function CommandRow({
|
|
928
933
|
item,
|
|
929
934
|
width,
|
|
935
|
+
column,
|
|
930
936
|
active
|
|
931
937
|
}) {
|
|
932
938
|
const hint = item.hint ?? "";
|
|
933
939
|
const room = width - POINTER - (hint ? hint.length + GAP2 : 0);
|
|
934
940
|
const label = clip(item.label, Math.max(room, 0));
|
|
935
|
-
const
|
|
941
|
+
const shows = item.shows ?? "";
|
|
942
|
+
const pad = Math.max(column - label.length, 0) + GAP2;
|
|
943
|
+
const value = shows && label.length + pad + shows.length <= room ? shows : "";
|
|
944
|
+
const left = label.length + (value ? pad + value.length : 0);
|
|
945
|
+
const gap = Math.max(width - POINTER - left - hint.length, hint ? 1 : 0);
|
|
936
946
|
return /* @__PURE__ */ jsxs5(Text4, {
|
|
937
947
|
children: [
|
|
938
948
|
/* @__PURE__ */ jsx5(Text4, {
|
|
@@ -944,6 +954,9 @@ function CommandRow({
|
|
|
944
954
|
color: active ? tone.primary : undefined,
|
|
945
955
|
children: label
|
|
946
956
|
}),
|
|
957
|
+
value ? /* @__PURE__ */ jsx5(Text4, {
|
|
958
|
+
children: `${" ".repeat(pad)}${value}`
|
|
959
|
+
}) : null,
|
|
947
960
|
/* @__PURE__ */ jsx5(Text4, {
|
|
948
961
|
dimColor: true,
|
|
949
962
|
children: `${" ".repeat(gap)}${hint}`
|
|
@@ -963,6 +976,7 @@ function CommandPalette({
|
|
|
963
976
|
const rows = flattenCommands(visible);
|
|
964
977
|
const current = rows[cursor];
|
|
965
978
|
const interior = width - FRAME_CHROME;
|
|
979
|
+
const column = valueColumn(rows);
|
|
966
980
|
return /* @__PURE__ */ jsxs5(Box3, {
|
|
967
981
|
flexDirection: "column",
|
|
968
982
|
children: [
|
|
@@ -997,6 +1011,7 @@ function CommandPalette({
|
|
|
997
1011
|
group.items.map((item) => /* @__PURE__ */ jsx5(CommandRow, {
|
|
998
1012
|
item,
|
|
999
1013
|
width: interior,
|
|
1014
|
+
column,
|
|
1000
1015
|
active: item.value === current?.value
|
|
1001
1016
|
}, item.value))
|
|
1002
1017
|
]
|
|
@@ -5753,7 +5768,7 @@ import { realpathSync } from "node:fs";
|
|
|
5753
5768
|
// package.json
|
|
5754
5769
|
var package_default = {
|
|
5755
5770
|
name: "yourskills",
|
|
5756
|
-
version: "0.
|
|
5771
|
+
version: "0.4.0",
|
|
5757
5772
|
description: "Browse, install and keep up to date the agent skills and bundles your team publishes on yourskills.",
|
|
5758
5773
|
license: "UNLICENSED",
|
|
5759
5774
|
homepage: "https://yourskills.store",
|
|
@@ -6198,8 +6213,41 @@ async function runSessionStart() {
|
|
|
6198
6213
|
const outcome = await sessionStart();
|
|
6199
6214
|
emit(outcome, await upgradeCheck());
|
|
6200
6215
|
}
|
|
6201
|
-
// src/org/
|
|
6216
|
+
// src/org/wire.ts
|
|
6202
6217
|
var authBase2 = (base) => `${base.replace(/\/$/, "")}/api/auth`;
|
|
6218
|
+
async function activeOrganizationId(base, token) {
|
|
6219
|
+
const res = await fetch(`${authBase2(base)}/get-session`, {
|
|
6220
|
+
headers: { authorization: `Bearer ${token}` }
|
|
6221
|
+
});
|
|
6222
|
+
if (!res.ok)
|
|
6223
|
+
return null;
|
|
6224
|
+
const body = await res.json();
|
|
6225
|
+
return body?.session?.activeOrganizationId ?? null;
|
|
6226
|
+
}
|
|
6227
|
+
async function listOrganizations(base, token) {
|
|
6228
|
+
let res;
|
|
6229
|
+
try {
|
|
6230
|
+
res = await fetch(`${authBase2(base)}/organization/list`, {
|
|
6231
|
+
headers: { authorization: `Bearer ${token}` }
|
|
6232
|
+
});
|
|
6233
|
+
} catch (error) {
|
|
6234
|
+
throw new Error(`Could not reach ${base}: ${error instanceof Error ? error.message : String(error)}`);
|
|
6235
|
+
}
|
|
6236
|
+
if (!res.ok) {
|
|
6237
|
+
throw new Error(`Could not list organizations: ${res.status} ${res.statusText}`);
|
|
6238
|
+
}
|
|
6239
|
+
return await res.json();
|
|
6240
|
+
}
|
|
6241
|
+
async function rememberOrganization(name) {
|
|
6242
|
+
try {
|
|
6243
|
+
const config = await readConfig();
|
|
6244
|
+
if ((config.orgName ?? null) === name)
|
|
6245
|
+
return;
|
|
6246
|
+
await writeConfig(name === null ? { ...config, orgName: undefined } : { ...config, orgName: name });
|
|
6247
|
+
} catch {}
|
|
6248
|
+
}
|
|
6249
|
+
|
|
6250
|
+
// src/org/org.ts
|
|
6203
6251
|
var NO_ACTIVE_ORGANIZATION = "none: choose one with `yourskills org <name>`, or in the web app";
|
|
6204
6252
|
async function namedOrganization(server) {
|
|
6205
6253
|
const client = await createClient(server);
|
|
@@ -6208,11 +6256,9 @@ async function namedOrganization(server) {
|
|
|
6208
6256
|
}
|
|
6209
6257
|
async function whoamiReport(server) {
|
|
6210
6258
|
const who = await whoami(server);
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
organization: who.org ? await namedOrganization(server) : null
|
|
6215
|
-
});
|
|
6259
|
+
const organization = who.org ? await namedOrganization(server) : null;
|
|
6260
|
+
await rememberOrganization(organization?.name ?? null);
|
|
6261
|
+
return drawWhoami({ user: who.user, server: who.server, organization });
|
|
6216
6262
|
}
|
|
6217
6263
|
function drawWhoami({ user, server, organization }) {
|
|
6218
6264
|
const label = (text) => text.padEnd(7);
|
|
@@ -6230,29 +6276,6 @@ function drawWhoami({ user, server, organization }) {
|
|
|
6230
6276
|
json: { user, server, organization }
|
|
6231
6277
|
};
|
|
6232
6278
|
}
|
|
6233
|
-
async function activeOrganizationId(base, token) {
|
|
6234
|
-
const res = await fetch(`${authBase2(base)}/get-session`, {
|
|
6235
|
-
headers: { authorization: `Bearer ${token}` }
|
|
6236
|
-
});
|
|
6237
|
-
if (!res.ok)
|
|
6238
|
-
return null;
|
|
6239
|
-
const body = await res.json();
|
|
6240
|
-
return body?.session?.activeOrganizationId ?? null;
|
|
6241
|
-
}
|
|
6242
|
-
async function listOrganizations(base, token) {
|
|
6243
|
-
let res;
|
|
6244
|
-
try {
|
|
6245
|
-
res = await fetch(`${authBase2(base)}/organization/list`, {
|
|
6246
|
-
headers: { authorization: `Bearer ${token}` }
|
|
6247
|
-
});
|
|
6248
|
-
} catch (error) {
|
|
6249
|
-
throw new Error(`Could not reach ${base}: ${error instanceof Error ? error.message : String(error)}`);
|
|
6250
|
-
}
|
|
6251
|
-
if (!res.ok) {
|
|
6252
|
-
throw new Error(`Could not list organizations: ${res.status} ${res.statusText}`);
|
|
6253
|
-
}
|
|
6254
|
-
return await res.json();
|
|
6255
|
-
}
|
|
6256
6279
|
function rows(orgs, active) {
|
|
6257
6280
|
if (orgs.length === 0) {
|
|
6258
6281
|
return [
|
|
@@ -6269,12 +6292,40 @@ function rows(orgs, active) {
|
|
|
6269
6292
|
note: org.slug ?? org.id
|
|
6270
6293
|
}));
|
|
6271
6294
|
}
|
|
6295
|
+
async function learnActiveOrganization(server) {
|
|
6296
|
+
try {
|
|
6297
|
+
const { token, base } = await requireToken(server);
|
|
6298
|
+
const [orgs, active] = await Promise.all([
|
|
6299
|
+
listOrganizations(base, token),
|
|
6300
|
+
activeOrganizationId(base, token)
|
|
6301
|
+
]);
|
|
6302
|
+
const name = orgs.find((o) => o.id === active)?.name ?? null;
|
|
6303
|
+
await rememberOrganization(name);
|
|
6304
|
+
return name;
|
|
6305
|
+
} catch {
|
|
6306
|
+
return null;
|
|
6307
|
+
}
|
|
6308
|
+
}
|
|
6309
|
+
async function organizationChoices(server) {
|
|
6310
|
+
const { token, base } = await requireToken(server);
|
|
6311
|
+
const [orgs, active] = await Promise.all([
|
|
6312
|
+
listOrganizations(base, token),
|
|
6313
|
+
activeOrganizationId(base, token)
|
|
6314
|
+
]);
|
|
6315
|
+
await rememberOrganization(orgs.find((o) => o.id === active)?.name ?? null);
|
|
6316
|
+
return orgs.map((org) => ({
|
|
6317
|
+
name: org.name,
|
|
6318
|
+
slug: org.slug ?? null,
|
|
6319
|
+
active: org.id === active
|
|
6320
|
+
}));
|
|
6321
|
+
}
|
|
6272
6322
|
async function orgListReport(server) {
|
|
6273
6323
|
const { token, base } = await requireToken(server);
|
|
6274
6324
|
const [orgs, active] = await Promise.all([
|
|
6275
6325
|
listOrganizations(base, token),
|
|
6276
6326
|
activeOrganizationId(base, token)
|
|
6277
6327
|
]);
|
|
6328
|
+
await rememberOrganization(orgs.find((o) => o.id === active)?.name ?? null);
|
|
6278
6329
|
return {
|
|
6279
6330
|
title: "org",
|
|
6280
6331
|
lines: rows(orgs, active),
|
|
@@ -6331,6 +6382,7 @@ async function orgSwitchReport(name, server) {
|
|
|
6331
6382
|
failed: true
|
|
6332
6383
|
};
|
|
6333
6384
|
}
|
|
6385
|
+
await rememberOrganization(match.name);
|
|
6334
6386
|
return {
|
|
6335
6387
|
title: "org",
|
|
6336
6388
|
lines: [{ mark: "ok", text: `Active organization: ${match.name}` }],
|
|
@@ -6896,6 +6948,7 @@ function noSuchPass(id, passes) {
|
|
|
6896
6948
|
};
|
|
6897
6949
|
}
|
|
6898
6950
|
// src/commands/facts.ts
|
|
6951
|
+
var NO_FEED = {};
|
|
6899
6952
|
function count2(n, one, many = `${one}s`) {
|
|
6900
6953
|
return `${n} ${n === 1 ? one : many}`;
|
|
6901
6954
|
}
|
|
@@ -6988,6 +7041,7 @@ var TABLE = {
|
|
|
6988
7041
|
value: "catalog.bundles",
|
|
6989
7042
|
label: "browse bundles",
|
|
6990
7043
|
hint: "browse",
|
|
7044
|
+
shows: (facts) => facts.feed.bundles === undefined ? "" : count2(facts.feed.bundles, "bundle"),
|
|
6991
7045
|
when: (facts) => facts.signedIn,
|
|
6992
7046
|
opens: { kind: "browse" }
|
|
6993
7047
|
}
|
|
@@ -7094,8 +7148,9 @@ var TABLE = {
|
|
|
7094
7148
|
value: "account.org",
|
|
7095
7149
|
label: "switch org",
|
|
7096
7150
|
hint: "org <name>",
|
|
7151
|
+
shows: (facts) => facts.feed.organizations === undefined ? "" : facts.feed.organizations <= 1 ? "only this one" : count2(facts.feed.organizations - 1, "other"),
|
|
7097
7152
|
when: (facts) => facts.signedIn,
|
|
7098
|
-
|
|
7153
|
+
says: (facts) => facts.organization ? `switch this machine out of ${facts.organization}` : "choose which organization this machine installs from"
|
|
7099
7154
|
}
|
|
7100
7155
|
],
|
|
7101
7156
|
invitesHooks: false,
|
|
@@ -7118,6 +7173,7 @@ var TABLE = {
|
|
|
7118
7173
|
value: "catalog.skills",
|
|
7119
7174
|
label: "browse skills",
|
|
7120
7175
|
hint: "list",
|
|
7176
|
+
shows: (facts) => facts.feed.skills === undefined ? "" : count2(facts.feed.skills, "skill"),
|
|
7121
7177
|
when: (facts) => facts.signedIn,
|
|
7122
7178
|
opens: { kind: "list" }
|
|
7123
7179
|
}
|
|
@@ -7295,6 +7351,7 @@ var TABLE = {
|
|
|
7295
7351
|
value: "installed.update",
|
|
7296
7352
|
label: "update all",
|
|
7297
7353
|
hint: "update --all",
|
|
7354
|
+
shows: (facts) => updateScope(facts.bundles, facts.loose),
|
|
7298
7355
|
when: (facts) => facts.skills > 0 && facts.signedIn,
|
|
7299
7356
|
opens: { kind: "update", all: true }
|
|
7300
7357
|
}
|
|
@@ -7384,6 +7441,7 @@ var TABLE = {
|
|
|
7384
7441
|
value: "installed.list",
|
|
7385
7442
|
label: "list installed",
|
|
7386
7443
|
hint: "installed",
|
|
7444
|
+
shows: (facts) => count2(facts.skills, "skill"),
|
|
7387
7445
|
when: (facts) => facts.skills > 0,
|
|
7388
7446
|
opens: { kind: "installed" }
|
|
7389
7447
|
}
|
|
@@ -7413,6 +7471,7 @@ var TABLE = {
|
|
|
7413
7471
|
value: "installed.outdated",
|
|
7414
7472
|
label: "outdated",
|
|
7415
7473
|
hint: "outdated",
|
|
7474
|
+
shows: (facts) => facts.feed.outdated === undefined ? "" : facts.feed.outdated === 0 ? "all current" : `${facts.feed.outdated} behind`,
|
|
7416
7475
|
when: (facts) => facts.skills > 0 && facts.signedIn,
|
|
7417
7476
|
opens: { kind: "outdated" }
|
|
7418
7477
|
}
|
|
@@ -7447,6 +7506,7 @@ var TABLE = {
|
|
|
7447
7506
|
value: "catalog.pending",
|
|
7448
7507
|
label: "waiting for a review",
|
|
7449
7508
|
hint: "pending",
|
|
7509
|
+
shows: (facts) => facts.feed.pending === undefined ? "" : facts.feed.pending === 0 ? "none open" : `${facts.feed.pending} open`,
|
|
7450
7510
|
when: (facts) => facts.signedIn,
|
|
7451
7511
|
opens: { kind: "pending" }
|
|
7452
7512
|
}
|
|
@@ -7553,20 +7613,21 @@ var TABLE = {
|
|
|
7553
7613
|
value: "setup.scope",
|
|
7554
7614
|
label: "scope",
|
|
7555
7615
|
hint: "config set scope project",
|
|
7556
|
-
|
|
7616
|
+
shows: (facts) => facts.scope,
|
|
7557
7617
|
says: (facts) => `where installs land: ${facts.scope} right now`
|
|
7558
7618
|
},
|
|
7559
7619
|
{
|
|
7560
7620
|
value: "setup.agents",
|
|
7561
7621
|
label: "agents",
|
|
7562
7622
|
hint: "config set agents <name>",
|
|
7563
|
-
|
|
7564
|
-
says: () => "which agents
|
|
7623
|
+
shows: (facts) => facts.agents.length > 0 ? count2(facts.agents.length, "agent") : "unset",
|
|
7624
|
+
says: (facts) => facts.agents.length > 0 ? `which agents an install writes for: ${facts.agents.join(", ")}` : "which agents an install writes for; nothing pinned, so `skills` looks"
|
|
7565
7625
|
},
|
|
7566
7626
|
{
|
|
7567
7627
|
value: "setup.explain",
|
|
7568
7628
|
label: "explain",
|
|
7569
7629
|
hint: "config get --explain",
|
|
7630
|
+
shows: (facts) => `${count2(facts.settings, "setting")} set`,
|
|
7570
7631
|
opens: { kind: "config", action: "get", explain: true }
|
|
7571
7632
|
}
|
|
7572
7633
|
],
|
|
@@ -7644,6 +7705,7 @@ var TABLE = {
|
|
|
7644
7705
|
value: "setup.upgrade",
|
|
7645
7706
|
label: "upgrade",
|
|
7646
7707
|
hint: "upgrade",
|
|
7708
|
+
shows: (facts) => facts.feed.upgrade === undefined ? "" : facts.feed.upgrade === null ? "up to date" : `${facts.feed.upgrade} is out`,
|
|
7647
7709
|
opens: { kind: "upgrade" }
|
|
7648
7710
|
}
|
|
7649
7711
|
],
|
|
@@ -7740,6 +7802,9 @@ function refuseCommand(command) {
|
|
|
7740
7802
|
code: EXIT.usage
|
|
7741
7803
|
});
|
|
7742
7804
|
}
|
|
7805
|
+
function doorShows(door, facts) {
|
|
7806
|
+
return door.shows?.(facts) ?? "";
|
|
7807
|
+
}
|
|
7743
7808
|
function doorSays(door, facts) {
|
|
7744
7809
|
if (door.opens === undefined)
|
|
7745
7810
|
return door.says(facts);
|
|
@@ -8041,13 +8106,19 @@ var PALETTE = [
|
|
|
8041
8106
|
]
|
|
8042
8107
|
}
|
|
8043
8108
|
];
|
|
8044
|
-
function item(door) {
|
|
8045
|
-
|
|
8109
|
+
function item(door, facts) {
|
|
8110
|
+
const shows = doorShows(door, facts);
|
|
8111
|
+
return {
|
|
8112
|
+
value: door.value,
|
|
8113
|
+
label: door.label,
|
|
8114
|
+
hint: door.hint,
|
|
8115
|
+
...shows ? { shows } : {}
|
|
8116
|
+
};
|
|
8046
8117
|
}
|
|
8047
8118
|
function paletteGroups(facts) {
|
|
8048
8119
|
const groups = [];
|
|
8049
8120
|
for (const place of PALETTE) {
|
|
8050
|
-
const items = place.doors.map((value) => DOORS[value]).filter((door) => door.when?.(facts) ?? true).map(item);
|
|
8121
|
+
const items = place.doors.map((value) => DOORS[value]).filter((door) => door.when?.(facts) ?? true).map((door) => item(door, facts));
|
|
8051
8122
|
if (items.length > 0)
|
|
8052
8123
|
groups.push({ group: place.group, items });
|
|
8053
8124
|
}
|
|
@@ -8056,29 +8127,78 @@ function paletteGroups(facts) {
|
|
|
8056
8127
|
// src/shell/facts.ts
|
|
8057
8128
|
import { existsSync as existsSync7 } from "node:fs";
|
|
8058
8129
|
async function paletteFacts(scope, server) {
|
|
8059
|
-
const [account, nearest, config] = await Promise.all([
|
|
8130
|
+
const [account, nearest, config, agents] = await Promise.all([
|
|
8060
8131
|
localAccount(server),
|
|
8061
8132
|
nearestManifest(scope),
|
|
8062
|
-
readConfig()
|
|
8133
|
+
readConfig(),
|
|
8134
|
+
resolveAgents()
|
|
8063
8135
|
]);
|
|
8064
8136
|
const skills = Object.keys(nearest.manifest.skills).length;
|
|
8065
8137
|
return {
|
|
8066
8138
|
signedIn: account.signedIn,
|
|
8067
8139
|
email: account.email,
|
|
8140
|
+
organization: account.organization,
|
|
8068
8141
|
server: account.server,
|
|
8069
8142
|
firstRun: !account.signedIn && skills === 0 && !config.welcomed,
|
|
8070
8143
|
agentsOnDisk: HOOK_ADAPTERS.filter((adapter) => existsSync7(adapter.home())).map((adapter) => adapter.agent),
|
|
8144
|
+
agents,
|
|
8071
8145
|
scope: nearest.scope,
|
|
8072
8146
|
manifest: nearest.path,
|
|
8073
8147
|
skills,
|
|
8074
8148
|
bundles: Object.keys(nearest.manifest.bundles).length,
|
|
8075
|
-
loose: looseSkills(nearest.manifest).length
|
|
8149
|
+
loose: looseSkills(nearest.manifest).length,
|
|
8150
|
+
settings: CONFIG_KEYS.filter((key) => configValue(config, key) !== UNSET).length,
|
|
8151
|
+
feed: NO_FEED
|
|
8076
8152
|
};
|
|
8077
8153
|
}
|
|
8078
8154
|
// src/shell/screens/home.tsx
|
|
8079
8155
|
import { Box as Box14, Text as Text16, useApp as useApp7, useInput as useInput8 } from "ink";
|
|
8080
8156
|
import { useCallback as useCallback3, useEffect as useEffect9, useMemo as useMemo4, useRef, useState as useState11 } from "react";
|
|
8081
8157
|
|
|
8158
|
+
// src/shell/feed.ts
|
|
8159
|
+
async function feedFacts(client, where, server) {
|
|
8160
|
+
const installed = Object.keys(where.manifest.skills).length > 0;
|
|
8161
|
+
const [skills, bundles, passes, drift, orgs] = await Promise.allSettled([
|
|
8162
|
+
client.skills.list.query({}),
|
|
8163
|
+
client.bundles.list.query({}),
|
|
8164
|
+
client.mirror.passes.query(),
|
|
8165
|
+
installed ? driftNow(client, where) : Promise.resolve(null),
|
|
8166
|
+
organizationChoices(server)
|
|
8167
|
+
]);
|
|
8168
|
+
return {
|
|
8169
|
+
...skills.status === "fulfilled" ? { skills: skills.value.length } : {},
|
|
8170
|
+
...bundles.status === "fulfilled" ? { bundles: bundles.value.length } : {},
|
|
8171
|
+
...passes.status === "fulfilled" ? { pending: passes.value.length } : {},
|
|
8172
|
+
...drift.status === "fulfilled" && drift.value ? { outdated: drift.value.moved.length } : {},
|
|
8173
|
+
...orgs.status === "fulfilled" ? { organizations: orgs.value.length } : {}
|
|
8174
|
+
};
|
|
8175
|
+
}
|
|
8176
|
+
|
|
8177
|
+
// src/shell/probe.ts
|
|
8178
|
+
var importProbe = async (where) => {
|
|
8179
|
+
const found = await listInstalled(where.scope);
|
|
8180
|
+
const recorded = new Set(Object.keys(where.manifest.skills));
|
|
8181
|
+
const news = found.filter((skill) => !recorded.has(skill.name)).length;
|
|
8182
|
+
if (found.length === 0)
|
|
8183
|
+
return "nothing on this machine to adopt";
|
|
8184
|
+
return news === 0 ? `${count2(found.length, "skill")} on this machine, all recorded here already` : `${count2(found.length, "skill")} on this machine, ${news} not recorded here`;
|
|
8185
|
+
};
|
|
8186
|
+
var doctorProbe = async (where, server) => {
|
|
8187
|
+
const checks = await diagnose(where, {
|
|
8188
|
+
local: true,
|
|
8189
|
+
...server ? { server } : {}
|
|
8190
|
+
});
|
|
8191
|
+
const bad = checks.filter((check) => !check.ok);
|
|
8192
|
+
return bad.length === 0 ? `${count2(checks.length, "local check")}, all passing` : `${bad.length} of ${checks.length} local checks failing: ${bad.map((check) => check.name).join(", ")}`;
|
|
8193
|
+
};
|
|
8194
|
+
var PROBES = {
|
|
8195
|
+
"setup.import": importProbe,
|
|
8196
|
+
"setup.doctor": doctorProbe
|
|
8197
|
+
};
|
|
8198
|
+
function probeFor(value) {
|
|
8199
|
+
return value ? PROBES[value] : undefined;
|
|
8200
|
+
}
|
|
8201
|
+
|
|
8082
8202
|
// src/args.ts
|
|
8083
8203
|
function configCommand2(rest, explain) {
|
|
8084
8204
|
const [action, key, ...value] = rest;
|
|
@@ -8406,13 +8526,16 @@ function PickScreen({
|
|
|
8406
8526
|
rows,
|
|
8407
8527
|
empty,
|
|
8408
8528
|
verb,
|
|
8529
|
+
single = false,
|
|
8530
|
+
marked,
|
|
8531
|
+
preset,
|
|
8409
8532
|
onPick,
|
|
8410
8533
|
onBack
|
|
8411
8534
|
}) {
|
|
8412
8535
|
const width = useFrameWidth();
|
|
8413
8536
|
const [query, setQuery] = useState9("");
|
|
8414
8537
|
const [cursor, setCursor] = useState9(0);
|
|
8415
|
-
const [picked, setPicked] = useState9(new Set);
|
|
8538
|
+
const [picked, setPicked] = useState9(() => new Set(preset ?? []));
|
|
8416
8539
|
const visible = useMemo3(() => {
|
|
8417
8540
|
if (query.length === 0)
|
|
8418
8541
|
return rows;
|
|
@@ -8439,7 +8562,7 @@ function PickScreen({
|
|
|
8439
8562
|
} else if (key.backspace || key.delete) {
|
|
8440
8563
|
setQuery((q) => q.slice(0, -1));
|
|
8441
8564
|
setCursor(0);
|
|
8442
|
-
} else if (input === " ") {
|
|
8565
|
+
} else if (input === " " && !single) {
|
|
8443
8566
|
const row = visible[cursor];
|
|
8444
8567
|
if (!row)
|
|
8445
8568
|
return;
|
|
@@ -8490,21 +8613,21 @@ function PickScreen({
|
|
|
8490
8613
|
names,
|
|
8491
8614
|
selectable: true,
|
|
8492
8615
|
cursor: i === cursor,
|
|
8493
|
-
selected: picked.has(row.name)
|
|
8616
|
+
selected: single ? row.name === marked : picked.has(row.name)
|
|
8494
8617
|
}, row.name)),
|
|
8495
8618
|
/* @__PURE__ */ jsx16(Divider, {
|
|
8496
8619
|
width
|
|
8497
8620
|
}),
|
|
8498
8621
|
/* @__PURE__ */ jsxs14(Box12, {
|
|
8499
8622
|
children: [
|
|
8500
|
-
picked.size > 0 ? /* @__PURE__ */ jsx16(Text14, {
|
|
8623
|
+
picked.size > 0 && !single ? /* @__PURE__ */ jsx16(Text14, {
|
|
8501
8624
|
color: tone.notice,
|
|
8502
8625
|
children: `${mark.selected} ${picked.size} marked `
|
|
8503
8626
|
}) : null,
|
|
8504
8627
|
/* @__PURE__ */ jsx16(Hints, {
|
|
8505
8628
|
hints: [
|
|
8506
8629
|
["^v", "move"],
|
|
8507
|
-
["space", "mark"],
|
|
8630
|
+
...single ? [] : [["space", "mark"]],
|
|
8508
8631
|
["enter", verb],
|
|
8509
8632
|
["esc", query ? "clear" : "back"]
|
|
8510
8633
|
]
|
|
@@ -8620,12 +8743,35 @@ function failure(title, error) {
|
|
|
8620
8743
|
json: { error: message }
|
|
8621
8744
|
};
|
|
8622
8745
|
}
|
|
8746
|
+
var HEAD_FLOOR = 14;
|
|
8747
|
+
var AGENTS_FLOOR = 9;
|
|
8748
|
+
function agentsIn(agents, room) {
|
|
8749
|
+
if (agents.length === 0)
|
|
8750
|
+
return "agents unset";
|
|
8751
|
+
const full = agents.join(",");
|
|
8752
|
+
if (full.length <= room)
|
|
8753
|
+
return full;
|
|
8754
|
+
for (let keep = agents.length - 1;keep > 0; keep--) {
|
|
8755
|
+
const text = `${agents.slice(0, keep).join(",")} +${agents.length - keep}`;
|
|
8756
|
+
if (text.length <= room)
|
|
8757
|
+
return text;
|
|
8758
|
+
}
|
|
8759
|
+
return `${agents.length} agents`;
|
|
8760
|
+
}
|
|
8623
8761
|
function AccountLine({ facts, width }) {
|
|
8624
|
-
const right = `${facts.scope} ${facts.skills} installed`;
|
|
8625
8762
|
const head = facts.signedIn ? facts.email ?? "signed in" : "not signed in";
|
|
8626
|
-
const
|
|
8763
|
+
const stat = `${facts.scope} ${facts.skills} installed`;
|
|
8764
|
+
const inner = width - FRAME_CHROME;
|
|
8765
|
+
const spent = Math.min(head.length, 24) + 2 + stat.length + 4;
|
|
8766
|
+
const forAgents = inner - spent;
|
|
8767
|
+
const agents = forAgents >= AGENTS_FLOOR ? agentsIn(facts.agents, forAgents) : "";
|
|
8768
|
+
const right = agents ? `${agents} ${stat}` : stat;
|
|
8769
|
+
const room = Math.max(inner - right.length - 2, HEAD_FLOOR);
|
|
8627
8770
|
const tail = facts.signedIn ? ` ${hostOf(facts.server)}` : " — the catalog needs a session";
|
|
8771
|
+
const org = facts.signedIn && facts.organization ? ` ${facts.organization}` : "";
|
|
8628
8772
|
const spare = room - 2 - head.length;
|
|
8773
|
+
const showOrg = spare >= org.length;
|
|
8774
|
+
const showTail = spare - (showOrg ? org.length : 0) >= tail.length;
|
|
8629
8775
|
return /* @__PURE__ */ jsxs16(Box14, {
|
|
8630
8776
|
width: width - FRAME_CHROME,
|
|
8631
8777
|
justifyContent: "space-between",
|
|
@@ -8640,7 +8786,11 @@ function AccountLine({ facts, width }) {
|
|
|
8640
8786
|
color: facts.signedIn ? undefined : tone.notice,
|
|
8641
8787
|
children: ` ${clip(head, room - 2)}`
|
|
8642
8788
|
}),
|
|
8643
|
-
|
|
8789
|
+
showOrg ? /* @__PURE__ */ jsx18(Text16, {
|
|
8790
|
+
color: tone.primary,
|
|
8791
|
+
children: org
|
|
8792
|
+
}) : null,
|
|
8793
|
+
showTail ? /* @__PURE__ */ jsx18(Text16, {
|
|
8644
8794
|
dimColor: true,
|
|
8645
8795
|
children: tail
|
|
8646
8796
|
}) : null
|
|
@@ -8648,7 +8798,7 @@ function AccountLine({ facts, width }) {
|
|
|
8648
8798
|
}),
|
|
8649
8799
|
/* @__PURE__ */ jsx18(Text16, {
|
|
8650
8800
|
dimColor: true,
|
|
8651
|
-
children: right
|
|
8801
|
+
children: clip(right, inner - room)
|
|
8652
8802
|
})
|
|
8653
8803
|
]
|
|
8654
8804
|
});
|
|
@@ -8664,7 +8814,9 @@ function StaleLine({ stale, width }) {
|
|
|
8664
8814
|
});
|
|
8665
8815
|
}
|
|
8666
8816
|
var RUN = "run";
|
|
8817
|
+
var REST_MS = 250;
|
|
8667
8818
|
var ASK_NPM = () => upgradeCheck();
|
|
8819
|
+
var ASK_REGISTRY = feedFacts;
|
|
8668
8820
|
var NO_EXIT_CODE = () => {
|
|
8669
8821
|
return;
|
|
8670
8822
|
};
|
|
@@ -8680,19 +8832,20 @@ function HomeScreen({
|
|
|
8680
8832
|
onWelcomed = async () => {
|
|
8681
8833
|
return;
|
|
8682
8834
|
},
|
|
8683
|
-
checkUpgrade = ASK_NPM
|
|
8835
|
+
checkUpgrade = ASK_NPM,
|
|
8836
|
+
loadFeed = ASK_REGISTRY,
|
|
8837
|
+
probes: probeSet = probeFor
|
|
8684
8838
|
}) {
|
|
8685
8839
|
const { exit } = useApp7();
|
|
8686
8840
|
const width = useFrameWidth();
|
|
8687
8841
|
const [facts, setFacts] = useState11(initial);
|
|
8688
8842
|
const [where, setWhere] = useState11(initialWhere);
|
|
8689
|
-
const groups = useMemo4(() => paletteGroups(facts), [facts]);
|
|
8690
8843
|
const [query, setQuery] = useState11("");
|
|
8691
8844
|
const [cursor, setCursor] = useState11(0);
|
|
8692
8845
|
const [route, setRoute] = useState11(null);
|
|
8693
8846
|
const [welcome, setWelcome] = useState11(initial.firstRun);
|
|
8694
8847
|
const [wizard, setWizard] = useState11(false);
|
|
8695
|
-
const [stale, setStale] = useState11(
|
|
8848
|
+
const [stale, setStale] = useState11(undefined);
|
|
8696
8849
|
useEffect9(() => {
|
|
8697
8850
|
let live = true;
|
|
8698
8851
|
checkUpgrade().then((found) => {
|
|
@@ -8705,6 +8858,17 @@ function HomeScreen({
|
|
|
8705
8858
|
live = false;
|
|
8706
8859
|
};
|
|
8707
8860
|
}, [checkUpgrade]);
|
|
8861
|
+
const [feed, setFeed] = useState11(NO_FEED);
|
|
8862
|
+
const [probes, setProbes] = useState11({});
|
|
8863
|
+
const [probing, setProbing] = useState11(null);
|
|
8864
|
+
const shown = useMemo4(() => ({
|
|
8865
|
+
...facts,
|
|
8866
|
+
feed: {
|
|
8867
|
+
...feed,
|
|
8868
|
+
...stale === undefined ? {} : { upgrade: stale ? stale.latest : null }
|
|
8869
|
+
}
|
|
8870
|
+
}), [facts, feed, stale]);
|
|
8871
|
+
const groups = useMemo4(() => paletteGroups(shown), [shown]);
|
|
8708
8872
|
const typed = useMemo4(() => typedCommand(query), [query]);
|
|
8709
8873
|
const visible = useMemo4(() => {
|
|
8710
8874
|
const filtered = filterCommands(groups, query);
|
|
@@ -8727,6 +8891,20 @@ function HomeScreen({
|
|
|
8727
8891
|
held.current ??= await openClient();
|
|
8728
8892
|
return held.current;
|
|
8729
8893
|
}, [openClient]);
|
|
8894
|
+
useEffect9(() => {
|
|
8895
|
+
if (!facts.signedIn)
|
|
8896
|
+
return;
|
|
8897
|
+
let live = true;
|
|
8898
|
+
connect().then((client) => loadFeed(client, where, server)).then((found) => {
|
|
8899
|
+
if (live)
|
|
8900
|
+
setFeed(found);
|
|
8901
|
+
}).catch(() => {
|
|
8902
|
+
return;
|
|
8903
|
+
});
|
|
8904
|
+
return () => {
|
|
8905
|
+
live = false;
|
|
8906
|
+
};
|
|
8907
|
+
}, [facts.signedIn, connect, loadFeed, where, server]);
|
|
8730
8908
|
const checkSession = useCallback3(async () => facts.signedIn, [facts.signedIn]);
|
|
8731
8909
|
const answering = useCallback3((title, working, load) => ({
|
|
8732
8910
|
kind: "report",
|
|
@@ -8806,20 +8984,87 @@ function HomeScreen({
|
|
|
8806
8984
|
held.current = null;
|
|
8807
8985
|
return routeFrom(answer, say(command, facts));
|
|
8808
8986
|
}, [catalogDoor, ctx, facts, routeFrom]);
|
|
8809
|
-
const ownRoute = useCallback3((value) => {
|
|
8987
|
+
const ownRoute = useCallback3(async (value) => {
|
|
8810
8988
|
switch (value) {
|
|
8811
8989
|
case "catalog.search":
|
|
8812
8990
|
return { kind: "browse", tab: "skills" };
|
|
8813
8991
|
case "installed.remove":
|
|
8814
8992
|
return {
|
|
8815
8993
|
kind: "pick",
|
|
8994
|
+
title: "remove",
|
|
8816
8995
|
rows: installedRows(where).map((row) => ({
|
|
8817
8996
|
name: row.name,
|
|
8818
8997
|
description: `${row.bundle ?? "loose"} ${shortRef(row.ref)}`
|
|
8819
|
-
}))
|
|
8998
|
+
})),
|
|
8999
|
+
empty: "Nothing installed here.",
|
|
9000
|
+
verb: "remove",
|
|
9001
|
+
command: (names) => ({ kind: "remove", names })
|
|
9002
|
+
};
|
|
9003
|
+
case "setup.scope":
|
|
9004
|
+
return {
|
|
9005
|
+
kind: "pick",
|
|
9006
|
+
title: "scope",
|
|
9007
|
+
rows: [
|
|
9008
|
+
{
|
|
9009
|
+
name: "global",
|
|
9010
|
+
description: "installs land in your home directory, where every project sees them"
|
|
9011
|
+
},
|
|
9012
|
+
{
|
|
9013
|
+
name: "project",
|
|
9014
|
+
description: "installs land in this project's yourskills.json, and travel with the repo"
|
|
9015
|
+
}
|
|
9016
|
+
],
|
|
9017
|
+
empty: "",
|
|
9018
|
+
verb: "set",
|
|
9019
|
+
single: true,
|
|
9020
|
+
marked: facts.scope,
|
|
9021
|
+
command: (names) => ({
|
|
9022
|
+
kind: "config",
|
|
9023
|
+
action: "set",
|
|
9024
|
+
key: "scope",
|
|
9025
|
+
value: names[0] ?? ""
|
|
9026
|
+
})
|
|
9027
|
+
};
|
|
9028
|
+
case "setup.agents": {
|
|
9029
|
+
const valid = await knownAgents() ?? [];
|
|
9030
|
+
const onDisk = new Set(facts.agentsOnDisk);
|
|
9031
|
+
return {
|
|
9032
|
+
kind: "pick",
|
|
9033
|
+
title: "agents",
|
|
9034
|
+
rows: valid.map((name) => ({
|
|
9035
|
+
name,
|
|
9036
|
+
description: onDisk.has(name) ? "on this machine" : ""
|
|
9037
|
+
})),
|
|
9038
|
+
empty: "Could not ask the `skills` CLI which agent names it accepts. Run `yourskills doctor`.",
|
|
9039
|
+
verb: "set",
|
|
9040
|
+
preset: facts.agents,
|
|
9041
|
+
command: (names) => ({
|
|
9042
|
+
kind: "config",
|
|
9043
|
+
action: "set",
|
|
9044
|
+
key: "agents",
|
|
9045
|
+
value: names.join(",")
|
|
9046
|
+
})
|
|
9047
|
+
};
|
|
9048
|
+
}
|
|
9049
|
+
case "account.org": {
|
|
9050
|
+
const orgs = await organizationChoices(server);
|
|
9051
|
+
const active = orgs.find((org) => org.active)?.name;
|
|
9052
|
+
return {
|
|
9053
|
+
kind: "pick",
|
|
9054
|
+
title: "org",
|
|
9055
|
+
rows: orgs.map((org) => ({
|
|
9056
|
+
name: org.name,
|
|
9057
|
+
description: org.slug ?? ""
|
|
9058
|
+
})),
|
|
9059
|
+
empty: "You are not a member of any organization yet.",
|
|
9060
|
+
verb: "switch",
|
|
9061
|
+
single: true,
|
|
9062
|
+
...active ? { marked: active } : {},
|
|
9063
|
+
command: (names) => ({ kind: "org", name: names[0] ?? "" })
|
|
8820
9064
|
};
|
|
9065
|
+
}
|
|
8821
9066
|
}
|
|
8822
|
-
}, [where]);
|
|
9067
|
+
}, [where, server, facts]);
|
|
8823
9068
|
const routeForDoor = useCallback3(async (door) => door.opens === undefined ? ownRoute(door.value) : routeForCommand(door.opens), [ownRoute, routeForCommand]);
|
|
8824
9069
|
const open = useCallback3((pending, title) => {
|
|
8825
9070
|
pending.then((next) => {
|
|
@@ -8836,6 +9081,29 @@ function HomeScreen({
|
|
|
8836
9081
|
open(routeForCommand(parsed.command), parsed.text);
|
|
8837
9082
|
}, [open, routeForCommand]);
|
|
8838
9083
|
const current = rows[cursor];
|
|
9084
|
+
useEffect9(() => {
|
|
9085
|
+
const value = current?.value;
|
|
9086
|
+
const probe = probeSet(value);
|
|
9087
|
+
if (!value || !probe || probes[value] !== undefined)
|
|
9088
|
+
return;
|
|
9089
|
+
let live = true;
|
|
9090
|
+
const timer = setTimeout(() => {
|
|
9091
|
+
setProbing(value);
|
|
9092
|
+
probe(where, server).then((text) => {
|
|
9093
|
+
if (live)
|
|
9094
|
+
setProbes((was) => ({ ...was, [value]: text }));
|
|
9095
|
+
}).catch(() => {
|
|
9096
|
+
return;
|
|
9097
|
+
}).finally(() => {
|
|
9098
|
+
if (live)
|
|
9099
|
+
setProbing(null);
|
|
9100
|
+
});
|
|
9101
|
+
}, REST_MS);
|
|
9102
|
+
return () => {
|
|
9103
|
+
live = false;
|
|
9104
|
+
clearTimeout(timer);
|
|
9105
|
+
};
|
|
9106
|
+
}, [current?.value, probes, probeSet, where, server]);
|
|
8839
9107
|
const activate = useCallback3(() => {
|
|
8840
9108
|
const item = rows[cursor];
|
|
8841
9109
|
if (!item)
|
|
@@ -8862,6 +9130,7 @@ function HomeScreen({
|
|
|
8862
9130
|
setRoute(null);
|
|
8863
9131
|
setQuery("");
|
|
8864
9132
|
setCursor(0);
|
|
9133
|
+
setProbes({});
|
|
8865
9134
|
reload().then(setFacts).catch(() => {
|
|
8866
9135
|
return;
|
|
8867
9136
|
});
|
|
@@ -8870,6 +9139,9 @@ function HomeScreen({
|
|
|
8870
9139
|
});
|
|
8871
9140
|
}, [reload, resite]);
|
|
8872
9141
|
const afterLogin = useCallback3(() => {
|
|
9142
|
+
learnActiveOrganization(server).then(() => reload()).then(setFacts).catch(() => {
|
|
9143
|
+
return;
|
|
9144
|
+
});
|
|
8873
9145
|
if (!wizard) {
|
|
8874
9146
|
back();
|
|
8875
9147
|
return;
|
|
@@ -8879,7 +9151,7 @@ function HomeScreen({
|
|
|
8879
9151
|
setFacts(next);
|
|
8880
9152
|
setRoute({ kind: "browse" });
|
|
8881
9153
|
}).catch(() => setRoute(null));
|
|
8882
|
-
}, [wizard, back, reload]);
|
|
9154
|
+
}, [wizard, back, reload, server]);
|
|
8883
9155
|
const leaveWelcome = useCallback3((start) => {
|
|
8884
9156
|
setWelcome(false);
|
|
8885
9157
|
onWelcomed().catch(() => {
|
|
@@ -8966,13 +9238,17 @@ function HomeScreen({
|
|
|
8966
9238
|
});
|
|
8967
9239
|
}
|
|
8968
9240
|
if (route?.kind === "pick") {
|
|
9241
|
+
const picked = route;
|
|
8969
9242
|
return /* @__PURE__ */ jsx18(PickScreen, {
|
|
8970
|
-
title:
|
|
8971
|
-
rows:
|
|
8972
|
-
empty:
|
|
8973
|
-
verb:
|
|
9243
|
+
title: picked.title,
|
|
9244
|
+
rows: picked.rows,
|
|
9245
|
+
empty: picked.empty,
|
|
9246
|
+
verb: picked.verb,
|
|
9247
|
+
...picked.single ? { single: true } : {},
|
|
9248
|
+
...picked.marked ? { marked: picked.marked } : {},
|
|
9249
|
+
...picked.preset ? { preset: picked.preset } : {},
|
|
8974
9250
|
onPick: (names) => {
|
|
8975
|
-
open(routeForCommand(
|
|
9251
|
+
open(routeForCommand(picked.command(names)), picked.title);
|
|
8976
9252
|
},
|
|
8977
9253
|
onBack: back
|
|
8978
9254
|
});
|
|
@@ -9003,14 +9279,15 @@ function HomeScreen({
|
|
|
9003
9279
|
});
|
|
9004
9280
|
}
|
|
9005
9281
|
const highlighted = current ? doorFor(current.value) : undefined;
|
|
9006
|
-
const description = current?.value === RUN && runnable(typed) ? say(typed.command,
|
|
9282
|
+
const description = current?.value === RUN && runnable(typed) ? say(typed.command, shown) : highlighted ? doorSays(highlighted, shown) : typed ? say(typed.command, shown) : "";
|
|
9283
|
+
const found = current ? probes[current.value] ?? (probing === current.value ? "looking..." : "") : "";
|
|
9007
9284
|
const empty = typed?.command.kind === "error" && typed.command.next ? `${mark.fail} ${typed.command.message} try: ${typed.command.next.replace(/^yourskills /, "")}` : "No matching commands.";
|
|
9008
9285
|
return /* @__PURE__ */ jsxs16(Frame, {
|
|
9009
9286
|
title: "yourskills",
|
|
9010
9287
|
width,
|
|
9011
9288
|
children: [
|
|
9012
9289
|
/* @__PURE__ */ jsx18(AccountLine, {
|
|
9013
|
-
facts,
|
|
9290
|
+
facts: shown,
|
|
9014
9291
|
width
|
|
9015
9292
|
}),
|
|
9016
9293
|
stale ? /* @__PURE__ */ jsx18(StaleLine, {
|
|
@@ -9034,6 +9311,10 @@ function HomeScreen({
|
|
|
9034
9311
|
dimColor: true,
|
|
9035
9312
|
children: clip(description, width - FRAME_CHROME)
|
|
9036
9313
|
}),
|
|
9314
|
+
/* @__PURE__ */ jsx18(Text16, {
|
|
9315
|
+
dimColor: true,
|
|
9316
|
+
children: found ? clip(` ${found}`, width - FRAME_CHROME) : " "
|
|
9317
|
+
}),
|
|
9037
9318
|
/* @__PURE__ */ jsx18(Hints, {
|
|
9038
9319
|
hints: [
|
|
9039
9320
|
["^v", "move"],
|
package/package.json
CHANGED