flyspace-cli 0.1.35 → 0.1.36
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/{chunk-KTMAS4TP.js → chunk-HG5Z6QVF.js} +22 -3
- package/dist/cli.js +42 -14
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -343,6 +343,7 @@ function rowToChannel(row) {
|
|
|
343
343
|
model: row.model,
|
|
344
344
|
effort: row.effort && isEffort(row.effort) ? row.effort : null,
|
|
345
345
|
prompt: row.prompt?.trim() || null,
|
|
346
|
+
topicCategories: normaliseTopicCategories(row.topic_categories),
|
|
346
347
|
// A uuid[] arrives as a real array; anything else (an older row read
|
|
347
348
|
// through a cached client, a hand-edited value) reads as "no MCP", which
|
|
348
349
|
// is the safe direction for a list that decides which credentials a run
|
|
@@ -528,6 +529,15 @@ function resolveEffort(explicitEffort, channelId, fallback) {
|
|
|
528
529
|
if (explicitEffort) return explicitEffort;
|
|
529
530
|
return resolveChannelEffort(channelId) ?? fallback;
|
|
530
531
|
}
|
|
532
|
+
function normaliseTopicCategories(value) {
|
|
533
|
+
if (!Array.isArray(value)) return [];
|
|
534
|
+
const out = [];
|
|
535
|
+
for (const v of value) {
|
|
536
|
+
const t = typeof v === "string" ? v.trim() : "";
|
|
537
|
+
if (t && !out.includes(t)) out.push(t);
|
|
538
|
+
}
|
|
539
|
+
return out;
|
|
540
|
+
}
|
|
531
541
|
function toRow(input) {
|
|
532
542
|
const row = {};
|
|
533
543
|
if (input.name !== void 0) row["name"] = input.name;
|
|
@@ -537,6 +547,10 @@ function toRow(input) {
|
|
|
537
547
|
if (input.model !== void 0) row["model"] = input.model;
|
|
538
548
|
if (input.effort !== void 0) row["effort"] = input.effort;
|
|
539
549
|
if (input.prompt !== void 0) row["prompt"] = input.prompt?.trim() || null;
|
|
550
|
+
if (input.topicCategories !== void 0) {
|
|
551
|
+
const list = normaliseTopicCategories(input.topicCategories);
|
|
552
|
+
row["topic_categories"] = list.length ? list : null;
|
|
553
|
+
}
|
|
540
554
|
if (input.access !== void 0) row["access"] = input.access;
|
|
541
555
|
if (input.visibility !== void 0) row["visibility"] = input.visibility;
|
|
542
556
|
if (input.memberEmails !== void 0) {
|
|
@@ -2625,7 +2639,7 @@ async function listWorkspaceSummaries() {
|
|
|
2625
2639
|
const [workspaces, settings, channels, memberships, activity] = await Promise.all([
|
|
2626
2640
|
db.from("workspaces").select("id, slug, created_at, agent_connected_at, plan, plan_status, archived_at"),
|
|
2627
2641
|
db.from("workspace_settings").select("profile, display_name, logo"),
|
|
2628
|
-
db.from("channels").select("profile").is("archived_at", null),
|
|
2642
|
+
db.from("channels").select("profile, is_default").is("archived_at", null),
|
|
2629
2643
|
db.from("memberships").select("workspace_id, user_id, email, handle, role, accepted_at").eq("status", "active").eq("is_support", false).order("invited_at", { ascending: true }),
|
|
2630
2644
|
db.rpc("workspace_last_activity")
|
|
2631
2645
|
]);
|
|
@@ -2646,6 +2660,9 @@ async function listWorkspaceSummaries() {
|
|
|
2646
2660
|
);
|
|
2647
2661
|
const tally = (keys) => keys.reduce((m, k) => m.set(k, (m.get(k) ?? 0) + 1), /* @__PURE__ */ new Map());
|
|
2648
2662
|
const channelCounts = tally((channels.data ?? []).map((c) => c.profile));
|
|
2663
|
+
const ownChannelCounts = tally(
|
|
2664
|
+
(channels.data ?? []).filter((c) => !c.is_default).map((c) => c.profile)
|
|
2665
|
+
);
|
|
2649
2666
|
const memberCounts = tally((memberships.data ?? []).map((m) => m.workspace_id));
|
|
2650
2667
|
const owners = /* @__PURE__ */ new Map();
|
|
2651
2668
|
for (const m of memberships.data ?? []) {
|
|
@@ -2672,6 +2689,7 @@ async function listWorkspaceSummaries() {
|
|
|
2672
2689
|
displayName: displayNames.get(w.slug) || null,
|
|
2673
2690
|
logo: logos.get(w.slug) || null,
|
|
2674
2691
|
channelCount: channelCounts.get(w.slug) ?? 0,
|
|
2692
|
+
ownChannelCount: ownChannelCounts.get(w.slug) ?? 0,
|
|
2675
2693
|
memberCount: memberCounts.get(w.id) ?? 0,
|
|
2676
2694
|
lastActivityAt: lastActivity.get(w.slug) ?? null,
|
|
2677
2695
|
owner: owners.get(w.id) ?? null
|
|
@@ -2961,8 +2979,8 @@ var MAX_BODY_CHARS = 4e3;
|
|
|
2961
2979
|
var MAX_THREAD_CHARS = 12e3;
|
|
2962
2980
|
var THREAD_TIMEOUT_MS = 15e3;
|
|
2963
2981
|
var SUBJECT_MAX_CHARS = 30;
|
|
2964
|
-
var CATEGORY_MAX_CHARS =
|
|
2965
|
-
var DEFAULT_TITLE_RULES = `- category: ONE short
|
|
2982
|
+
var CATEGORY_MAX_CHARS = 16;
|
|
2983
|
+
var DEFAULT_TITLE_RULES = `- category: ONE short phrase naming the component or feature area the thread is about (e.g. Docs pane, Auto Topic, Login, Billing), not the kind of request. Pick from Channel categories whenever one fits, otherwise reuse one of the Existing categories; invent a new area name only if none fits. Generic types such as Bug, Feature, Idea or Question are a last resort, only when no area can be named.
|
|
2966
2984
|
- subject: the most concise noun phrase that names the topic, as short as possible (aim for 3 to 6 words, or under 15 Chinese characters). Keep only the core topic: drop filler, background, verbs like "help me" or "how to", and details already implied by the category or channel. Not a copied sentence, no quotes, no Markdown, no trailing punctuation.
|
|
2967
2985
|
- If the Workspace or Channel instructions contain title or naming rules, follow them over the defaults above.
|
|
2968
2986
|
- Keep the message's own language. If it is Traditional Chinese (Taiwan), use Taiwan wording and keep technical terms in English.
|
|
@@ -3003,6 +3021,7 @@ async function buildAutoTitle(input) {
|
|
|
3003
3021
|
${input.workspacePrompt.slice(0, 1500)}` : "",
|
|
3004
3022
|
input.channelPrompt ? `Channel instructions:
|
|
3005
3023
|
${input.channelPrompt.slice(0, 1500)}` : "",
|
|
3024
|
+
input.channelCategories.length ? `Channel categories (pick one of these whenever it fits): ${input.channelCategories.join(", ")}` : "",
|
|
3006
3025
|
`Existing categories: ${input.existingCategories.length ? input.existingCategories.join(", ") : "(none yet)"}`,
|
|
3007
3026
|
whole ? `Conversation (latest last):
|
|
3008
3027
|
${input.body.slice(-MAX_THREAD_CHARS)}` : `Opening message:
|
package/dist/cli.js
CHANGED
|
@@ -187,7 +187,7 @@ import {
|
|
|
187
187
|
warnOnBrokenChannelCwds,
|
|
188
188
|
workspaceSkillsDir,
|
|
189
189
|
writeSkillFile
|
|
190
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-HG5Z6QVF.js";
|
|
191
191
|
import {
|
|
192
192
|
firstReplyBody,
|
|
193
193
|
getThread,
|
|
@@ -1861,7 +1861,7 @@ async function runAuthCmd(args) {
|
|
|
1861
1861
|
}
|
|
1862
1862
|
|
|
1863
1863
|
// ../api/src/version.ts
|
|
1864
|
-
var CLI_VERSION = true ? "0.1.
|
|
1864
|
+
var CLI_VERSION = true ? "0.1.36" : null;
|
|
1865
1865
|
function isOlderVersion(a, b) {
|
|
1866
1866
|
const parse = (v) => v.replace(/^v/, "").split("-")[0].split(".").map(Number);
|
|
1867
1867
|
const [pa, pb] = [parse(a), parse(b)];
|
|
@@ -2471,7 +2471,7 @@ function npmEnv(target) {
|
|
|
2471
2471
|
return nodeBin ? { ...process.env, PATH: `${nodeBin}:${process.env.PATH ?? ""}` } : process.env;
|
|
2472
2472
|
}
|
|
2473
2473
|
async function runUpgrade() {
|
|
2474
|
-
const current = "0.1.
|
|
2474
|
+
const current = "0.1.36";
|
|
2475
2475
|
console.log(`Current version: ${current}`);
|
|
2476
2476
|
console.log("Checking for updates...\n");
|
|
2477
2477
|
try {
|
|
@@ -3331,19 +3331,31 @@ function hashInviteToken(token) {
|
|
|
3331
3331
|
}
|
|
3332
3332
|
async function issueInvite(membershipId, message) {
|
|
3333
3333
|
const db = getSupabaseClient();
|
|
3334
|
-
const { error: clearError } = await db.from("workspace_invites").delete().eq("membership_id", membershipId).is("accepted_at", null);
|
|
3335
|
-
if (clearError) throw new Error(`issueInvite(${membershipId}): ${clearError.message}`);
|
|
3336
3334
|
const token = randomBytes2(32).toString("hex");
|
|
3337
|
-
const expiresAt = new Date(Date.now() + INVITE_TTL_DAYS * 24 * 60 * 60 * 1e3);
|
|
3338
|
-
const { error:
|
|
3335
|
+
const expiresAt = new Date(Date.now() + INVITE_TTL_DAYS * 24 * 60 * 60 * 1e3).toISOString();
|
|
3336
|
+
const { data: pending2, error: pendingError } = await db.from("workspace_invites").select("id, token_hash, previous_token_hashes").eq("membership_id", membershipId).is("accepted_at", null).order("created_at", { ascending: false }).limit(1).maybeSingle();
|
|
3337
|
+
if (pendingError) throw new Error(`issueInvite(${membershipId}): ${pendingError.message}`);
|
|
3338
|
+
const { error: error2 } = pending2 ? await db.from("workspace_invites").update({
|
|
3339
|
+
token_hash: hashInviteToken(token),
|
|
3340
|
+
previous_token_hashes: [
|
|
3341
|
+
...pending2.previous_token_hashes ?? [],
|
|
3342
|
+
pending2.token_hash
|
|
3343
|
+
],
|
|
3344
|
+
message,
|
|
3345
|
+
expires_at: expiresAt
|
|
3346
|
+
}).eq("id", pending2.id) : await db.from("workspace_invites").insert({
|
|
3339
3347
|
membership_id: membershipId,
|
|
3340
3348
|
token_hash: hashInviteToken(token),
|
|
3341
3349
|
message,
|
|
3342
|
-
expires_at: expiresAt
|
|
3350
|
+
expires_at: expiresAt
|
|
3343
3351
|
});
|
|
3344
3352
|
if (error2) throw new Error(`issueInvite(${membershipId}): ${error2.message}`);
|
|
3345
3353
|
return token;
|
|
3346
3354
|
}
|
|
3355
|
+
function tokenHashFilter(token) {
|
|
3356
|
+
const hash = hashInviteToken(token);
|
|
3357
|
+
return `token_hash.eq.${hash},previous_token_hashes.cs.{${hash}}`;
|
|
3358
|
+
}
|
|
3347
3359
|
async function latestInviteMessage(membershipId) {
|
|
3348
3360
|
const { data, error: error2 } = await getSupabaseClient().from("workspace_invites").select("message").eq("membership_id", membershipId).order("created_at", { ascending: false }).limit(1).maybeSingle();
|
|
3349
3361
|
if (error2) throw new Error(`latestInviteMessage(${membershipId}): ${error2.message}`);
|
|
@@ -3352,7 +3364,7 @@ async function latestInviteMessage(membershipId) {
|
|
|
3352
3364
|
async function lookupInviteByToken(token) {
|
|
3353
3365
|
const { data, error: error2 } = await getSupabaseClient().from("workspace_invites").select(
|
|
3354
3366
|
"id, message, expires_at, accepted_at, memberships!inner(workspace_id, user_id, email)"
|
|
3355
|
-
).
|
|
3367
|
+
).or(tokenHashFilter(token)).maybeSingle();
|
|
3356
3368
|
if (error2) throw new Error(`lookupInviteByToken: ${error2.message}`);
|
|
3357
3369
|
return toInviteLookup(data);
|
|
3358
3370
|
}
|
|
@@ -3817,12 +3829,19 @@ async function revokeSetupInvite(id) {
|
|
|
3817
3829
|
}
|
|
3818
3830
|
async function reissueSetupInvite(id) {
|
|
3819
3831
|
const db = getSupabaseClient();
|
|
3820
|
-
const { data, error: error2 } = await db.from("workspace_setup_invites").select("email, owner_name, message").eq("id", id).is("accepted_at", null).maybeSingle();
|
|
3832
|
+
const { data, error: error2 } = await db.from("workspace_setup_invites").select("email, owner_name, message, token_hash, previous_token_hashes").eq("id", id).is("accepted_at", null).maybeSingle();
|
|
3821
3833
|
if (error2) throw new Error(`reissueSetupInvite(${id}): ${error2.message}`);
|
|
3822
3834
|
if (!data) throw new Error("no pending invite with that id");
|
|
3823
3835
|
const token = randomBytes3(32).toString("hex");
|
|
3824
3836
|
const expiresAt = new Date(Date.now() + INVITE_TTL_DAYS * 24 * 60 * 60 * 1e3);
|
|
3825
|
-
const { error: updateError } = await db.from("workspace_setup_invites").update({
|
|
3837
|
+
const { error: updateError } = await db.from("workspace_setup_invites").update({
|
|
3838
|
+
token_hash: hashInviteToken(token),
|
|
3839
|
+
previous_token_hashes: [
|
|
3840
|
+
...data.previous_token_hashes ?? [],
|
|
3841
|
+
data.token_hash
|
|
3842
|
+
],
|
|
3843
|
+
expires_at: expiresAt.toISOString()
|
|
3844
|
+
}).eq("id", id);
|
|
3826
3845
|
if (updateError) throw new Error(`reissueSetupInvite(${id}): ${updateError.message}`);
|
|
3827
3846
|
return {
|
|
3828
3847
|
token,
|
|
@@ -3834,7 +3853,7 @@ async function reissueSetupInvite(id) {
|
|
|
3834
3853
|
};
|
|
3835
3854
|
}
|
|
3836
3855
|
async function lookupSetupInvite(token) {
|
|
3837
|
-
const { data, error: error2 } = await getSupabaseClient().from("workspace_setup_invites").select("id, email, owner_name, plan, message, expires_at, accepted_at, workspace_id").
|
|
3856
|
+
const { data, error: error2 } = await getSupabaseClient().from("workspace_setup_invites").select("id, email, owner_name, plan, message, expires_at, accepted_at, workspace_id").or(tokenHashFilter(token)).maybeSingle();
|
|
3838
3857
|
if (error2) throw new Error(`lookupSetupInvite: ${error2.message}`);
|
|
3839
3858
|
if (!data) return { state: "unknown" };
|
|
3840
3859
|
if (data.accepted_at) return { state: "used", workspaceId: data.workspace_id ?? null };
|
|
@@ -10596,6 +10615,7 @@ async function labelThread(channelId, body, scope) {
|
|
|
10596
10615
|
return buildAutoTitle({
|
|
10597
10616
|
channelName: channel.name,
|
|
10598
10617
|
channelPrompt: channel.prompt,
|
|
10618
|
+
channelCategories: channel.topicCategories,
|
|
10599
10619
|
workspacePrompt: loadWorkspacePrompt().prompt,
|
|
10600
10620
|
titlePrompt: (await loadWorkspaceBranding()).autoTitlePrompt,
|
|
10601
10621
|
existingCategories,
|
|
@@ -14374,6 +14394,7 @@ function registerDataRoutes(api, agent = {}) {
|
|
|
14374
14394
|
model: ch.model ?? void 0,
|
|
14375
14395
|
effort: ch.effort ?? void 0,
|
|
14376
14396
|
prompt: ch.prompt ?? void 0,
|
|
14397
|
+
topicCategories: ch.topicCategories,
|
|
14377
14398
|
access: ch.access,
|
|
14378
14399
|
visibility: ch.visibility,
|
|
14379
14400
|
memberEmails: ch.memberEmails,
|
|
@@ -15222,6 +15243,9 @@ function coerceRuntime(raw) {
|
|
|
15222
15243
|
function coerceEffort(raw) {
|
|
15223
15244
|
return typeof raw === "string" && isEffort(raw) ? raw : void 0;
|
|
15224
15245
|
}
|
|
15246
|
+
function coerceTopicCategories(raw) {
|
|
15247
|
+
return Array.isArray(raw) ? raw.filter((v) => typeof v === "string") : void 0;
|
|
15248
|
+
}
|
|
15225
15249
|
function coerceMounts(raw) {
|
|
15226
15250
|
const list = typeof raw === "string" ? raw.split("\n") : raw;
|
|
15227
15251
|
if (!Array.isArray(list)) return void 0;
|
|
@@ -15258,6 +15282,7 @@ function toResponse3(channel) {
|
|
|
15258
15282
|
model: channel.model ?? void 0,
|
|
15259
15283
|
effort: channel.effort ?? void 0,
|
|
15260
15284
|
prompt: channel.prompt ?? void 0,
|
|
15285
|
+
topicCategories: channel.topicCategories,
|
|
15261
15286
|
access: channel.access,
|
|
15262
15287
|
visibility: channel.visibility,
|
|
15263
15288
|
memberEmails: channel.memberEmails,
|
|
@@ -15289,6 +15314,7 @@ function createChannelWriteRouter() {
|
|
|
15289
15314
|
model: model || null,
|
|
15290
15315
|
effort: coerceEffort(body["effort"]) ?? null,
|
|
15291
15316
|
prompt: typeof body["prompt"] === "string" ? body["prompt"] : null,
|
|
15317
|
+
topicCategories: coerceTopicCategories(body["topicCategories"]),
|
|
15292
15318
|
access: coerceAccess(body["access"]),
|
|
15293
15319
|
visibility: coerceVisibility(body["visibility"]),
|
|
15294
15320
|
memberEmails: coerceMemberEmails(body["memberEmails"]),
|
|
@@ -15318,6 +15344,7 @@ function createChannelWriteRouter() {
|
|
|
15318
15344
|
model: model || null,
|
|
15319
15345
|
effort: coerceEffort(body["effort"]) ?? null,
|
|
15320
15346
|
prompt: typeof body["prompt"] === "string" ? body["prompt"] : null,
|
|
15347
|
+
topicCategories: coerceTopicCategories(body["topicCategories"]),
|
|
15321
15348
|
access: coerceAccess(body["access"]),
|
|
15322
15349
|
visibility: coerceVisibility(body["visibility"]),
|
|
15323
15350
|
memberEmails: coerceMemberEmails(body["memberEmails"]),
|
|
@@ -15360,6 +15387,7 @@ function createChannelWriteRouter() {
|
|
|
15360
15387
|
if (typeof body["position"] === "number") patch.position = body["position"];
|
|
15361
15388
|
if (typeof body["model"] === "string") patch.model = body["model"] || null;
|
|
15362
15389
|
if ("effort" in body) patch.effort = coerceEffort(body["effort"]) ?? null;
|
|
15390
|
+
if ("topicCategories" in body) patch.topicCategories = coerceTopicCategories(body["topicCategories"]);
|
|
15363
15391
|
if ("prompt" in body) {
|
|
15364
15392
|
patch.prompt = typeof body["prompt"] === "string" ? body["prompt"] : null;
|
|
15365
15393
|
}
|
|
@@ -19993,7 +20021,7 @@ var MAX_AGE_MINUTES = 30;
|
|
|
19993
20021
|
var GRACE_MS = 6e4;
|
|
19994
20022
|
var BODY_LIMIT = 140;
|
|
19995
20023
|
function preview(body) {
|
|
19996
|
-
const flat = body.replace(/```[\s\S]*?```/g, "[code]").replace(/\s+/g, " ").trim();
|
|
20024
|
+
const flat = body.replace(/```[\s\S]*?```/g, "[code]").replace(/!\[([^\]]*)\]\([^)]*\)/g, (_, alt) => alt || "[image]").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/<(https?:[^|>]+)\|([^>]+)>/g, "$2").replace(/^\s{0,3}(?:#{1,6}\s+|>\s?|[-*+]\s+(?:\[[ xX]\]\s+)?|\d+[.)]\s+)/gm, "").replace(/^\s*(?:[-*_]\s*){3,}$/gm, "").replace(/(\*\*|__|~~)(.+?)\1/g, "$2").replace(/(^|[^\w*])[*_](\S(?:.*?\S)?)[*_](?=[^\w*]|$)/g, "$1$2").replace(/`([^`]+)`/g, "$1").replace(/\s+/g, " ").trim();
|
|
19997
20025
|
return flat.length > BODY_LIMIT ? `${flat.slice(0, BODY_LIMIT - 1)}\u2026` : flat;
|
|
19998
20026
|
}
|
|
19999
20027
|
async function channelNames(ids) {
|
|
@@ -20679,7 +20707,7 @@ async function main() {
|
|
|
20679
20707
|
break;
|
|
20680
20708
|
case "-v":
|
|
20681
20709
|
case "--version":
|
|
20682
|
-
printRaw("0.1.
|
|
20710
|
+
printRaw("0.1.36");
|
|
20683
20711
|
break;
|
|
20684
20712
|
case "-h":
|
|
20685
20713
|
case "--help":
|
package/dist/index.js
CHANGED