@treeseed/cli 0.6.25 → 0.6.26
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/cli/handlers/auth-login.js +15 -19
- package/dist/cli/handlers/auth-logout.js +13 -8
- package/dist/cli/handlers/auth-whoami.js +37 -11
- package/dist/cli/handlers/market-utils.d.ts +12 -0
- package/dist/cli/handlers/market-utils.js +39 -0
- package/dist/cli/handlers/market.d.ts +2 -0
- package/dist/cli/handlers/market.js +88 -0
- package/dist/cli/handlers/packs.d.ts +2 -0
- package/dist/cli/handlers/packs.js +70 -0
- package/dist/cli/handlers/projects.d.ts +2 -0
- package/dist/cli/handlers/projects.js +48 -0
- package/dist/cli/handlers/teams.d.ts +2 -0
- package/dist/cli/handlers/teams.js +47 -0
- package/dist/cli/handlers/template.js +63 -0
- package/dist/cli/operations-registry.js +127 -2
- package/dist/cli/registry.d.ts +4 -0
- package/dist/cli/registry.js +8 -0
- package/dist/cli/runtime.js +13 -1
- package/package.json +2 -2
|
@@ -1,25 +1,19 @@
|
|
|
1
|
-
import { RemoteTreeseedAuthClient, RemoteTreeseedClient } from "@treeseed/sdk/remote";
|
|
2
1
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from "@treeseed/sdk/workflow-support";
|
|
2
|
+
setMarketSession
|
|
3
|
+
} from "@treeseed/sdk/market-client";
|
|
4
|
+
import { TreeseedKeyAgentError } from "@treeseed/sdk/workflow-support";
|
|
7
5
|
import { guidedResult } from "./utils.js";
|
|
6
|
+
import { createMarketClientForInvocation, marketAuthRoot } from "./market-utils.js";
|
|
8
7
|
function sleep(ms) {
|
|
9
8
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
9
|
}
|
|
11
10
|
const handleAuthLogin = async (invocation, context) => {
|
|
12
11
|
try {
|
|
13
|
-
const tenantRoot = context
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const client = new RemoteTreeseedAuthClient(new RemoteTreeseedClient({
|
|
17
|
-
...remoteConfig,
|
|
18
|
-
activeHostId: hostId
|
|
19
|
-
}));
|
|
20
|
-
const started = await client.startDeviceFlow({
|
|
12
|
+
const tenantRoot = marketAuthRoot(context);
|
|
13
|
+
const { profile, client } = createMarketClientForInvocation(invocation, context);
|
|
14
|
+
const started = await client.startDeviceLogin({
|
|
21
15
|
clientName: "treeseed-cli",
|
|
22
|
-
scopes: ["auth:me", "
|
|
16
|
+
scopes: ["auth:me", "market"]
|
|
23
17
|
});
|
|
24
18
|
if (context.outputFormat !== "json") {
|
|
25
19
|
context.write(`Open ${started.verificationUriComplete}`, "stdout");
|
|
@@ -28,10 +22,10 @@ const handleAuthLogin = async (invocation, context) => {
|
|
|
28
22
|
}
|
|
29
23
|
const deadline = Date.parse(started.expiresAt);
|
|
30
24
|
while (Date.now() < deadline) {
|
|
31
|
-
const response = await client.
|
|
25
|
+
const response = await client.pollDeviceLogin({ deviceCode: started.deviceCode });
|
|
32
26
|
if (response.ok && response.status === "approved") {
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
setMarketSession(tenantRoot, {
|
|
28
|
+
marketId: profile.id,
|
|
35
29
|
accessToken: response.accessToken,
|
|
36
30
|
refreshToken: response.refreshToken,
|
|
37
31
|
expiresAt: response.expiresAt,
|
|
@@ -41,12 +35,14 @@ const handleAuthLogin = async (invocation, context) => {
|
|
|
41
35
|
command: "auth:login",
|
|
42
36
|
summary: "Treeseed API login completed successfully.",
|
|
43
37
|
facts: [
|
|
44
|
-
{ label: "
|
|
38
|
+
{ label: "Market", value: profile.id },
|
|
39
|
+
{ label: "URL", value: profile.baseUrl },
|
|
45
40
|
{ label: "Principal", value: response.principal.displayName ?? response.principal.id },
|
|
46
41
|
{ label: "Scopes", value: response.principal.scopes.join(", ") }
|
|
47
42
|
],
|
|
48
43
|
report: {
|
|
49
|
-
|
|
44
|
+
marketId: profile.id,
|
|
45
|
+
baseUrl: profile.baseUrl,
|
|
50
46
|
principal: response.principal
|
|
51
47
|
}
|
|
52
48
|
});
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
|
-
clearTreeseedRemoteSession,
|
|
3
|
-
resolveTreeseedRemoteConfig,
|
|
4
2
|
TreeseedKeyAgentError
|
|
5
3
|
} from "@treeseed/sdk/workflow-support";
|
|
4
|
+
import { clearMarketSession } from "@treeseed/sdk/market-client";
|
|
6
5
|
import { guidedResult } from "./utils.js";
|
|
6
|
+
import { createMarketClientForInvocation, marketAuthRoot } from "./market-utils.js";
|
|
7
7
|
const handleAuthLogout = async (invocation, context) => {
|
|
8
8
|
try {
|
|
9
|
-
const tenantRoot = context
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
const tenantRoot = marketAuthRoot(context);
|
|
10
|
+
const { profile, client, session } = createMarketClientForInvocation(invocation, context);
|
|
11
|
+
if (session?.accessToken) {
|
|
12
|
+
await client.logout().catch(() => null);
|
|
13
|
+
}
|
|
14
|
+
clearMarketSession(tenantRoot, profile.id);
|
|
13
15
|
return guidedResult({
|
|
14
16
|
command: "auth:logout",
|
|
15
17
|
summary: "Cleared the local Treeseed API session.",
|
|
16
|
-
facts: [
|
|
17
|
-
|
|
18
|
+
facts: [
|
|
19
|
+
{ label: "Market", value: profile.id },
|
|
20
|
+
{ label: "URL", value: profile.baseUrl }
|
|
21
|
+
],
|
|
22
|
+
report: { marketId: profile.id, baseUrl: profile.baseUrl }
|
|
18
23
|
});
|
|
19
24
|
} catch (error) {
|
|
20
25
|
if (error instanceof TreeseedKeyAgentError) {
|
|
@@ -1,22 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { loadMarketRegistryState, resolveMarketSession } from "@treeseed/sdk/market-client";
|
|
2
|
+
import { TreeseedKeyAgentError } from "@treeseed/sdk/workflow-support";
|
|
3
3
|
import { guidedResult } from "./utils.js";
|
|
4
|
-
|
|
4
|
+
import { createMarketClientForInvocation, marketAuthRoot } from "./market-utils.js";
|
|
5
|
+
const handleAuthWhoAmI = async (invocation, context) => {
|
|
5
6
|
try {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
if (invocation.args.allMarkets === true) {
|
|
8
|
+
const tenantRoot = marketAuthRoot(context);
|
|
9
|
+
const state = loadMarketRegistryState();
|
|
10
|
+
const sessions = state.profiles.map((profile2) => ({
|
|
11
|
+
profile: profile2,
|
|
12
|
+
session: resolveMarketSession(tenantRoot, profile2.id)
|
|
13
|
+
}));
|
|
14
|
+
return guidedResult({
|
|
15
|
+
command: "auth:whoami",
|
|
16
|
+
summary: "Treeseed market identities",
|
|
17
|
+
sections: [{
|
|
18
|
+
title: "Markets",
|
|
19
|
+
lines: sessions.map(({ profile: profile2, session }) => `${profile2.id}: ${session?.principal?.displayName ?? session?.principal?.id ?? "(not logged in)"}`)
|
|
20
|
+
}],
|
|
21
|
+
report: {
|
|
22
|
+
markets: sessions.map(({ profile: profile2, session }) => ({
|
|
23
|
+
marketId: profile2.id,
|
|
24
|
+
baseUrl: profile2.baseUrl,
|
|
25
|
+
principal: session?.principal ?? null
|
|
26
|
+
}))
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const { profile, client } = createMarketClientForInvocation(invocation, context, { requireAuth: true });
|
|
31
|
+
const response = await client.me();
|
|
9
32
|
return guidedResult({
|
|
10
33
|
command: "auth:whoami",
|
|
11
34
|
summary: "Treeseed API identity",
|
|
12
35
|
facts: [
|
|
13
|
-
{ label: "
|
|
14
|
-
{ label: "
|
|
15
|
-
{ label: "
|
|
36
|
+
{ label: "Market", value: profile.id },
|
|
37
|
+
{ label: "URL", value: profile.baseUrl },
|
|
38
|
+
{ label: "Principal", value: response.payload.principal.displayName ?? response.payload.principal.id },
|
|
39
|
+
{ label: "Scopes", value: response.payload.principal.scopes.join(", ") }
|
|
16
40
|
],
|
|
17
41
|
report: {
|
|
18
|
-
|
|
19
|
-
|
|
42
|
+
marketId: profile.id,
|
|
43
|
+
baseUrl: profile.baseUrl,
|
|
44
|
+
principal: response.payload.principal,
|
|
45
|
+
teams: response.payload.teams
|
|
20
46
|
}
|
|
21
47
|
});
|
|
22
48
|
} catch (error) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MarketClient, type MarketProfile } from '@treeseed/sdk/market-client';
|
|
2
|
+
import type { TreeseedCommandContext, TreeseedParsedInvocation } from '../types.js';
|
|
3
|
+
export declare function marketAuthRoot(context: TreeseedCommandContext): string;
|
|
4
|
+
export declare function marketSelector(invocation: TreeseedParsedInvocation): string | null;
|
|
5
|
+
export declare function createMarketClientForInvocation(invocation: TreeseedParsedInvocation, context: TreeseedCommandContext, options?: {
|
|
6
|
+
requireAuth?: boolean;
|
|
7
|
+
}): {
|
|
8
|
+
profile: MarketProfile;
|
|
9
|
+
session: import("@treeseed/sdk/market-client").MarketSession | null;
|
|
10
|
+
client: MarketClient;
|
|
11
|
+
};
|
|
12
|
+
export declare function formatMarketProfile(profile: MarketProfile): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
MarketClient,
|
|
5
|
+
resolveMarketProfile,
|
|
6
|
+
resolveMarketSession
|
|
7
|
+
} from "@treeseed/sdk/market-client";
|
|
8
|
+
import { findNearestTreeseedRoot } from "@treeseed/sdk/workflow-support";
|
|
9
|
+
function marketAuthRoot(context) {
|
|
10
|
+
return findNearestTreeseedRoot(context.cwd) ?? resolve(context.env.HOME || homedir());
|
|
11
|
+
}
|
|
12
|
+
function marketSelector(invocation) {
|
|
13
|
+
return typeof invocation.args.market === "string" ? invocation.args.market : typeof invocation.args.host === "string" ? invocation.args.host : null;
|
|
14
|
+
}
|
|
15
|
+
function createMarketClientForInvocation(invocation, context, options = {}) {
|
|
16
|
+
const profile = resolveMarketProfile(marketSelector(invocation));
|
|
17
|
+
const session = resolveMarketSession(marketAuthRoot(context), profile.id);
|
|
18
|
+
if (options.requireAuth && !session?.accessToken) {
|
|
19
|
+
throw new Error(`Not logged in to market "${profile.id}". Run treeseed auth:login --market ${profile.id}.`);
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
profile,
|
|
23
|
+
session,
|
|
24
|
+
client: new MarketClient({
|
|
25
|
+
profile,
|
|
26
|
+
accessToken: session?.accessToken ?? null,
|
|
27
|
+
userAgent: "treeseed-cli"
|
|
28
|
+
})
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function formatMarketProfile(profile) {
|
|
32
|
+
return `${profile.id} ${profile.baseUrl} ${profile.kind}${profile.teamId ? ` team=${profile.teamId}` : ""}`;
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
createMarketClientForInvocation,
|
|
36
|
+
formatMarketProfile,
|
|
37
|
+
marketAuthRoot,
|
|
38
|
+
marketSelector
|
|
39
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addMarketProfile,
|
|
3
|
+
loadMarketRegistryState,
|
|
4
|
+
removeMarketProfile,
|
|
5
|
+
setActiveMarketProfile
|
|
6
|
+
} from "@treeseed/sdk/market-client";
|
|
7
|
+
import { guidedResult } from "./utils.js";
|
|
8
|
+
import { createMarketClientForInvocation, formatMarketProfile } from "./market-utils.js";
|
|
9
|
+
const handleMarket = async (invocation, context) => {
|
|
10
|
+
const action = invocation.positionals[0] ?? "list";
|
|
11
|
+
if (action === "list") {
|
|
12
|
+
const state = loadMarketRegistryState();
|
|
13
|
+
return guidedResult({
|
|
14
|
+
command: "market",
|
|
15
|
+
summary: "Configured Treeseed markets",
|
|
16
|
+
sections: [{
|
|
17
|
+
title: "Markets",
|
|
18
|
+
lines: state.profiles.map((profile) => `${profile.id === state.activeMarketId ? "*" : " "} ${formatMarketProfile(profile)}`)
|
|
19
|
+
}],
|
|
20
|
+
report: state
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
if (action === "add") {
|
|
24
|
+
const id = invocation.positionals[1];
|
|
25
|
+
const baseUrl = invocation.positionals[2];
|
|
26
|
+
if (!id || !baseUrl) {
|
|
27
|
+
return { exitCode: 1, stderr: ["Usage: treeseed market add <id> <url>"] };
|
|
28
|
+
}
|
|
29
|
+
const state = addMarketProfile({
|
|
30
|
+
id,
|
|
31
|
+
label: typeof invocation.args.label === "string" ? invocation.args.label : id,
|
|
32
|
+
baseUrl,
|
|
33
|
+
kind: invocation.args.kind === "central" ? "central" : "specialized",
|
|
34
|
+
teamId: typeof invocation.args.team === "string" ? invocation.args.team : null,
|
|
35
|
+
alwaysAvailable: invocation.args.kind === "central"
|
|
36
|
+
});
|
|
37
|
+
return guidedResult({
|
|
38
|
+
command: "market",
|
|
39
|
+
summary: `Added market "${id}".`,
|
|
40
|
+
report: state
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (action === "remove") {
|
|
44
|
+
const id = invocation.positionals[1];
|
|
45
|
+
if (!id) return { exitCode: 1, stderr: ["Usage: treeseed market remove <id>"] };
|
|
46
|
+
const state = removeMarketProfile(id);
|
|
47
|
+
return guidedResult({
|
|
48
|
+
command: "market",
|
|
49
|
+
summary: `Removed market "${id}".`,
|
|
50
|
+
report: state
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (action === "use") {
|
|
54
|
+
const id = invocation.positionals[1];
|
|
55
|
+
if (!id) return { exitCode: 1, stderr: ["Usage: treeseed market use <id>"] };
|
|
56
|
+
const state = setActiveMarketProfile(id);
|
|
57
|
+
return guidedResult({
|
|
58
|
+
command: "market",
|
|
59
|
+
summary: `Active market is now "${id}".`,
|
|
60
|
+
report: state
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (action === "status") {
|
|
64
|
+
const { profile, client, session } = createMarketClientForInvocation(invocation, context);
|
|
65
|
+
const current = await client.currentMarket().catch(() => null);
|
|
66
|
+
return guidedResult({
|
|
67
|
+
command: "market",
|
|
68
|
+
summary: "Treeseed market status",
|
|
69
|
+
facts: [
|
|
70
|
+
{ label: "Market", value: profile.id },
|
|
71
|
+
{ label: "URL", value: profile.baseUrl },
|
|
72
|
+
{ label: "Kind", value: current?.payload.kind ?? profile.kind },
|
|
73
|
+
{ label: "Authenticated", value: Boolean(session?.accessToken) }
|
|
74
|
+
],
|
|
75
|
+
report: {
|
|
76
|
+
market: current?.payload ?? profile,
|
|
77
|
+
authenticated: Boolean(session?.accessToken)
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
exitCode: 1,
|
|
83
|
+
stderr: [`Unknown market action: ${action}`]
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
export {
|
|
87
|
+
handleMarket
|
|
88
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
listIntegratedMarketCatalog,
|
|
5
|
+
resolveIntegratedCatalogArtifactDownload,
|
|
6
|
+
verifyArtifactBytes
|
|
7
|
+
} from "@treeseed/sdk/market-client";
|
|
8
|
+
import { guidedResult } from "./utils.js";
|
|
9
|
+
import { marketAuthRoot, marketSelector } from "./market-utils.js";
|
|
10
|
+
function artifactFileName(kind, slug, version) {
|
|
11
|
+
return `${kind}-${slug}-${version}.tar`.replace(/[^A-Za-z0-9._-]+/g, "-");
|
|
12
|
+
}
|
|
13
|
+
const handlePacks = async (invocation, context) => {
|
|
14
|
+
const action = invocation.positionals[0] ?? "search";
|
|
15
|
+
const selector = marketSelector(invocation);
|
|
16
|
+
const authRoot = marketAuthRoot(context);
|
|
17
|
+
if (action === "search" || action === "list") {
|
|
18
|
+
const response = await listIntegratedMarketCatalog({
|
|
19
|
+
kind: "knowledge_pack",
|
|
20
|
+
selector,
|
|
21
|
+
authRoot,
|
|
22
|
+
userAgent: "treeseed-cli"
|
|
23
|
+
});
|
|
24
|
+
return guidedResult({
|
|
25
|
+
command: "packs",
|
|
26
|
+
summary: selector ? "Treeseed knowledge packs" : "Treeseed integrated knowledge packs",
|
|
27
|
+
sections: [{
|
|
28
|
+
title: "Packs",
|
|
29
|
+
lines: response.payload.map((pack) => `${pack.id} ${pack.title ?? pack.name ?? pack.slug} market=${pack.sourceMarket.label ?? pack.sourceMarket.id}`)
|
|
30
|
+
}],
|
|
31
|
+
report: { selector, packs: response.payload, errors: response.errors }
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (action === "install") {
|
|
35
|
+
const itemId = invocation.positionals[1];
|
|
36
|
+
const version = typeof invocation.args.version === "string" ? invocation.args.version : "1.0.0";
|
|
37
|
+
if (!itemId) return { exitCode: 1, stderr: ["Usage: treeseed packs install <item-id> [--version <version>]"] };
|
|
38
|
+
const response = await resolveIntegratedCatalogArtifactDownload({
|
|
39
|
+
itemId,
|
|
40
|
+
version,
|
|
41
|
+
selector,
|
|
42
|
+
authRoot,
|
|
43
|
+
userAgent: "treeseed-cli"
|
|
44
|
+
});
|
|
45
|
+
const download = await fetch(response.payload.downloadUrl);
|
|
46
|
+
if (!download.ok) {
|
|
47
|
+
return { exitCode: 1, stderr: [`Artifact download failed with ${download.status}.`] };
|
|
48
|
+
}
|
|
49
|
+
const bytes = await verifyArtifactBytes(download, response.payload.sha256);
|
|
50
|
+
const outputDir = resolve(context.cwd, ".treeseed", "downloads");
|
|
51
|
+
mkdirSync(outputDir, { recursive: true });
|
|
52
|
+
const outputPath = resolve(outputDir, artifactFileName(response.payload.kind, response.payload.slug ?? itemId, response.payload.version));
|
|
53
|
+
writeFileSync(outputPath, bytes);
|
|
54
|
+
return guidedResult({
|
|
55
|
+
command: "packs",
|
|
56
|
+
summary: "Downloaded knowledge pack artifact.",
|
|
57
|
+
facts: [
|
|
58
|
+
{ label: "Market", value: response.payload.sourceMarket.label ?? response.payload.sourceMarket.id },
|
|
59
|
+
{ label: "Pack", value: response.payload.slug ?? itemId },
|
|
60
|
+
{ label: "Version", value: response.payload.version },
|
|
61
|
+
{ label: "Path", value: outputPath }
|
|
62
|
+
],
|
|
63
|
+
report: { marketId: response.payload.sourceMarket.id, artifact: response.payload, outputPath }
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return { exitCode: 1, stderr: [`Unknown packs action: ${action}`] };
|
|
67
|
+
};
|
|
68
|
+
export {
|
|
69
|
+
handlePacks
|
|
70
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { guidedResult } from "./utils.js";
|
|
2
|
+
import { createMarketClientForInvocation } from "./market-utils.js";
|
|
3
|
+
const handleProjects = async (invocation, context) => {
|
|
4
|
+
const action = invocation.positionals[0] ?? "list";
|
|
5
|
+
const { profile, client } = createMarketClientForInvocation(invocation, context, { requireAuth: true });
|
|
6
|
+
if (action === "list") {
|
|
7
|
+
const teamId = typeof invocation.args.team === "string" ? invocation.args.team : null;
|
|
8
|
+
const response = await client.projects(teamId);
|
|
9
|
+
return guidedResult({
|
|
10
|
+
command: "projects",
|
|
11
|
+
summary: "Treeseed market projects",
|
|
12
|
+
sections: [{
|
|
13
|
+
title: "Projects",
|
|
14
|
+
lines: response.payload.map((project) => `${project.id} ${project.name ?? project.slug} team=${project.teamId}`)
|
|
15
|
+
}],
|
|
16
|
+
report: { marketId: profile.id, teamId, projects: response.payload }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (action === "access") {
|
|
20
|
+
const projectId = invocation.positionals[1];
|
|
21
|
+
if (!projectId) return { exitCode: 1, stderr: ["Usage: treeseed projects access <project-id>"] };
|
|
22
|
+
const response = await client.projectAccess(projectId);
|
|
23
|
+
return guidedResult({
|
|
24
|
+
command: "projects",
|
|
25
|
+
summary: "Treeseed market project access",
|
|
26
|
+
facts: [
|
|
27
|
+
{ label: "Project", value: response.payload.projectId },
|
|
28
|
+
{ label: "Staging admin", value: response.payload.team.summary.canAdminStaging },
|
|
29
|
+
{ label: "Production admin", value: response.payload.team.summary.canAdminProduction }
|
|
30
|
+
],
|
|
31
|
+
sections: [{
|
|
32
|
+
title: "Environments",
|
|
33
|
+
lines: response.payload.environments.map((entry) => `${entry.environment}: ${entry.role}`)
|
|
34
|
+
}],
|
|
35
|
+
report: { marketId: profile.id, access: response.payload }
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (action === "connect") {
|
|
39
|
+
return {
|
|
40
|
+
exitCode: 1,
|
|
41
|
+
stderr: ["Use treeseed config --connect-market --market-project-id <project-id> for project pairing."]
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return { exitCode: 1, stderr: [`Unknown projects action: ${action}`] };
|
|
45
|
+
};
|
|
46
|
+
export {
|
|
47
|
+
handleProjects
|
|
48
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { setActiveMarketProfile } from "@treeseed/sdk/market-client";
|
|
2
|
+
import { guidedResult } from "./utils.js";
|
|
3
|
+
import { createMarketClientForInvocation } from "./market-utils.js";
|
|
4
|
+
const handleTeams = async (invocation, context) => {
|
|
5
|
+
const action = invocation.positionals[0] ?? "list";
|
|
6
|
+
const { profile, client } = createMarketClientForInvocation(invocation, context, { requireAuth: true });
|
|
7
|
+
if (action === "list") {
|
|
8
|
+
const response = await client.teams();
|
|
9
|
+
return guidedResult({
|
|
10
|
+
command: "teams",
|
|
11
|
+
summary: "Treeseed market teams",
|
|
12
|
+
sections: [{
|
|
13
|
+
title: "Teams",
|
|
14
|
+
lines: response.payload.map((team) => `${team.id} ${team.displayName ?? team.name ?? team.slug}`)
|
|
15
|
+
}],
|
|
16
|
+
report: { marketId: profile.id, teams: response.payload }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (action === "use") {
|
|
20
|
+
const teamId = invocation.positionals[1];
|
|
21
|
+
if (!teamId) return { exitCode: 1, stderr: ["Usage: treeseed teams use <team-id>"] };
|
|
22
|
+
const state = setActiveMarketProfile(profile.id);
|
|
23
|
+
return guidedResult({
|
|
24
|
+
command: "teams",
|
|
25
|
+
summary: `Selected team "${teamId}" for market "${profile.id}".`,
|
|
26
|
+
report: { marketId: profile.id, teamId, registry: state }
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (action === "members") {
|
|
30
|
+
const teamId = typeof invocation.args.team === "string" ? invocation.args.team : invocation.positionals[1];
|
|
31
|
+
if (!teamId) return { exitCode: 1, stderr: ["Usage: treeseed teams members <team-id>"] };
|
|
32
|
+
const response = await client.teamMembers(teamId);
|
|
33
|
+
return guidedResult({
|
|
34
|
+
command: "teams",
|
|
35
|
+
summary: "Treeseed market team members",
|
|
36
|
+
sections: [{
|
|
37
|
+
title: "Members",
|
|
38
|
+
lines: response.payload.map((member) => `${member.userId} ${member.displayName ?? member.email ?? member.id} ${(member.roles ?? []).join(", ")}`)
|
|
39
|
+
}],
|
|
40
|
+
report: { marketId: profile.id, teamId, members: response.payload }
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return { exitCode: 1, stderr: [`Unknown teams action: ${action}`] };
|
|
44
|
+
};
|
|
45
|
+
export {
|
|
46
|
+
handleTeams
|
|
47
|
+
};
|
|
@@ -1,6 +1,69 @@
|
|
|
1
1
|
import { TreeseedOperationsSdk } from "@treeseed/sdk/operations";
|
|
2
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import {
|
|
5
|
+
listIntegratedMarketCatalog,
|
|
6
|
+
resolveIntegratedCatalogArtifactDownload,
|
|
7
|
+
verifyArtifactBytes
|
|
8
|
+
} from "@treeseed/sdk/market-client";
|
|
9
|
+
import { guidedResult } from "./utils.js";
|
|
10
|
+
import { marketAuthRoot, marketSelector } from "./market-utils.js";
|
|
2
11
|
const operations = new TreeseedOperationsSdk();
|
|
3
12
|
const handleTemplate = async (invocation, context) => {
|
|
13
|
+
if (invocation.positionals[0] === "search" || invocation.positionals[0] === "install" || typeof invocation.args.market === "string") {
|
|
14
|
+
const action = invocation.positionals[0] ?? "search";
|
|
15
|
+
const selector = marketSelector(invocation);
|
|
16
|
+
const authRoot = marketAuthRoot(context);
|
|
17
|
+
if (action === "search" || action === "list") {
|
|
18
|
+
const response = await listIntegratedMarketCatalog({
|
|
19
|
+
kind: "template",
|
|
20
|
+
selector,
|
|
21
|
+
authRoot,
|
|
22
|
+
userAgent: "treeseed-cli"
|
|
23
|
+
});
|
|
24
|
+
return guidedResult({
|
|
25
|
+
command: "template",
|
|
26
|
+
summary: selector ? "Treeseed market templates" : "Treeseed integrated market templates",
|
|
27
|
+
sections: [{
|
|
28
|
+
title: "Templates",
|
|
29
|
+
lines: response.payload.map((template) => `${template.id} ${template.title ?? template.displayName ?? template.slug} market=${template.sourceMarket.label ?? template.sourceMarket.id}`)
|
|
30
|
+
}],
|
|
31
|
+
report: { selector, templates: response.payload, errors: response.errors }
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (action === "install") {
|
|
35
|
+
const itemId = invocation.positionals[1];
|
|
36
|
+
const version = typeof invocation.args.version === "string" ? invocation.args.version : "1.0.0";
|
|
37
|
+
if (!itemId) return { exitCode: 1, stderr: ["Usage: treeseed template install <item-id> [--version <version>]"] };
|
|
38
|
+
const response = await resolveIntegratedCatalogArtifactDownload({
|
|
39
|
+
itemId,
|
|
40
|
+
version,
|
|
41
|
+
selector,
|
|
42
|
+
authRoot,
|
|
43
|
+
userAgent: "treeseed-cli"
|
|
44
|
+
});
|
|
45
|
+
const download = await fetch(response.payload.downloadUrl);
|
|
46
|
+
if (!download.ok) {
|
|
47
|
+
return { exitCode: 1, stderr: [`Artifact download failed with ${download.status}.`] };
|
|
48
|
+
}
|
|
49
|
+
const bytes = await verifyArtifactBytes(download, response.payload.sha256);
|
|
50
|
+
const outputDir = resolve(context.cwd, ".treeseed", "downloads");
|
|
51
|
+
mkdirSync(outputDir, { recursive: true });
|
|
52
|
+
const outputPath = resolve(outputDir, `template-${response.payload.slug ?? itemId}-${response.payload.version}.tar`.replace(/[^A-Za-z0-9._-]+/g, "-"));
|
|
53
|
+
writeFileSync(outputPath, bytes);
|
|
54
|
+
return guidedResult({
|
|
55
|
+
command: "template",
|
|
56
|
+
summary: "Downloaded template artifact.",
|
|
57
|
+
facts: [
|
|
58
|
+
{ label: "Market", value: response.payload.sourceMarket.label ?? response.payload.sourceMarket.id },
|
|
59
|
+
{ label: "Template", value: response.payload.slug ?? itemId },
|
|
60
|
+
{ label: "Version", value: response.payload.version },
|
|
61
|
+
{ label: "Path", value: outputPath }
|
|
62
|
+
],
|
|
63
|
+
report: { marketId: response.payload.sourceMarket.id, artifact: response.payload, outputPath }
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
4
67
|
const result = await operations.execute({
|
|
5
68
|
operationName: "template",
|
|
6
69
|
input: {
|
|
@@ -662,6 +662,7 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
662
662
|
["auth:login", command({
|
|
663
663
|
options: [
|
|
664
664
|
{ name: "host", flags: "--host <id>", description: "Override the configured remote host id for this login.", kind: "string" },
|
|
665
|
+
{ name: "market", flags: "--market <id-or-url>", description: "Limit catalog lookup to one configured market id or direct market API URL. Without this, search/install uses the integrated catalog from all configured catalog markets.", kind: "string" },
|
|
665
666
|
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
666
667
|
],
|
|
667
668
|
examples: ["treeseed auth:login"],
|
|
@@ -679,6 +680,7 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
679
680
|
["auth:logout", command({
|
|
680
681
|
options: [
|
|
681
682
|
{ name: "host", flags: "--host <id>", description: "Override the configured remote host id to clear.", kind: "string" },
|
|
683
|
+
{ name: "market", flags: "--market <id-or-url>", description: "Select a configured market id or direct market API URL.", kind: "string" },
|
|
682
684
|
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
683
685
|
],
|
|
684
686
|
examples: ["treeseed auth:logout"],
|
|
@@ -694,7 +696,11 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
694
696
|
handlerName: "auth:logout"
|
|
695
697
|
})],
|
|
696
698
|
["auth:whoami", command({
|
|
697
|
-
options: [
|
|
699
|
+
options: [
|
|
700
|
+
{ name: "market", flags: "--market <id-or-url>", description: "Select a configured market id or direct market API URL.", kind: "string" },
|
|
701
|
+
{ name: "allMarkets", flags: "--all-markets", description: "Show locally stored identities for all configured markets.", kind: "boolean" },
|
|
702
|
+
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
703
|
+
],
|
|
698
704
|
examples: ["treeseed auth:whoami"],
|
|
699
705
|
help: {
|
|
700
706
|
longSummary: ["Auth:whoami shows the currently active Treeseed API identity so you can verify which account and host context the CLI is using."],
|
|
@@ -790,10 +796,15 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
790
796
|
{ name: "action", description: "Template action: list, show, or validate.", required: false },
|
|
791
797
|
{ name: "id", description: "Template id for show or validate.", required: false }
|
|
792
798
|
],
|
|
799
|
+
options: [
|
|
800
|
+
{ name: "market", flags: "--market <id-or-url>", description: "Select a configured market id or direct market API URL.", kind: "string" },
|
|
801
|
+
{ name: "version", flags: "--version <version>", description: "Artifact version for market template install.", kind: "string" },
|
|
802
|
+
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
803
|
+
],
|
|
793
804
|
examples: ["treeseed template", "treeseed template list", "treeseed template show starter-basic", "treeseed template validate"],
|
|
794
805
|
help: {
|
|
795
806
|
longSummary: [
|
|
796
|
-
"Template exposes
|
|
807
|
+
"Template exposes local starter catalog actions and market-backed search/install actions. Market search/install uses an integrated catalog from central and configured specialized markets, with every result labeled by source market."
|
|
797
808
|
],
|
|
798
809
|
examples: [
|
|
799
810
|
example("treeseed template", "Default to the catalog list", "Show the available starters without specifying an action."),
|
|
@@ -1201,6 +1212,120 @@ const CLI_COMMAND_OVERLAYS = /* @__PURE__ */ new Map([
|
|
|
1201
1212
|
["starlight:patch", command({ examples: ["treeseed starlight:patch"], executionMode: "adapter" })]
|
|
1202
1213
|
]);
|
|
1203
1214
|
const CLI_ONLY_OPERATION_SPECS = [
|
|
1215
|
+
{
|
|
1216
|
+
id: "market.registry",
|
|
1217
|
+
name: "market",
|
|
1218
|
+
aliases: [],
|
|
1219
|
+
group: "Utilities",
|
|
1220
|
+
summary: "Manage configured Treeseed market API endpoints.",
|
|
1221
|
+
description: "List, add, select, remove, and inspect market API profiles stored in local machine configuration.",
|
|
1222
|
+
provider: "default",
|
|
1223
|
+
related: ["auth:login", "teams", "projects"],
|
|
1224
|
+
usage: "treeseed market [list|add|use|remove|status]",
|
|
1225
|
+
arguments: [{ name: "action", description: "Market action.", required: false }],
|
|
1226
|
+
options: [
|
|
1227
|
+
{ name: "market", flags: "--market <id-or-url>", description: "Select a configured market id or direct market API URL.", kind: "string" },
|
|
1228
|
+
{ name: "label", flags: "--label <label>", description: "Display label for market add.", kind: "string" },
|
|
1229
|
+
{ name: "kind", flags: "--kind <kind>", description: "Market kind for market add.", kind: "enum", values: ["central", "specialized"] },
|
|
1230
|
+
{ name: "team", flags: "--team <team-id>", description: "Team id for a specialized market profile.", kind: "string" },
|
|
1231
|
+
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
1232
|
+
],
|
|
1233
|
+
examples: ["treeseed market list", "treeseed market add enterprise https://market.example.com", "treeseed market use central"],
|
|
1234
|
+
help: {
|
|
1235
|
+
longSummary: ["Market manages local Treeseed market API profiles. It never serves market behavior itself; it only selects endpoints the SDK market client should call."],
|
|
1236
|
+
whenToUse: ["Use this when you need to add an enterprise market, switch back to central, or inspect which market endpoint CLI commands will target."],
|
|
1237
|
+
beforeYouRun: ["Decide whether you are managing the always-available central profile or a team-specific specialized market profile."],
|
|
1238
|
+
automationNotes: ["Use `--json` when scripts need the active market id, URL, and configured profiles."]
|
|
1239
|
+
},
|
|
1240
|
+
helpVisible: true,
|
|
1241
|
+
helpFeatured: false,
|
|
1242
|
+
executionMode: "handler",
|
|
1243
|
+
handlerName: "market"
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
id: "market.teams",
|
|
1247
|
+
name: "teams",
|
|
1248
|
+
aliases: [],
|
|
1249
|
+
group: "Utilities",
|
|
1250
|
+
summary: "Inspect teams from the selected market.",
|
|
1251
|
+
description: "List teams, select a team context, and inspect team membership through the market API client.",
|
|
1252
|
+
provider: "default",
|
|
1253
|
+
related: ["market", "auth:login", "projects"],
|
|
1254
|
+
usage: "treeseed teams [list|use|members]",
|
|
1255
|
+
arguments: [{ name: "action", description: "Teams action.", required: false }],
|
|
1256
|
+
options: [
|
|
1257
|
+
{ name: "market", flags: "--market <id-or-url>", description: "Select a configured market id or direct market API URL.", kind: "string" },
|
|
1258
|
+
{ name: "team", flags: "--team <team-id>", description: "Team id for member lookup.", kind: "string" },
|
|
1259
|
+
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
1260
|
+
],
|
|
1261
|
+
examples: ["treeseed teams list", "treeseed teams members team_123"],
|
|
1262
|
+
help: {
|
|
1263
|
+
longSummary: ["Teams reads team membership data from the selected market API using the SDK market client."],
|
|
1264
|
+
whenToUse: ["Use this after login to confirm team membership or inspect who belongs to a market-owned team."],
|
|
1265
|
+
beforeYouRun: ["Authenticate to the selected market with `treeseed auth:login --market <id>` before reading private team data."],
|
|
1266
|
+
automationNotes: ["Use `--json` for scripts that need stable team or member arrays."]
|
|
1267
|
+
},
|
|
1268
|
+
helpVisible: true,
|
|
1269
|
+
helpFeatured: false,
|
|
1270
|
+
executionMode: "handler",
|
|
1271
|
+
handlerName: "teams"
|
|
1272
|
+
},
|
|
1273
|
+
{
|
|
1274
|
+
id: "market.projects",
|
|
1275
|
+
name: "projects",
|
|
1276
|
+
aliases: [],
|
|
1277
|
+
group: "Utilities",
|
|
1278
|
+
summary: "Inspect projects and access controls from the selected market.",
|
|
1279
|
+
description: "List market projects and inspect staging/production access through the market API client.",
|
|
1280
|
+
provider: "default",
|
|
1281
|
+
related: ["market", "teams", "config"],
|
|
1282
|
+
usage: "treeseed projects [list|access|connect]",
|
|
1283
|
+
arguments: [{ name: "action", description: "Projects action.", required: false }],
|
|
1284
|
+
options: [
|
|
1285
|
+
{ name: "market", flags: "--market <id-or-url>", description: "Select a configured market id or direct market API URL.", kind: "string" },
|
|
1286
|
+
{ name: "team", flags: "--team <team-id>", description: "Limit project list to a team.", kind: "string" },
|
|
1287
|
+
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
1288
|
+
],
|
|
1289
|
+
examples: ["treeseed projects list", "treeseed projects access project_123"],
|
|
1290
|
+
help: {
|
|
1291
|
+
longSummary: ["Projects reads project and environment access data from the selected market API using the SDK market client."],
|
|
1292
|
+
whenToUse: ["Use this to confirm which market projects you can see and whether your account has staging or production admin access."],
|
|
1293
|
+
beforeYouRun: ["Authenticate to the market and know the project id when inspecting a single project access summary."],
|
|
1294
|
+
automationNotes: ["Use `--json` to capture project lists and access summaries for automation."]
|
|
1295
|
+
},
|
|
1296
|
+
helpVisible: true,
|
|
1297
|
+
helpFeatured: false,
|
|
1298
|
+
executionMode: "handler",
|
|
1299
|
+
handlerName: "projects"
|
|
1300
|
+
},
|
|
1301
|
+
{
|
|
1302
|
+
id: "market.packs",
|
|
1303
|
+
name: "packs",
|
|
1304
|
+
aliases: [],
|
|
1305
|
+
group: "Utilities",
|
|
1306
|
+
summary: "Search and download market knowledge packs.",
|
|
1307
|
+
description: "Search knowledge packs and download artifact versions through the integrated market catalog or a selected market API.",
|
|
1308
|
+
provider: "default",
|
|
1309
|
+
related: ["market", "template"],
|
|
1310
|
+
usage: "treeseed packs [search|install] [id]",
|
|
1311
|
+
arguments: [{ name: "action", description: "Packs action.", required: false }],
|
|
1312
|
+
options: [
|
|
1313
|
+
{ name: "market", flags: "--market <id-or-url>", description: "Limit catalog lookup to one configured market id or direct market API URL. Without this, search/install uses the integrated catalog from all configured catalog markets.", kind: "string" },
|
|
1314
|
+
{ name: "version", flags: "--version <version>", description: "Artifact version for install.", kind: "string" },
|
|
1315
|
+
{ name: "json", flags: "--json", description: "Emit machine-readable JSON instead of human-readable text.", kind: "boolean" }
|
|
1316
|
+
],
|
|
1317
|
+
examples: ["treeseed packs search", "treeseed packs install pack_123 --version 1.0.0"],
|
|
1318
|
+
help: {
|
|
1319
|
+
longSummary: ["Packs searches and downloads knowledge pack artifacts from the integrated catalog formed by central and configured specialized markets."],
|
|
1320
|
+
whenToUse: ["Use this when a project should install a market-published knowledge bundle rather than a local fixture."],
|
|
1321
|
+
beforeYouRun: ["Choose the market and artifact version; private packs require an authenticated market session."],
|
|
1322
|
+
automationNotes: ["Use `--json` to capture artifact metadata and the downloaded file path."]
|
|
1323
|
+
},
|
|
1324
|
+
helpVisible: true,
|
|
1325
|
+
helpFeatured: false,
|
|
1326
|
+
executionMode: "handler",
|
|
1327
|
+
handlerName: "packs"
|
|
1328
|
+
},
|
|
1204
1329
|
{
|
|
1205
1330
|
id: "agents.run",
|
|
1206
1331
|
name: "agents",
|
package/dist/cli/registry.d.ts
CHANGED
|
@@ -24,6 +24,10 @@ export declare const COMMAND_HANDLERS: {
|
|
|
24
24
|
readonly 'auth:login': import("./operations-types.js").TreeseedCommandHandler;
|
|
25
25
|
readonly 'auth:logout': import("./operations-types.js").TreeseedCommandHandler;
|
|
26
26
|
readonly 'auth:whoami': import("./operations-types.js").TreeseedCommandHandler;
|
|
27
|
+
readonly market: import("./operations-types.js").TreeseedCommandHandler;
|
|
28
|
+
readonly teams: import("./operations-types.js").TreeseedCommandHandler;
|
|
29
|
+
readonly projects: import("./operations-types.js").TreeseedCommandHandler;
|
|
30
|
+
readonly packs: import("./operations-types.js").TreeseedCommandHandler;
|
|
27
31
|
readonly 'secrets:status': import("./operations-types.js").TreeseedCommandHandler;
|
|
28
32
|
readonly 'secrets:unlock': import("./operations-types.js").TreeseedCommandHandler;
|
|
29
33
|
readonly 'secrets:lock': import("./operations-types.js").TreeseedCommandHandler;
|
package/dist/cli/registry.js
CHANGED
|
@@ -19,6 +19,10 @@ import { handleSync } from "./handlers/sync.js";
|
|
|
19
19
|
import { handleAuthLogin } from "./handlers/auth-login.js";
|
|
20
20
|
import { handleAuthLogout } from "./handlers/auth-logout.js";
|
|
21
21
|
import { handleAuthWhoAmI } from "./handlers/auth-whoami.js";
|
|
22
|
+
import { handleMarket } from "./handlers/market.js";
|
|
23
|
+
import { handleTeams } from "./handlers/teams.js";
|
|
24
|
+
import { handleProjects } from "./handlers/projects.js";
|
|
25
|
+
import { handlePacks } from "./handlers/packs.js";
|
|
22
26
|
import {
|
|
23
27
|
handleSecretsLock,
|
|
24
28
|
handleSecretsMigrateKey,
|
|
@@ -62,6 +66,10 @@ const COMMAND_HANDLERS = {
|
|
|
62
66
|
"auth:login": handleAuthLogin,
|
|
63
67
|
"auth:logout": handleAuthLogout,
|
|
64
68
|
"auth:whoami": handleAuthWhoAmI,
|
|
69
|
+
market: handleMarket,
|
|
70
|
+
teams: handleTeams,
|
|
71
|
+
projects: handleProjects,
|
|
72
|
+
packs: handlePacks,
|
|
65
73
|
"secrets:status": handleSecretsStatus,
|
|
66
74
|
"secrets:unlock": handleSecretsUnlock,
|
|
67
75
|
"secrets:lock": handleSecretsLock,
|
package/dist/cli/runtime.js
CHANGED
|
@@ -333,7 +333,19 @@ function formatProjectError(spec) {
|
|
|
333
333
|
].join("\n");
|
|
334
334
|
}
|
|
335
335
|
function commandNeedsProjectRoot(spec) {
|
|
336
|
-
return
|
|
336
|
+
return !(/* @__PURE__ */ new Set([
|
|
337
|
+
"init",
|
|
338
|
+
"export",
|
|
339
|
+
"install",
|
|
340
|
+
"auth:login",
|
|
341
|
+
"auth:logout",
|
|
342
|
+
"auth:whoami",
|
|
343
|
+
"market",
|
|
344
|
+
"teams",
|
|
345
|
+
"projects",
|
|
346
|
+
"packs",
|
|
347
|
+
"template"
|
|
348
|
+
])).has(spec.name);
|
|
337
349
|
}
|
|
338
350
|
function resolveTreeseedCommandCwd(spec, cwd) {
|
|
339
351
|
if (!commandNeedsProjectRoot(spec)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treeseed/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.26",
|
|
4
4
|
"description": "Operator-facing Treeseed CLI package.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"release:publish": "node ./scripts/run-ts.mjs ./scripts/publish-package.ts"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@treeseed/sdk": "0.6.
|
|
48
|
+
"@treeseed/sdk": "0.6.28",
|
|
49
49
|
"ink": "^7.0.0",
|
|
50
50
|
"react": "^19.2.5"
|
|
51
51
|
},
|