superlore-cli 0.2.0 → 0.3.1
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/config.d.ts +7 -3
- package/dist/config.js +5 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +510 -41
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -11,8 +11,12 @@
|
|
|
11
11
|
* imported from anywhere — including the browser or an edge runtime — without dragging in a
|
|
12
12
|
* validator. Keep it that way.
|
|
13
13
|
*/
|
|
14
|
-
/**
|
|
15
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The kinds of superlore KB. Drives defaults — the auth warning for company KBs, and an
|
|
16
|
+
* auth-ON-by-default, MCP-ON private posture for a `personal-kb` (a digital replica of how one
|
|
17
|
+
* person thinks, works, and writes).
|
|
18
|
+
*/
|
|
19
|
+
type SuperloreType = "company-kb" | "product-docs" | "personal-kb";
|
|
16
20
|
/** Supported SSO providers. Only Google ships today (Auth.js v5 + Google SSO). */
|
|
17
21
|
type SuperloreAuthProvider = "google";
|
|
18
22
|
/** The human gate. Optional and per-deploy — public by default. */
|
|
@@ -35,7 +39,7 @@ interface SuperloreMcpConfig {
|
|
|
35
39
|
interface SuperloreJson {
|
|
36
40
|
/** Human-facing KB name. */
|
|
37
41
|
name: string;
|
|
38
|
-
/** Whether this is a private company KB
|
|
42
|
+
/** Whether this is a private company KB, public product docs, or a private personal KB. */
|
|
39
43
|
type: SuperloreType;
|
|
40
44
|
/** Brand accent — any CSS colour. superlore derives the rest of the family (light + dark). */
|
|
41
45
|
accent?: string;
|
package/dist/config.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
2
|
var DEFAULT_MCP_PATH = "/api/mcp";
|
|
3
3
|
var SUPERLORE_JSON_FILENAME = "superlore.json";
|
|
4
|
-
var SUPERLORE_TYPES = [
|
|
4
|
+
var SUPERLORE_TYPES = [
|
|
5
|
+
"company-kb",
|
|
6
|
+
"product-docs",
|
|
7
|
+
"personal-kb"
|
|
8
|
+
];
|
|
5
9
|
function isRecord(value) {
|
|
6
10
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
11
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,8 +13,12 @@ import * as cac from 'cac';
|
|
|
13
13
|
* imported from anywhere — including the browser or an edge runtime — without dragging in a
|
|
14
14
|
* validator. Keep it that way.
|
|
15
15
|
*/
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The kinds of superlore KB. Drives defaults — the auth warning for company KBs, and an
|
|
18
|
+
* auth-ON-by-default, MCP-ON private posture for a `personal-kb` (a digital replica of how one
|
|
19
|
+
* person thinks, works, and writes).
|
|
20
|
+
*/
|
|
21
|
+
type SuperloreType = "company-kb" | "product-docs" | "personal-kb";
|
|
18
22
|
/** Supported SSO providers. Only Google ships today (Auth.js v5 + Google SSO). */
|
|
19
23
|
type SuperloreAuthProvider = "google";
|
|
20
24
|
/** The human gate. Optional and per-deploy — public by default. */
|
|
@@ -37,7 +41,7 @@ interface SuperloreMcpConfig {
|
|
|
37
41
|
interface SuperloreJson {
|
|
38
42
|
/** Human-facing KB name. */
|
|
39
43
|
name: string;
|
|
40
|
-
/** Whether this is a private company KB
|
|
44
|
+
/** Whether this is a private company KB, public product docs, or a private personal KB. */
|
|
41
45
|
type: SuperloreType;
|
|
42
46
|
/** Brand accent — any CSS colour. superlore derives the rest of the family (light + dark). */
|
|
43
47
|
accent?: string;
|
|
@@ -83,7 +87,7 @@ declare function serializeSuperloreJson(config: SuperloreJson): string;
|
|
|
83
87
|
declare function resolveMcpPath(config: SuperloreJson): string | undefined;
|
|
84
88
|
|
|
85
89
|
/** The CLI version, kept in sync with package.json at build time. */
|
|
86
|
-
declare const VERSION = "0.
|
|
90
|
+
declare const VERSION = "0.3.1";
|
|
87
91
|
/** Build the argument parser. Exported for tests; `run()` wires it to argv. */
|
|
88
92
|
declare function buildCli(argv?: readonly string[]): cac.CAC;
|
|
89
93
|
/** Parse argv and dispatch. Reports unknown commands and unexpected errors cleanly. */
|
package/dist/index.js
CHANGED
|
@@ -27,10 +27,10 @@ function banner() {
|
|
|
27
27
|
}
|
|
28
28
|
const seam = dim("\u258F");
|
|
29
29
|
const lines = [
|
|
30
|
-
` ${accent("\u2597\
|
|
31
|
-
` ${accent("\
|
|
32
|
-
` ${accent("\
|
|
33
|
-
` ${accent("\u259D\
|
|
30
|
+
` ${accent("\u2597\u2584")}${seam}${accentSoft("\u2584\u2596")}`,
|
|
31
|
+
` ${accent("\u2588\u2588")}${seam}${accentSoft("\u2588\u2588")} ${wordmark("superlore")}`,
|
|
32
|
+
` ${accent("\u2588\u2588")}${seam}${accentSoft("\u2588\u2588")} ${dim("the company knowledge base your agents run on")}`,
|
|
33
|
+
` ${accent("\u259D\u2580")}${seam}${accentSoft("\u2580\u2598")}`
|
|
34
34
|
];
|
|
35
35
|
process.stdout.write(`
|
|
36
36
|
${lines.join("\n")}
|
|
@@ -71,7 +71,11 @@ import { dirname, join, resolve } from "path";
|
|
|
71
71
|
// src/config.ts
|
|
72
72
|
var DEFAULT_MCP_PATH = "/api/mcp";
|
|
73
73
|
var SUPERLORE_JSON_FILENAME = "superlore.json";
|
|
74
|
-
var SUPERLORE_TYPES = [
|
|
74
|
+
var SUPERLORE_TYPES = [
|
|
75
|
+
"company-kb",
|
|
76
|
+
"product-docs",
|
|
77
|
+
"personal-kb"
|
|
78
|
+
];
|
|
75
79
|
function isRecord(value) {
|
|
76
80
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
77
81
|
}
|
|
@@ -209,14 +213,15 @@ function detectPackageManager(root) {
|
|
|
209
213
|
function isInstalled(root) {
|
|
210
214
|
return existsSync(join(root, "node_modules"));
|
|
211
215
|
}
|
|
212
|
-
function runScript(root, script, extraArgs = []) {
|
|
216
|
+
function runScript(root, script, extraArgs = [], env) {
|
|
213
217
|
const pm = detectPackageManager(root);
|
|
214
218
|
const args = ["run", script, ...extraArgs.length ? ["--", ...extraArgs] : []];
|
|
215
219
|
return new Promise((resolvePromise, reject) => {
|
|
216
220
|
const child = spawn(pm, args, {
|
|
217
221
|
cwd: root,
|
|
218
222
|
stdio: "inherit",
|
|
219
|
-
shell: process.platform === "win32"
|
|
223
|
+
shell: process.platform === "win32",
|
|
224
|
+
env: env ? { ...process.env, ...env } : process.env
|
|
220
225
|
});
|
|
221
226
|
child.on("error", reject);
|
|
222
227
|
child.on("close", (code) => resolvePromise(code ?? 0));
|
|
@@ -413,7 +418,9 @@ function report(result) {
|
|
|
413
418
|
log.success(`${bold(result.editor.label)} ${dim("\u2014 extension installed.")}`);
|
|
414
419
|
break;
|
|
415
420
|
case "already-installed":
|
|
416
|
-
log.info(
|
|
421
|
+
log.info(
|
|
422
|
+
`${accent("\u203A")} ${bold(result.editor.label)} ${dim("\u2014 already installed, up to date.")}`
|
|
423
|
+
);
|
|
417
424
|
break;
|
|
418
425
|
case "failed":
|
|
419
426
|
log.error(`${bold(result.editor.label)} ${dim("\u2014 install failed:")} ${result.error}`);
|
|
@@ -433,12 +440,15 @@ function printManualInstall() {
|
|
|
433
440
|
function printMcpNextStep() {
|
|
434
441
|
log.blank();
|
|
435
442
|
log.info(bold("Next: connect the MCP"));
|
|
443
|
+
log.info(` ${dim("superlore's docs + help, in your agent \u2014 always current:")}`);
|
|
436
444
|
log.info(
|
|
437
|
-
` ${
|
|
445
|
+
` ${cyan("claude mcp add --transport http -s user superlore-docs https://superlore.vercel.app/api/mcp")}`
|
|
438
446
|
);
|
|
447
|
+
log.blank();
|
|
439
448
|
log.info(
|
|
440
|
-
` ${dim("
|
|
449
|
+
` ${dim("And your own KB once it's live (or ask Claude")} ${cyan('"connect my superlore MCP"')}${dim("):")}`
|
|
441
450
|
);
|
|
451
|
+
log.info(` ${cyan("claude mcp add --transport http -s user my-kb <your-kb-url>/api/mcp")}`);
|
|
442
452
|
}
|
|
443
453
|
|
|
444
454
|
// src/commands/deploy.ts
|
|
@@ -514,8 +524,7 @@ async function devCommand(flags) {
|
|
|
514
524
|
);
|
|
515
525
|
}
|
|
516
526
|
log.blank();
|
|
517
|
-
const
|
|
518
|
-
const code = await runScript(project.root, "dev", args);
|
|
527
|
+
const code = await runScript(project.root, "dev", [], { PORT: String(port) });
|
|
519
528
|
process.exit(code);
|
|
520
529
|
}
|
|
521
530
|
|
|
@@ -568,6 +577,7 @@ function scaffold(options) {
|
|
|
568
577
|
function writeSkeleton(root, config) {
|
|
569
578
|
const accent2 = config.accent ?? SUPERLORE_VIOLET;
|
|
570
579
|
const mcpEnabled = config.mcp?.enabled ?? true;
|
|
580
|
+
const authEnabled = config.auth?.enabled ?? false;
|
|
571
581
|
const slug = config.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "superlore-kb";
|
|
572
582
|
const write = (rel, body) => {
|
|
573
583
|
const file = join3(root, rel);
|
|
@@ -592,9 +602,14 @@ function writeSkeleton(root, config) {
|
|
|
592
602
|
"fumadocs-core": "16.8.2",
|
|
593
603
|
"fumadocs-mdx": "14.3.1",
|
|
594
604
|
"fumadocs-ui": "16.8.2",
|
|
595
|
-
superlore: "^0.1
|
|
605
|
+
superlore: "^0.5.1",
|
|
596
606
|
"lucide-react": "^1.21.0",
|
|
607
|
+
// superlore peers the rendered components pull in: Mermaid (Diagram), themes.
|
|
608
|
+
mermaid: "^11.15.0",
|
|
597
609
|
...mcpEnabled ? { "@modelcontextprotocol/sdk": "^1.29.0", "mcp-handler": "^1.1.0" } : {},
|
|
610
|
+
// Auth.js v5 powers the optional Google SSO gate (superlore/auth). Self-disabling
|
|
611
|
+
// without AUTH_GOOGLE_ID, so it's harmless until the env is set.
|
|
612
|
+
...authEnabled ? { "next-auth": "^5.0.0-beta.25" } : {},
|
|
598
613
|
next: "16.2.4",
|
|
599
614
|
"next-themes": "^0.4.6",
|
|
600
615
|
react: "^19.2.5",
|
|
@@ -633,7 +648,7 @@ function writeSkeleton(root, config) {
|
|
|
633
648
|
isolatedModules: true,
|
|
634
649
|
skipLibCheck: true,
|
|
635
650
|
incremental: true,
|
|
636
|
-
paths: { "@/*": ["./*"] },
|
|
651
|
+
paths: { "@/*": ["./*"], "collections/*": ["./.source/*"] },
|
|
637
652
|
plugins: [{ name: "next" }]
|
|
638
653
|
},
|
|
639
654
|
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
@@ -653,8 +668,7 @@ const withMDX = createMDX();
|
|
|
653
668
|
/** @type {import('next').NextConfig} */
|
|
654
669
|
const config = {
|
|
655
670
|
reactStrictMode: true,
|
|
656
|
-
//
|
|
657
|
-
transpilePackages: ["superlore"],
|
|
671
|
+
// superlore ships compiled ESM \u2014 consume it as a normal package (no transpilePackages).
|
|
658
672
|
};
|
|
659
673
|
|
|
660
674
|
export default withMDX(config);
|
|
@@ -698,7 +712,7 @@ export default config;
|
|
|
698
712
|
write(
|
|
699
713
|
"app/layout.tsx",
|
|
700
714
|
`import type { ReactNode } from "react";
|
|
701
|
-
import { RootProvider } from "
|
|
715
|
+
import { RootProvider } from "superlore/ui";
|
|
702
716
|
import "./global.css";
|
|
703
717
|
|
|
704
718
|
export default function RootLayout({ children }: { children: ReactNode }) {
|
|
@@ -772,18 +786,22 @@ export function generateStaticParams() {
|
|
|
772
786
|
);
|
|
773
787
|
write(
|
|
774
788
|
"lib/source.ts",
|
|
775
|
-
`import {
|
|
776
|
-
import {
|
|
789
|
+
`import { docs } from "collections/server";
|
|
790
|
+
import { loader, lucideIconsPlugin } from "superlore/source";
|
|
777
791
|
|
|
778
792
|
export const source = loader({
|
|
779
793
|
baseUrl: "/docs",
|
|
780
794
|
source: docs.toFumadocsSource(),
|
|
795
|
+
plugins: [lucideIconsPlugin()],
|
|
781
796
|
});
|
|
782
797
|
`
|
|
783
798
|
);
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
799
|
+
if (config.type === "personal-kb") {
|
|
800
|
+
writePersonalContent(write, config);
|
|
801
|
+
} else {
|
|
802
|
+
write(
|
|
803
|
+
"content/docs/index.mdx",
|
|
804
|
+
`---
|
|
787
805
|
title: Welcome
|
|
788
806
|
description: The home of your superlore knowledge base.
|
|
789
807
|
summary: Landing page for the ${config.name} knowledge base.
|
|
@@ -797,7 +815,11 @@ agents read the same structured content over MCP.
|
|
|
797
815
|
|
|
798
816
|
Edit \`content/docs/index.mdx\` to make it yours, then run \`superlore dev\`.
|
|
799
817
|
`
|
|
800
|
-
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
if (authEnabled) {
|
|
821
|
+
writeAuth(write, config);
|
|
822
|
+
}
|
|
801
823
|
if (mcpEnabled) {
|
|
802
824
|
const mcpPath = config.mcp?.path ?? "/api/mcp";
|
|
803
825
|
write(
|
|
@@ -805,10 +827,14 @@ Edit \`content/docs/index.mdx\` to make it yours, then run \`superlore dev\`.
|
|
|
805
827
|
`import { createMcpHandler } from "mcp-handler";
|
|
806
828
|
import { z } from "zod";
|
|
807
829
|
import { getComponentData, getPage, list, navigate, search } from "superlore/mcp";
|
|
830
|
+
import { buildIndexFromSource } from "superlore/source";
|
|
831
|
+
import type { KKind } from "superlore";
|
|
832
|
+
import { source } from "@/lib/source";
|
|
808
833
|
|
|
809
834
|
// Your KB's MCP endpoint. Served at ${mcpPath} \u2014 the same structured content the site renders,
|
|
810
|
-
// exposed to agents.
|
|
811
|
-
//
|
|
835
|
+
// exposed to agents. The index is built straight from your content \`source\`: author once, and
|
|
836
|
+
// humans read the pages while agents query this corpus. No scraping, no drift.
|
|
837
|
+
const index = buildIndexFromSource(source);
|
|
812
838
|
|
|
813
839
|
const json = (data: unknown) => ({
|
|
814
840
|
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
|
|
@@ -820,31 +846,32 @@ const handler = createMcpHandler(
|
|
|
820
846
|
"search",
|
|
821
847
|
"Full-text search across the knowledge base.",
|
|
822
848
|
{ query: z.string(), limit: z.number().int().positive().optional() },
|
|
823
|
-
async ({ query, limit }) => json(search(
|
|
849
|
+
async ({ query, limit }) => json(search(index, query, limit)),
|
|
824
850
|
);
|
|
825
851
|
server.tool(
|
|
826
852
|
"get_page",
|
|
827
853
|
"Get a page's full structured content by path.",
|
|
828
854
|
{ path: z.string() },
|
|
829
|
-
async ({ path }) => json(getPage(
|
|
855
|
+
async ({ path }) => json(getPage(index, path)),
|
|
830
856
|
);
|
|
831
857
|
server.tool(
|
|
832
858
|
"list",
|
|
833
859
|
"List knowledge nodes, filtered by kind / tag / entityType.",
|
|
834
860
|
{ kind: z.string().optional(), tag: z.string().optional(), entityType: z.string().optional() },
|
|
835
|
-
async (
|
|
861
|
+
async ({ kind, tag, entityType }) =>
|
|
862
|
+
json(list(index, { kind: kind as KKind | undefined, tag, entityType })),
|
|
836
863
|
);
|
|
837
864
|
server.tool(
|
|
838
865
|
"navigate",
|
|
839
866
|
"Follow relations from a page path / node id / entity ref.",
|
|
840
867
|
{ target: z.string() },
|
|
841
|
-
async ({ target }) => json(navigate(
|
|
868
|
+
async ({ target }) => json(navigate(index, target)),
|
|
842
869
|
);
|
|
843
870
|
server.tool(
|
|
844
871
|
"get_component_data",
|
|
845
872
|
"Get the structured data behind a rendered component (its knowledge face).",
|
|
846
873
|
{ id: z.string() },
|
|
847
|
-
async ({ id }) => json(getComponentData(
|
|
874
|
+
async ({ id }) => json(getComponentData(index, id)),
|
|
848
875
|
);
|
|
849
876
|
},
|
|
850
877
|
{},
|
|
@@ -865,6 +892,27 @@ out
|
|
|
865
892
|
.env*.local
|
|
866
893
|
`
|
|
867
894
|
);
|
|
895
|
+
if (authEnabled) {
|
|
896
|
+
write(
|
|
897
|
+
".env.example",
|
|
898
|
+
`# Auth.js v5 + Google SSO. The gate is OFF until AUTH_GOOGLE_ID is set, so local dev works with
|
|
899
|
+
# this file empty. Copy to .env.local and fill in to enable it on a deploy.
|
|
900
|
+
AUTH_SECRET= # \`openssl rand -base64 32\`
|
|
901
|
+
AUTH_GOOGLE_ID= # presence of this turns the gate ON
|
|
902
|
+
AUTH_GOOGLE_SECRET=
|
|
903
|
+
AUTH_URL= # the deploy's canonical URL, e.g. https://your-kb.vercel.app
|
|
904
|
+
AUTH_TRUST_HOST=true
|
|
905
|
+
${config.auth?.allowedDomain ? `AUTH_ALLOWED_DOMAIN=${config.auth.allowedDomain}` : "# AUTH_ALLOWED_DOMAIN=example.com # restrict sign-in to one workspace domain (optional)"}
|
|
906
|
+
# AUTH_ALLOWED_EMAILS=you@example.com # comma-separated allowlist that bypasses the domain check
|
|
907
|
+
# LOCAL=true # force the gate OFF locally even when configured
|
|
908
|
+
`
|
|
909
|
+
);
|
|
910
|
+
}
|
|
911
|
+
const authReadme = authEnabled ? `
|
|
912
|
+
|
|
913
|
+
## Auth
|
|
914
|
+
|
|
915
|
+
This KB ships a Google SSO gate (Auth.js v5). It is **off until you set \`AUTH_GOOGLE_ID\`**, so local dev runs open. Copy \`.env.example\` to \`.env.local\` and fill it in to enable it. The gate lives in \`proxy.ts\`, in front of every route \u2014 so the MCP inherits it too.` : "";
|
|
868
916
|
write(
|
|
869
917
|
"README.md",
|
|
870
918
|
`# ${config.name}
|
|
@@ -886,7 +934,417 @@ superlore build
|
|
|
886
934
|
|
|
887
935
|
Config lives in \`superlore.json\`. Author content in \`content/docs/\`.${mcpEnabled ? `
|
|
888
936
|
|
|
889
|
-
The MCP endpoint is served at \`${config.mcp?.path ?? "/api/mcp"}\`.` : ""}
|
|
937
|
+
The MCP endpoint is served at \`${config.mcp?.path ?? "/api/mcp"}\`.` : ""}${authReadme}
|
|
938
|
+
`
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
function writeAuth(write, config) {
|
|
942
|
+
const allowedDomain = config.auth?.allowedDomain;
|
|
943
|
+
write(
|
|
944
|
+
"auth.ts",
|
|
945
|
+
`import { createSuperloreAuth } from "superlore/auth";
|
|
946
|
+
|
|
947
|
+
// Auth.js v5 + Google SSO. Allowlists can come from env (AUTH_ALLOWED_DOMAIN / AUTH_ALLOWED_EMAILS)
|
|
948
|
+
// or be passed explicitly here. Off until AUTH_GOOGLE_ID is set, so local dev needs no config.
|
|
949
|
+
export const { handlers, auth, signIn, signOut } = createSuperloreAuth(${allowedDomain ? `{
|
|
950
|
+
allowedDomain: ${JSON.stringify(allowedDomain)},
|
|
951
|
+
}` : "{}"});
|
|
952
|
+
`
|
|
953
|
+
);
|
|
954
|
+
write(
|
|
955
|
+
"app/api/auth/[...nextauth]/route.ts",
|
|
956
|
+
`import { handlers } from "@/auth";
|
|
957
|
+
|
|
958
|
+
export const { GET, POST } = handlers;
|
|
959
|
+
`
|
|
960
|
+
);
|
|
961
|
+
write(
|
|
962
|
+
"proxy.ts",
|
|
963
|
+
`import { auth } from "@/auth";
|
|
964
|
+
import { createAuthProxy } from "superlore/auth";
|
|
965
|
+
|
|
966
|
+
// Next.js 16 middleware lives in proxy.ts. The gate is self-disabling: with no AUTH_GOOGLE_ID
|
|
967
|
+
// (or LOCAL=true) every request passes through, so local dev and public deploys stay open.
|
|
968
|
+
export default createAuthProxy(auth);
|
|
969
|
+
|
|
970
|
+
export const config = {
|
|
971
|
+
// Run on everything except static assets (the helper also skips the auth dance + icons).
|
|
972
|
+
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
|
|
973
|
+
};
|
|
974
|
+
`
|
|
975
|
+
);
|
|
976
|
+
write(
|
|
977
|
+
"app/auth/signin/page.tsx",
|
|
978
|
+
`import { signIn } from "@/auth";
|
|
979
|
+
|
|
980
|
+
export default async function SignInPage(props: {
|
|
981
|
+
searchParams: Promise<{ callbackUrl?: string }>;
|
|
982
|
+
}) {
|
|
983
|
+
const { callbackUrl } = await props.searchParams;
|
|
984
|
+
return (
|
|
985
|
+
<main className="grid min-h-screen place-items-center p-6">
|
|
986
|
+
<form
|
|
987
|
+
action={async () => {
|
|
988
|
+
"use server";
|
|
989
|
+
await signIn("google", { redirectTo: callbackUrl ?? "/" });
|
|
990
|
+
}}
|
|
991
|
+
className="w-full max-w-sm rounded-lg border border-fd-border bg-fd-card p-6 text-center"
|
|
992
|
+
>
|
|
993
|
+
<h1 className="text-lg font-semibold text-fd-foreground">Sign in</h1>
|
|
994
|
+
<p className="mt-1 text-sm text-fd-muted-foreground">
|
|
995
|
+
This knowledge base is private. Continue with Google to read it.
|
|
996
|
+
</p>
|
|
997
|
+
<button
|
|
998
|
+
type="submit"
|
|
999
|
+
className="mt-5 inline-flex w-full items-center justify-center rounded-md border border-kp-accent-border bg-kp-accent px-4 py-2 text-sm font-medium text-white"
|
|
1000
|
+
>
|
|
1001
|
+
Continue with Google
|
|
1002
|
+
</button>
|
|
1003
|
+
</form>
|
|
1004
|
+
</main>
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
`
|
|
1008
|
+
);
|
|
1009
|
+
write(
|
|
1010
|
+
"app/auth/error/page.tsx",
|
|
1011
|
+
`export default async function AuthErrorPage(props: {
|
|
1012
|
+
searchParams: Promise<{ error?: string }>;
|
|
1013
|
+
}) {
|
|
1014
|
+
const { error } = await props.searchParams;
|
|
1015
|
+
return (
|
|
1016
|
+
<main className="grid min-h-screen place-items-center p-6">
|
|
1017
|
+
<div className="w-full max-w-sm rounded-lg border border-fd-border bg-fd-card p-6 text-center">
|
|
1018
|
+
<h1 className="text-lg font-semibold text-fd-foreground">Can't sign in</h1>
|
|
1019
|
+
<p className="mt-1 text-sm text-fd-muted-foreground">
|
|
1020
|
+
{error === "AccessDenied"
|
|
1021
|
+
? "That account isn't allowed to access this knowledge base."
|
|
1022
|
+
: "Something went wrong signing in. Try again."}
|
|
1023
|
+
</p>
|
|
1024
|
+
<a
|
|
1025
|
+
href="/auth/signin"
|
|
1026
|
+
className="mt-5 inline-flex w-full items-center justify-center rounded-md border border-fd-border px-4 py-2 text-sm font-medium text-fd-foreground no-underline"
|
|
1027
|
+
>
|
|
1028
|
+
Back to sign in
|
|
1029
|
+
</a>
|
|
1030
|
+
</div>
|
|
1031
|
+
</main>
|
|
1032
|
+
);
|
|
1033
|
+
}
|
|
1034
|
+
`
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
function writePersonalContent(write, config) {
|
|
1038
|
+
write(
|
|
1039
|
+
"content/docs/meta.json",
|
|
1040
|
+
`${JSON.stringify(
|
|
1041
|
+
{
|
|
1042
|
+
title: config.name,
|
|
1043
|
+
root: true,
|
|
1044
|
+
pages: ["index", "beliefs", "working-style", "pr-comments", "voice", "stories"]
|
|
1045
|
+
},
|
|
1046
|
+
null,
|
|
1047
|
+
2
|
|
1048
|
+
)}
|
|
1049
|
+
`
|
|
1050
|
+
);
|
|
1051
|
+
write(
|
|
1052
|
+
"content/docs/index.mdx",
|
|
1053
|
+
`---
|
|
1054
|
+
title: About me
|
|
1055
|
+
description: Who I am, what I care about, and how to work with me.
|
|
1056
|
+
summary: Overview of this person \u2014 role, focus, what they optimize for, and how an agent should use this KB to act on their behalf.
|
|
1057
|
+
tags: [overview, about, profile]
|
|
1058
|
+
---
|
|
1059
|
+
|
|
1060
|
+
<PageHero
|
|
1061
|
+
kicker="Personal KB"
|
|
1062
|
+
title="About me"
|
|
1063
|
+
description="A private, queryable replica of how I think, work, and write. Humans read this; my agents read the same content over MCP and act the way I would."
|
|
1064
|
+
/>
|
|
1065
|
+
|
|
1066
|
+
I'm a placeholder. Replace this with a short, honest description of who you are \u2014 your role, what
|
|
1067
|
+
you build, and the through-line in your work. Keep it concrete: an agent should be able to read
|
|
1068
|
+
this and understand what you'd care about in a decision.
|
|
1069
|
+
|
|
1070
|
+
<KeyFacts
|
|
1071
|
+
items={[
|
|
1072
|
+
{ label: "Role", value: "What you do, in five words or fewer" },
|
|
1073
|
+
{ label: "Focus", value: "The problem you spend most days on" },
|
|
1074
|
+
{ label: "Optimizes for", value: "Speed, correctness, clarity \u2014 pick yours" },
|
|
1075
|
+
{ label: "Time zone", value: "UTC+0" },
|
|
1076
|
+
{ label: "Best reached", value: "Async, in writing" },
|
|
1077
|
+
{ label: "Decides by", value: "Evidence over opinion" },
|
|
1078
|
+
]}
|
|
1079
|
+
/>
|
|
1080
|
+
|
|
1081
|
+
<EntityCard
|
|
1082
|
+
type="person"
|
|
1083
|
+
slug="me"
|
|
1084
|
+
title="Your Name"
|
|
1085
|
+
summary="One line that captures how you'd want an agent to introduce you."
|
|
1086
|
+
icon="user"
|
|
1087
|
+
fields={[
|
|
1088
|
+
{ key: "Discipline", value: "Engineering" },
|
|
1089
|
+
{ key: "Superpower", value: "Turning ambiguity into a plan" },
|
|
1090
|
+
{ key: "Allergic to", value: "Meetings that should have been a doc" },
|
|
1091
|
+
]}
|
|
1092
|
+
refs={[
|
|
1093
|
+
{ rel: "see", target: "/docs/working-style", label: "How I work" },
|
|
1094
|
+
{ rel: "see", target: "/docs/voice", label: "How I write" },
|
|
1095
|
+
]}
|
|
1096
|
+
/>
|
|
1097
|
+
|
|
1098
|
+
## How to use this KB
|
|
1099
|
+
|
|
1100
|
+
Ask it how I'd think about something before you ask me. The pages below are the source of truth
|
|
1101
|
+
for my beliefs, working style, review bar, voice, and the stories that shaped them.
|
|
1102
|
+
`
|
|
1103
|
+
);
|
|
1104
|
+
write(
|
|
1105
|
+
"content/docs/beliefs.mdx",
|
|
1106
|
+
`---
|
|
1107
|
+
title: Beliefs & takes
|
|
1108
|
+
description: The positions I hold and the principles I keep coming back to.
|
|
1109
|
+
summary: This person's strongly-held beliefs and operating principles, each phrased as a position an agent can apply when reasoning on their behalf.
|
|
1110
|
+
tags: [beliefs, principles, takes]
|
|
1111
|
+
---
|
|
1112
|
+
|
|
1113
|
+
<SectionHead
|
|
1114
|
+
eyebrow="What I believe"
|
|
1115
|
+
title="Beliefs & takes"
|
|
1116
|
+
description="Strongly held, loosely coupled. Each is a position you can act on, not a vibe."
|
|
1117
|
+
/>
|
|
1118
|
+
|
|
1119
|
+
These are placeholders \u2014 rewrite them as your own. Phrase each as a clear position so an agent can
|
|
1120
|
+
reason from it.
|
|
1121
|
+
|
|
1122
|
+
<KeyFacts
|
|
1123
|
+
items={[
|
|
1124
|
+
{ label: "On shipping", value: "Small and reversible beats big and perfect." },
|
|
1125
|
+
{ label: "On code", value: "Delete more than you add." },
|
|
1126
|
+
{ label: "On process", value: "Process is scar tissue \u2014 keep only what earned its place." },
|
|
1127
|
+
{ label: "On disagreement", value: "Disagree in the doc, commit in the room." },
|
|
1128
|
+
{ label: "On estimates", value: "Confidence intervals, not single numbers." },
|
|
1129
|
+
{ label: "On tools", value: "Boring tech for load-bearing things." },
|
|
1130
|
+
]}
|
|
1131
|
+
/>
|
|
1132
|
+
|
|
1133
|
+
## A take I'll defend
|
|
1134
|
+
|
|
1135
|
+
<Decision
|
|
1136
|
+
title="Prefer clarity over cleverness"
|
|
1137
|
+
status="accepted"
|
|
1138
|
+
identifier="TAKE-01"
|
|
1139
|
+
context={<>Clever code feels good to write and is expensive to read. Most code is read far more than it is written.</>}
|
|
1140
|
+
decision={<>Optimize for the next person (often future me). If a reviewer has to ask what it does, it isn't done.</>}
|
|
1141
|
+
consequences={[
|
|
1142
|
+
"Fewer abstractions until they pay rent.",
|
|
1143
|
+
"Comments explain why, names explain what.",
|
|
1144
|
+
"I'll trade a few keystrokes for a faster read every time.",
|
|
1145
|
+
]}
|
|
1146
|
+
/>
|
|
1147
|
+
`
|
|
1148
|
+
);
|
|
1149
|
+
write(
|
|
1150
|
+
"content/docs/working-style.mdx",
|
|
1151
|
+
`---
|
|
1152
|
+
title: Working style
|
|
1153
|
+
description: How I plan, decide, focus, and collaborate.
|
|
1154
|
+
summary: How this person works day to day \u2014 how they plan, make decisions, manage focus, and collaborate. Use this to predict how they'd approach a task.
|
|
1155
|
+
tags: [working-style, how-to, collaboration]
|
|
1156
|
+
---
|
|
1157
|
+
|
|
1158
|
+
<SectionHead
|
|
1159
|
+
eyebrow="How I work"
|
|
1160
|
+
title="Working style"
|
|
1161
|
+
description="If you handed me a task, this is the shape of what I'd do with it."
|
|
1162
|
+
/>
|
|
1163
|
+
|
|
1164
|
+
Placeholder content \u2014 make it yours. Be specific enough that an agent could run a task the way you
|
|
1165
|
+
would.
|
|
1166
|
+
|
|
1167
|
+
<FeatureList
|
|
1168
|
+
items={[
|
|
1169
|
+
{ icon: "target", title: "Start from the outcome", description: "I write the goal and the done-condition before touching the work." },
|
|
1170
|
+
{ icon: "split", title: "Decompose, then sequence", description: "Break into reversible steps; do the riskiest cheap thing first." },
|
|
1171
|
+
{ icon: "message-square", title: "Default to writing", description: "A short doc beats a meeting. Decisions live in text, not memory." },
|
|
1172
|
+
{ icon: "gauge", title: "Protect deep work", description: "Mornings are for the hard thing. Coordination batches in the afternoon." },
|
|
1173
|
+
]}
|
|
1174
|
+
/>
|
|
1175
|
+
|
|
1176
|
+
## How I decide
|
|
1177
|
+
|
|
1178
|
+
<Decision
|
|
1179
|
+
title="Two-way doors don't need a meeting"
|
|
1180
|
+
status="accepted"
|
|
1181
|
+
identifier="STYLE-01"
|
|
1182
|
+
context={<>Many decisions are easily reversible. Treating them as if they aren't is the real cost.</>}
|
|
1183
|
+
decision={<>For reversible calls, I pick quickly and move; for one-way doors, I slow down and write the trade-offs out.</>}
|
|
1184
|
+
consequences={[
|
|
1185
|
+
"Speed on the 80% that's reversible.",
|
|
1186
|
+
"Care on the 20% that isn't.",
|
|
1187
|
+
]}
|
|
1188
|
+
/>
|
|
1189
|
+
|
|
1190
|
+
## A day, roughly
|
|
1191
|
+
|
|
1192
|
+
<Schedule
|
|
1193
|
+
label="Typical working day"
|
|
1194
|
+
events={[
|
|
1195
|
+
{ date: "Weekday", time: "09:00", title: "Deep work", body: "The hardest task of the day, no notifications." },
|
|
1196
|
+
{ date: "Weekday", time: "12:30", title: "Reviews & async", body: "PRs, comments, written replies." },
|
|
1197
|
+
{ date: "Weekday", time: "15:00", title: "Collaboration", body: "Pairing, calls, unblock others." },
|
|
1198
|
+
{ date: "Weekday", time: "17:00", title: "Wind-down", body: "Plan tomorrow's first task." },
|
|
1199
|
+
]}
|
|
1200
|
+
/>
|
|
1201
|
+
`
|
|
1202
|
+
);
|
|
1203
|
+
write(
|
|
1204
|
+
"content/docs/pr-comments.mdx",
|
|
1205
|
+
`---
|
|
1206
|
+
title: How I give PR comments
|
|
1207
|
+
description: My review bar, the tone I use, and concrete examples of comments I leave.
|
|
1208
|
+
summary: How this person reviews code \u2014 what they block on versus nudge, the tone of their comments, and worked examples an agent can imitate when reviewing on their behalf.
|
|
1209
|
+
tags: [code-review, feedback, how-to]
|
|
1210
|
+
---
|
|
1211
|
+
|
|
1212
|
+
<SectionHead
|
|
1213
|
+
eyebrow="Code review"
|
|
1214
|
+
title="How I give PR comments"
|
|
1215
|
+
description="What I block on, what I just nudge, and how I phrase it. Replace with your own."
|
|
1216
|
+
/>
|
|
1217
|
+
|
|
1218
|
+
## My review bar
|
|
1219
|
+
|
|
1220
|
+
<Checklist
|
|
1221
|
+
label="What I look for, in order"
|
|
1222
|
+
items={[
|
|
1223
|
+
{ text: "Correctness \u2014 does it do the thing, including the edge cases?", group: "Block on" },
|
|
1224
|
+
{ text: "Tests that would fail without the change", group: "Block on" },
|
|
1225
|
+
{ text: "Names and structure I can read in one pass", group: "Block on" },
|
|
1226
|
+
{ text: "Unnecessary abstraction or dead code", group: "Nudge on" },
|
|
1227
|
+
{ text: "Comments that explain why, not what", group: "Nudge on" },
|
|
1228
|
+
{ text: "Nits \u2014 formatting, ordering, taste", group: "Optional" },
|
|
1229
|
+
]}
|
|
1230
|
+
/>
|
|
1231
|
+
|
|
1232
|
+
## How I phrase comments
|
|
1233
|
+
|
|
1234
|
+
I prefix to signal weight: **blocking:** must change, **suggestion:** take it or leave it,
|
|
1235
|
+
**nit:** ignore freely, **question:** I genuinely don't know. Examples:
|
|
1236
|
+
|
|
1237
|
+
<Example title="A blocking comment">
|
|
1238
|
+
**blocking:** This drops the error on the floor \u2014 if the fetch fails we return \`undefined\` and
|
|
1239
|
+
the caller renders an empty state as if it were success. Surface it, or handle it explicitly.
|
|
1240
|
+
</Example>
|
|
1241
|
+
|
|
1242
|
+
<Example title="A suggestion">
|
|
1243
|
+
**suggestion:** This loop reads cleanly, but \`items.flatMap\` would say the same thing in one line.
|
|
1244
|
+
Your call \u2014 not blocking.
|
|
1245
|
+
</Example>
|
|
1246
|
+
|
|
1247
|
+
<Example title="A nit">
|
|
1248
|
+
**nit:** tiny \u2014 can we name this \`pendingCount\` so it matches the others? Ignore if you disagree.
|
|
1249
|
+
</Example>
|
|
1250
|
+
|
|
1251
|
+
<Tip title="Tone">
|
|
1252
|
+
Critique the code, never the author. Lead with the why. If I'd want it softened when it lands on
|
|
1253
|
+
my own PR, I soften it.
|
|
1254
|
+
</Tip>
|
|
1255
|
+
`
|
|
1256
|
+
);
|
|
1257
|
+
write(
|
|
1258
|
+
"content/docs/voice.mdx",
|
|
1259
|
+
`---
|
|
1260
|
+
title: Voice & writing
|
|
1261
|
+
description: How I sound in writing \u2014 tone, defaults, and what I avoid.
|
|
1262
|
+
summary: This person's writing voice \u2014 tone, structure defaults, and explicit do/don't rules an agent should follow when drafting in their name.
|
|
1263
|
+
tags: [voice, writing, style]
|
|
1264
|
+
---
|
|
1265
|
+
|
|
1266
|
+
<SectionHead
|
|
1267
|
+
eyebrow="How I write"
|
|
1268
|
+
title="Voice & writing"
|
|
1269
|
+
description="So an agent drafting in my name sounds like me, not like a template."
|
|
1270
|
+
/>
|
|
1271
|
+
|
|
1272
|
+
Placeholder \u2014 capture your actual voice. The more specific the do/don't list, the better an agent
|
|
1273
|
+
can match you.
|
|
1274
|
+
|
|
1275
|
+
<KeyFacts
|
|
1276
|
+
items={[
|
|
1277
|
+
{ label: "Tone", value: "Direct, warm, low ceremony" },
|
|
1278
|
+
{ label: "Sentence length", value: "Short. Then one longer one to breathe." },
|
|
1279
|
+
{ label: "Person", value: "First person, active voice" },
|
|
1280
|
+
{ label: "Jargon", value: "Only when it's the precise word" },
|
|
1281
|
+
]}
|
|
1282
|
+
/>
|
|
1283
|
+
|
|
1284
|
+
## Do / don't
|
|
1285
|
+
|
|
1286
|
+
<Comparison
|
|
1287
|
+
caption="My writing defaults"
|
|
1288
|
+
options={["Do", "Don't"]}
|
|
1289
|
+
rows={[
|
|
1290
|
+
{ criterion: "Openers", cells: ["Get to the point in the first line", "Open with filler pleasantries"] },
|
|
1291
|
+
{ criterion: "Hedging", cells: ["Say what I think", "It might possibly be worth considering"] },
|
|
1292
|
+
{ criterion: "Structure", cells: ["Lead with the answer, then the why", "Bury the ask at the end"] },
|
|
1293
|
+
{ criterion: "Emoji", cells: ["Rarely, and never in serious writing", "Decorate every line"] },
|
|
1294
|
+
]}
|
|
1295
|
+
/>
|
|
1296
|
+
|
|
1297
|
+
<Example title="A message in my voice">
|
|
1298
|
+
Shipping the import fix today. It was dropping rows when a column was empty \u2014 now we skip the row
|
|
1299
|
+
and log it. One follow-up: we should validate on upload so this can't happen again. Want me to take
|
|
1300
|
+
that next?
|
|
1301
|
+
</Example>
|
|
1302
|
+
`
|
|
1303
|
+
);
|
|
1304
|
+
write(
|
|
1305
|
+
"content/docs/stories.mdx",
|
|
1306
|
+
`---
|
|
1307
|
+
title: Stories
|
|
1308
|
+
description: Formative moments that explain how I got my defaults.
|
|
1309
|
+
summary: Formative experiences that shaped this person's beliefs and working style, as a dated timeline an agent can reference for context on why they think the way they do.
|
|
1310
|
+
tags: [stories, background, timeline]
|
|
1311
|
+
---
|
|
1312
|
+
|
|
1313
|
+
<SectionHead
|
|
1314
|
+
eyebrow="Where it comes from"
|
|
1315
|
+
title="Stories"
|
|
1316
|
+
description="The moments behind the takes. Replace these with your own \u2014 dates can be approximate."
|
|
1317
|
+
/>
|
|
1318
|
+
|
|
1319
|
+
An agent that knows *why* you believe something reasons better than one that only knows *what*.
|
|
1320
|
+
These are placeholders.
|
|
1321
|
+
|
|
1322
|
+
<Timeline
|
|
1323
|
+
label="Formative moments"
|
|
1324
|
+
items={[
|
|
1325
|
+
{
|
|
1326
|
+
date: "2016",
|
|
1327
|
+
title: "The outage that taught me to write things down",
|
|
1328
|
+
body: "A fix lived only in one person's head. When they were out, we relearned it the hard way. I've defaulted to docs ever since.",
|
|
1329
|
+
status: "done",
|
|
1330
|
+
tags: ["process", "writing"],
|
|
1331
|
+
},
|
|
1332
|
+
{
|
|
1333
|
+
date: "2019",
|
|
1334
|
+
title: "Shipped small for the first time",
|
|
1335
|
+
body: "Replaced a six-month rewrite with weekly reversible changes. It landed. I stopped believing in big-bang.",
|
|
1336
|
+
status: "done",
|
|
1337
|
+
tags: ["shipping"],
|
|
1338
|
+
},
|
|
1339
|
+
{
|
|
1340
|
+
date: "2022",
|
|
1341
|
+
title: "A review that changed how I review",
|
|
1342
|
+
body: "Someone critiqued my code without making me feel small. I've tried to give every review that way since.",
|
|
1343
|
+
status: "done",
|
|
1344
|
+
tags: ["code-review", "tone"],
|
|
1345
|
+
},
|
|
1346
|
+
]}
|
|
1347
|
+
/>
|
|
890
1348
|
`
|
|
891
1349
|
);
|
|
892
1350
|
}
|
|
@@ -915,8 +1373,8 @@ async function initCommand(dir, flags) {
|
|
|
915
1373
|
}
|
|
916
1374
|
if (!name) bail("A name is required (pass --name, a [dir] argument, or run interactively).");
|
|
917
1375
|
let type = flags.type;
|
|
918
|
-
if (type && type !== "company-kb" && type !== "product-docs") {
|
|
919
|
-
bail(`Invalid --type "${type}". Use "company-kb"
|
|
1376
|
+
if (type && type !== "company-kb" && type !== "product-docs" && type !== "personal-kb") {
|
|
1377
|
+
bail(`Invalid --type "${type}". Use "company-kb", "product-docs", or "personal-kb".`);
|
|
920
1378
|
}
|
|
921
1379
|
if (!type && interactive) {
|
|
922
1380
|
const answer = await select({
|
|
@@ -931,6 +1389,11 @@ async function initCommand(dir, flags) {
|
|
|
931
1389
|
value: "product-docs",
|
|
932
1390
|
label: "Product docs",
|
|
933
1391
|
hint: "public-facing documentation"
|
|
1392
|
+
},
|
|
1393
|
+
{
|
|
1394
|
+
value: "personal-kb",
|
|
1395
|
+
label: "Personal KB",
|
|
1396
|
+
hint: "a private, queryable replica of how you think, work, and write"
|
|
934
1397
|
}
|
|
935
1398
|
]
|
|
936
1399
|
});
|
|
@@ -938,6 +1401,7 @@ async function initCommand(dir, flags) {
|
|
|
938
1401
|
type = answer;
|
|
939
1402
|
}
|
|
940
1403
|
if (!type) bail("A type is required (pass --type or run interactively).");
|
|
1404
|
+
const wantsGate = type === "company-kb" || type === "personal-kb";
|
|
941
1405
|
let authEnabled;
|
|
942
1406
|
if (flags.auth !== void 0) {
|
|
943
1407
|
authEnabled = flags.auth;
|
|
@@ -946,12 +1410,12 @@ async function initCommand(dir, flags) {
|
|
|
946
1410
|
} else if (interactive) {
|
|
947
1411
|
const answer = await confirm({
|
|
948
1412
|
message: "Gate the site behind Google SSO (auth)?",
|
|
949
|
-
initialValue:
|
|
1413
|
+
initialValue: wantsGate
|
|
950
1414
|
});
|
|
951
1415
|
if (isCancel(answer)) bail("Cancelled.");
|
|
952
1416
|
authEnabled = answer;
|
|
953
1417
|
} else {
|
|
954
|
-
authEnabled =
|
|
1418
|
+
authEnabled = wantsGate;
|
|
955
1419
|
}
|
|
956
1420
|
let allowedDomain = flags.allowedDomain?.trim();
|
|
957
1421
|
if (authEnabled && !allowedDomain && interactive) {
|
|
@@ -993,10 +1457,11 @@ ${result.issues.map((i) => ` - ${i.path} ${i.message}`).join("\n")}`
|
|
|
993
1457
|
}
|
|
994
1458
|
const { root, source } = scaffold({ dir: targetDir, config });
|
|
995
1459
|
outro(`${bold("Scaffolded")} ${config.name} ${dim(`(${source})`)}`);
|
|
996
|
-
if (config.type === "company-kb" && !config.auth?.enabled) {
|
|
1460
|
+
if ((config.type === "company-kb" || config.type === "personal-kb") && !config.auth?.enabled) {
|
|
1461
|
+
const kind = config.type === "personal-kb" ? "personal KB" : "company KB";
|
|
997
1462
|
log.blank();
|
|
998
1463
|
log.warn(
|
|
999
|
-
`This is a ${bold(
|
|
1464
|
+
`This is a ${bold(kind)} but auth is ${bold("not enabled")}. A ${kind} should gate access before you deploy \u2014 re-run with ${cyan("--auth")} or set ${cyan('"auth": { "enabled": true }')} in superlore.json.`
|
|
1000
1465
|
);
|
|
1001
1466
|
}
|
|
1002
1467
|
printNextSteps(root, config);
|
|
@@ -1007,13 +1472,17 @@ async function maybeConnectEditor(flags, interactive) {
|
|
|
1007
1472
|
const editors = detectEditors();
|
|
1008
1473
|
if (editors.length === 0) {
|
|
1009
1474
|
log.blank();
|
|
1010
|
-
log.info(
|
|
1475
|
+
log.info(
|
|
1476
|
+
`${dim("Editor preview:")} install VS Code, Cursor, or Windsurf, then ${cyan("superlore connect")}.`
|
|
1477
|
+
);
|
|
1011
1478
|
return;
|
|
1012
1479
|
}
|
|
1013
1480
|
const names = editors.map((e) => e.label).join(", ");
|
|
1014
1481
|
if (flags.connect !== true && !interactive) {
|
|
1015
1482
|
log.blank();
|
|
1016
|
-
log.info(
|
|
1483
|
+
log.info(
|
|
1484
|
+
`${dim(`Detected ${names}.`)} Run ${cyan("superlore connect")} to install the live-preview extension.`
|
|
1485
|
+
);
|
|
1017
1486
|
return;
|
|
1018
1487
|
}
|
|
1019
1488
|
if (flags.connect !== true) {
|
|
@@ -1044,10 +1513,10 @@ function printNextSteps(root, config) {
|
|
|
1044
1513
|
}
|
|
1045
1514
|
|
|
1046
1515
|
// src/index.ts
|
|
1047
|
-
var VERSION = "0.
|
|
1516
|
+
var VERSION = "0.3.1";
|
|
1048
1517
|
function buildCli(argv = process3.argv) {
|
|
1049
1518
|
const cli = cac("superlore");
|
|
1050
|
-
cli.command("init [dir]", "Scaffold a new superlore knowledge base").option("--name <name>", "KB name").option("--type <type>", "KB type: company-kb | product-docs").option("--auth", "Enable the Google SSO auth gate").option("--no-auth", "Disable the auth gate").option("--allowed-domain <domain>", "Restrict SSO to one email domain (implies --auth)").option("--accent <color>", "Brand accent colour (any CSS colour)").option("--no-mcp", "Disable the MCP endpoint (on by default)").option("--connect", "Install the editor extension after scaffolding (skip the prompt)").option("--no-connect", "Don't set up the editor extension").option("-y, --yes", "Skip prompts; use flags + defaults").example("superlore init my-kb --type product-docs").example("superlore init acme --type company-kb --auth --allowed-domain acme.com").action(
|
|
1519
|
+
cli.command("init [dir]", "Scaffold a new superlore knowledge base").option("--name <name>", "KB name").option("--type <type>", "KB type: company-kb | product-docs | personal-kb").option("--auth", "Enable the Google SSO auth gate").option("--no-auth", "Disable the auth gate").option("--allowed-domain <domain>", "Restrict SSO to one email domain (implies --auth)").option("--accent <color>", "Brand accent colour (any CSS colour)").option("--no-mcp", "Disable the MCP endpoint (on by default)").option("--connect", "Install the editor extension after scaffolding (skip the prompt)").option("--no-connect", "Don't set up the editor extension").option("-y, --yes", "Skip prompts; use flags + defaults").example("superlore init my-kb --type product-docs").example("superlore init acme --type company-kb --auth --allowed-domain acme.com").example("superlore init me --type personal-kb").action(
|
|
1051
1520
|
async (dir, flags) => {
|
|
1052
1521
|
const authExplicit = argv.includes("--auth");
|
|
1053
1522
|
const noAuthExplicit = argv.includes("--no-auth");
|
package/package.json
CHANGED