facult 2.7.1 → 2.7.3
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/package.json +1 -1
- package/src/ai-state.ts +131 -1
- package/src/ai.ts +1 -0
- package/src/audit/update-index.ts +1 -0
- package/src/enable-disable.ts +1 -0
- package/src/graph-query.ts +3 -0
- package/src/graph.ts +1 -0
- package/src/index-builder.ts +164 -16
- package/src/trust-list.ts +1 -0
- package/src/trust.ts +1 -0
package/package.json
CHANGED
package/src/ai-state.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Dirent } from "node:fs";
|
|
2
|
+
import { copyFile, mkdir, readdir, stat } from "node:fs/promises";
|
|
2
3
|
import { dirname, join } from "node:path";
|
|
3
4
|
import { buildIndex } from "./index-builder";
|
|
4
5
|
import {
|
|
5
6
|
facultAiGraphPath,
|
|
6
7
|
facultAiIndexPath,
|
|
7
8
|
legacyFacultStateDirForRoot,
|
|
9
|
+
preferredGlobalAiRoot,
|
|
10
|
+
projectRootFromAiRoot,
|
|
8
11
|
} from "./paths";
|
|
9
12
|
|
|
10
13
|
async function fileExists(path: string): Promise<boolean> {
|
|
@@ -15,6 +18,99 @@ async function fileExists(path: string): Promise<boolean> {
|
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
async function newestPathMtime(path: string): Promise<number> {
|
|
22
|
+
try {
|
|
23
|
+
const st = await stat(path);
|
|
24
|
+
if (st.isFile()) {
|
|
25
|
+
return st.mtimeMs;
|
|
26
|
+
}
|
|
27
|
+
if (!st.isDirectory()) {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
let newest = st.mtimeMs;
|
|
31
|
+
let entries: Dirent<string>[] = [];
|
|
32
|
+
try {
|
|
33
|
+
entries = await readdir(path, { withFileTypes: true, encoding: "utf8" });
|
|
34
|
+
} catch {
|
|
35
|
+
return newest;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
const child = join(path, entry.name);
|
|
40
|
+
if (entry.isFile()) {
|
|
41
|
+
try {
|
|
42
|
+
const childStat = await stat(child);
|
|
43
|
+
newest = Math.max(newest, childStat.mtimeMs);
|
|
44
|
+
} catch {
|
|
45
|
+
// ignore unreadable children
|
|
46
|
+
}
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (entry.isDirectory()) {
|
|
50
|
+
newest = Math.max(newest, await newestPathMtime(child));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return newest;
|
|
54
|
+
} catch {
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function watchedPathMtime(path: string): Promise<number> {
|
|
60
|
+
const newest = await newestPathMtime(path);
|
|
61
|
+
if (newest > 0) {
|
|
62
|
+
return newest;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
return (await stat(dirname(path))).mtimeMs;
|
|
66
|
+
} catch {
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function canonicalAssetsNewerThanIndex(args: {
|
|
72
|
+
homeDir: string;
|
|
73
|
+
rootDir: string;
|
|
74
|
+
indexPath: string;
|
|
75
|
+
}): Promise<boolean> {
|
|
76
|
+
let indexMtimeMs = 0;
|
|
77
|
+
try {
|
|
78
|
+
indexMtimeMs = (await stat(args.indexPath)).mtimeMs;
|
|
79
|
+
} catch {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const watchedRelPaths = [
|
|
84
|
+
"AGENTS.global.md",
|
|
85
|
+
"AGENTS.override.global.md",
|
|
86
|
+
"agents",
|
|
87
|
+
"config.toml",
|
|
88
|
+
"instructions",
|
|
89
|
+
"mcp",
|
|
90
|
+
"skills",
|
|
91
|
+
"snippets",
|
|
92
|
+
"tools",
|
|
93
|
+
];
|
|
94
|
+
const watchedRoots = [args.rootDir];
|
|
95
|
+
|
|
96
|
+
if (projectRootFromAiRoot(args.rootDir, args.homeDir)) {
|
|
97
|
+
const globalRoot = preferredGlobalAiRoot(args.homeDir);
|
|
98
|
+
if (globalRoot !== args.rootDir) {
|
|
99
|
+
watchedRoots.push(globalRoot);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
for (const root of watchedRoots) {
|
|
104
|
+
for (const rel of watchedRelPaths) {
|
|
105
|
+
if ((await watchedPathMtime(join(root, rel))) > indexMtimeMs) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
18
114
|
export function legacyAiIndexPath(rootDir: string): string {
|
|
19
115
|
return join(rootDir, "index.json");
|
|
20
116
|
}
|
|
@@ -46,6 +142,21 @@ export async function ensureAiIndexPath(args: {
|
|
|
46
142
|
}> {
|
|
47
143
|
const generatedPath = facultAiIndexPath(args.homeDir, args.rootDir);
|
|
48
144
|
if (await fileExists(generatedPath)) {
|
|
145
|
+
if (
|
|
146
|
+
args.repair !== false &&
|
|
147
|
+
(await canonicalAssetsNewerThanIndex({
|
|
148
|
+
homeDir: args.homeDir,
|
|
149
|
+
rootDir: args.rootDir,
|
|
150
|
+
indexPath: generatedPath,
|
|
151
|
+
}))
|
|
152
|
+
) {
|
|
153
|
+
const { outputPath } = await buildIndex({
|
|
154
|
+
rootDir: args.rootDir,
|
|
155
|
+
homeDir: args.homeDir,
|
|
156
|
+
force: false,
|
|
157
|
+
});
|
|
158
|
+
return { path: outputPath, repaired: true, source: "rebuilt" };
|
|
159
|
+
}
|
|
49
160
|
return { path: generatedPath, repaired: false, source: "generated" };
|
|
50
161
|
}
|
|
51
162
|
|
|
@@ -100,6 +211,25 @@ export async function ensureAiGraphPath(args: {
|
|
|
100
211
|
}> {
|
|
101
212
|
const generatedPath = facultAiGraphPath(args.homeDir, args.rootDir);
|
|
102
213
|
if (await fileExists(generatedPath)) {
|
|
214
|
+
const generatedIndexPath = facultAiIndexPath(args.homeDir, args.rootDir);
|
|
215
|
+
const freshnessAnchor = (await fileExists(generatedIndexPath))
|
|
216
|
+
? generatedIndexPath
|
|
217
|
+
: generatedPath;
|
|
218
|
+
if (
|
|
219
|
+
args.repair !== false &&
|
|
220
|
+
(await canonicalAssetsNewerThanIndex({
|
|
221
|
+
homeDir: args.homeDir,
|
|
222
|
+
rootDir: args.rootDir,
|
|
223
|
+
indexPath: freshnessAnchor,
|
|
224
|
+
}))
|
|
225
|
+
) {
|
|
226
|
+
const { graphPath } = await buildIndex({
|
|
227
|
+
rootDir: args.rootDir,
|
|
228
|
+
homeDir: args.homeDir,
|
|
229
|
+
force: false,
|
|
230
|
+
});
|
|
231
|
+
return { path: graphPath, rebuilt: true };
|
|
232
|
+
}
|
|
103
233
|
return { path: generatedPath, rebuilt: false };
|
|
104
234
|
}
|
|
105
235
|
|
package/src/ai.ts
CHANGED
|
@@ -16,6 +16,7 @@ function ensureIndexStructure(index: FacultIndex): FacultIndex {
|
|
|
16
16
|
skills: index.skills ?? {},
|
|
17
17
|
mcp: index.mcp ?? { servers: {} },
|
|
18
18
|
agents: index.agents ?? {},
|
|
19
|
+
automations: index.automations ?? {},
|
|
19
20
|
snippets: index.snippets ?? {},
|
|
20
21
|
instructions: index.instructions ?? {},
|
|
21
22
|
};
|
package/src/enable-disable.ts
CHANGED
|
@@ -36,6 +36,7 @@ function ensureIndexStructure(index: FacultIndex): FacultIndex {
|
|
|
36
36
|
skills: index.skills ?? {},
|
|
37
37
|
mcp: index.mcp ?? { servers: {} },
|
|
38
38
|
agents: index.agents ?? {},
|
|
39
|
+
automations: index.automations ?? {},
|
|
39
40
|
snippets: index.snippets ?? {},
|
|
40
41
|
instructions: index.instructions ?? {},
|
|
41
42
|
};
|
package/src/graph-query.ts
CHANGED
|
@@ -12,6 +12,7 @@ type QueryableGraphKind =
|
|
|
12
12
|
| GraphNodeKind
|
|
13
13
|
| "skills"
|
|
14
14
|
| "agents"
|
|
15
|
+
| "automations"
|
|
15
16
|
| "snippets"
|
|
16
17
|
| "instructions"
|
|
17
18
|
| "docs"
|
|
@@ -34,6 +35,8 @@ const KIND_ALIASES: Record<QueryableGraphKind, GraphNodeKind> = {
|
|
|
34
35
|
skills: "skill",
|
|
35
36
|
agent: "agent",
|
|
36
37
|
agents: "agent",
|
|
38
|
+
automation: "automation",
|
|
39
|
+
automations: "automation",
|
|
37
40
|
snippet: "snippet",
|
|
38
41
|
snippets: "snippet",
|
|
39
42
|
instruction: "instruction",
|
package/src/graph.ts
CHANGED
package/src/index-builder.ts
CHANGED
|
@@ -69,6 +69,18 @@ export interface AgentEntry {
|
|
|
69
69
|
path: string;
|
|
70
70
|
description?: string;
|
|
71
71
|
lastModifiedAt?: string;
|
|
72
|
+
enabledFor?: string[];
|
|
73
|
+
trusted?: boolean;
|
|
74
|
+
trustedAt?: string;
|
|
75
|
+
trustedBy?: string;
|
|
76
|
+
auditStatus?: "pending" | "passed" | "flagged";
|
|
77
|
+
lastAuditAt?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface AutomationEntry {
|
|
81
|
+
name: string;
|
|
82
|
+
path: string;
|
|
83
|
+
lastModifiedAt?: string;
|
|
72
84
|
}
|
|
73
85
|
|
|
74
86
|
export interface SnippetEntry {
|
|
@@ -96,6 +108,7 @@ interface ToolAssetEntry extends AssetEntryBase {
|
|
|
96
108
|
export interface SkillEntry extends AssetEntryBase {}
|
|
97
109
|
export interface McpEntry extends AssetEntryBase {}
|
|
98
110
|
export interface AgentEntry extends AssetEntryBase {}
|
|
111
|
+
export interface AutomationEntry extends AssetEntryBase {}
|
|
99
112
|
export interface SnippetEntry extends AssetEntryBase {}
|
|
100
113
|
export interface InstructionEntry extends AssetEntryBase {}
|
|
101
114
|
|
|
@@ -105,6 +118,7 @@ export interface FacultIndex {
|
|
|
105
118
|
skills: Record<string, SkillEntry>;
|
|
106
119
|
mcp: { servers: Record<string, McpEntry> };
|
|
107
120
|
agents: Record<string, AgentEntry>;
|
|
121
|
+
automations?: Record<string, AutomationEntry>;
|
|
108
122
|
snippets: Record<string, SnippetEntry>;
|
|
109
123
|
instructions: Record<string, InstructionEntry>;
|
|
110
124
|
}
|
|
@@ -121,6 +135,7 @@ interface SourceAssets {
|
|
|
121
135
|
skills: Record<string, SkillEntry>;
|
|
122
136
|
mcpServers: Record<string, McpEntry>;
|
|
123
137
|
agents: Record<string, AgentEntry>;
|
|
138
|
+
automations: Record<string, AutomationEntry>;
|
|
124
139
|
snippets: Record<string, SnippetEntry>;
|
|
125
140
|
instructions: Record<string, InstructionEntry>;
|
|
126
141
|
toolConfigs: Record<string, ToolAssetEntry>;
|
|
@@ -197,6 +212,53 @@ function extractIndexMeta(entry: unknown): {
|
|
|
197
212
|
};
|
|
198
213
|
}
|
|
199
214
|
|
|
215
|
+
function findPreviousEntryByCanonicalRef(
|
|
216
|
+
previous: Record<string, unknown> | undefined,
|
|
217
|
+
canonicalRef: string | undefined,
|
|
218
|
+
fallbackName: string
|
|
219
|
+
): unknown {
|
|
220
|
+
if (!previous) {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
if (typeof canonicalRef === "string") {
|
|
224
|
+
for (const value of Object.values(previous)) {
|
|
225
|
+
if (!isPlainObject(value)) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (value.canonicalRef === canonicalRef) {
|
|
229
|
+
return value;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const legacyFallback = previous[fallbackName];
|
|
234
|
+
if (
|
|
235
|
+
isPlainObject(legacyFallback) &&
|
|
236
|
+
typeof legacyFallback.canonicalRef !== "string"
|
|
237
|
+
) {
|
|
238
|
+
return legacyFallback;
|
|
239
|
+
}
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function findPreviousMcpEntry(
|
|
244
|
+
previous: Record<string, unknown> | undefined,
|
|
245
|
+
canonicalRef: string | undefined,
|
|
246
|
+
name: string
|
|
247
|
+
): unknown {
|
|
248
|
+
if (!previous) {
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
const candidate = previous[name];
|
|
252
|
+
if (!isPlainObject(candidate)) {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
return typeof candidate.canonicalRef !== "string" ||
|
|
256
|
+
(typeof canonicalRef === "string" &&
|
|
257
|
+
candidate.canonicalRef === canonicalRef)
|
|
258
|
+
? candidate
|
|
259
|
+
: undefined;
|
|
260
|
+
}
|
|
261
|
+
|
|
200
262
|
function stripQuotes(s: string): string {
|
|
201
263
|
const t = s.trim();
|
|
202
264
|
if (
|
|
@@ -407,6 +469,7 @@ function canonicalRefForPath(
|
|
|
407
469
|
category:
|
|
408
470
|
| "skills"
|
|
409
471
|
| "agents"
|
|
472
|
+
| "automations"
|
|
410
473
|
| "snippets"
|
|
411
474
|
| "instructions"
|
|
412
475
|
| "mcp"
|
|
@@ -489,8 +552,12 @@ async function indexSkills(
|
|
|
489
552
|
const md = await Bun.file(skillMd).text();
|
|
490
553
|
const { description, tags } = parseSkillMarkdown(md);
|
|
491
554
|
const name = basename(d);
|
|
492
|
-
|
|
493
|
-
const prev =
|
|
555
|
+
const canonicalRef = canonicalRefForPath(source, "skills", d);
|
|
556
|
+
const prev = findPreviousEntryByCanonicalRef(
|
|
557
|
+
previous,
|
|
558
|
+
canonicalRef,
|
|
559
|
+
name
|
|
560
|
+
);
|
|
494
561
|
const meta = extractIndexMeta(prev);
|
|
495
562
|
|
|
496
563
|
out[name] = {
|
|
@@ -498,7 +565,7 @@ async function indexSkills(
|
|
|
498
565
|
path: d,
|
|
499
566
|
description,
|
|
500
567
|
tags,
|
|
501
|
-
canonicalRef
|
|
568
|
+
canonicalRef,
|
|
502
569
|
lastModifiedAt: await statIsoTime(skillMd),
|
|
503
570
|
enabledFor: meta.enabledFor,
|
|
504
571
|
trusted: meta.trusted ?? false,
|
|
@@ -550,12 +617,13 @@ async function indexMcpServers(
|
|
|
550
617
|
|
|
551
618
|
const lm = await statIsoTime(mcpConfigPath);
|
|
552
619
|
for (const name of Object.keys(serversObj).sort()) {
|
|
553
|
-
const
|
|
620
|
+
const canonicalRef = canonicalRefForPath(source, "mcp", mcpConfigPath);
|
|
621
|
+
const prev = findPreviousMcpEntry(previous, canonicalRef, name);
|
|
554
622
|
const meta = extractIndexMeta(prev);
|
|
555
623
|
out[name] = {
|
|
556
624
|
name,
|
|
557
625
|
path: mcpConfigPath,
|
|
558
|
-
canonicalRef
|
|
626
|
+
canonicalRef,
|
|
559
627
|
lastModifiedAt: lm,
|
|
560
628
|
definition: serversObj[name],
|
|
561
629
|
enabledFor: meta.enabledFor,
|
|
@@ -576,7 +644,8 @@ async function indexMcpServers(
|
|
|
576
644
|
|
|
577
645
|
async function indexAgents(
|
|
578
646
|
agentsDir: string,
|
|
579
|
-
source: IndexedSource
|
|
647
|
+
source: IndexedSource,
|
|
648
|
+
previous?: Record<string, unknown>
|
|
580
649
|
): Promise<Record<string, AgentEntry>> {
|
|
581
650
|
const out: Record<string, AgentEntry> = {};
|
|
582
651
|
const files: string[] = [];
|
|
@@ -596,6 +665,9 @@ async function indexAgents(
|
|
|
596
665
|
for (const p of files) {
|
|
597
666
|
const name =
|
|
598
667
|
basename(p) === "agent.toml" ? basename(dirname(p)) : basename(p);
|
|
668
|
+
const canonicalRef = canonicalRefForPath(source, "agents", p);
|
|
669
|
+
const prev = findPreviousEntryByCanonicalRef(previous, canonicalRef, name);
|
|
670
|
+
const meta = extractIndexMeta(prev);
|
|
599
671
|
let description: string | undefined;
|
|
600
672
|
try {
|
|
601
673
|
const raw = await Bun.file(p).text();
|
|
@@ -611,14 +683,53 @@ async function indexAgents(
|
|
|
611
683
|
name,
|
|
612
684
|
path: p,
|
|
613
685
|
description,
|
|
614
|
-
canonicalRef
|
|
686
|
+
canonicalRef,
|
|
615
687
|
lastModifiedAt: await statIsoTime(p),
|
|
688
|
+
enabledFor: meta.enabledFor,
|
|
689
|
+
trusted: meta.trusted ?? false,
|
|
690
|
+
trustedAt: meta.trustedAt,
|
|
691
|
+
trustedBy: meta.trustedBy,
|
|
692
|
+
auditStatus: meta.auditStatus ?? "pending",
|
|
693
|
+
lastAuditAt: meta.lastAuditAt,
|
|
616
694
|
...entryScopeMeta(source),
|
|
617
695
|
};
|
|
618
696
|
}
|
|
619
697
|
return out;
|
|
620
698
|
}
|
|
621
699
|
|
|
700
|
+
async function indexAutomations(
|
|
701
|
+
automationsDir: string,
|
|
702
|
+
source: IndexedSource
|
|
703
|
+
): Promise<Record<string, AutomationEntry>> {
|
|
704
|
+
const out: Record<string, AutomationEntry> = {};
|
|
705
|
+
const dirs = await listSubdirs(automationsDir);
|
|
706
|
+
for (const d of dirs) {
|
|
707
|
+
const automationToml = join(d, "automation.toml");
|
|
708
|
+
try {
|
|
709
|
+
const st = await Bun.file(automationToml).stat();
|
|
710
|
+
if (!st.isFile()) {
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const name = basename(d);
|
|
715
|
+
out[name] = {
|
|
716
|
+
name,
|
|
717
|
+
path: automationToml,
|
|
718
|
+
canonicalRef: canonicalRefForPath(
|
|
719
|
+
source,
|
|
720
|
+
"automations",
|
|
721
|
+
automationToml
|
|
722
|
+
),
|
|
723
|
+
lastModifiedAt: await statIsoTime(automationToml),
|
|
724
|
+
...entryScopeMeta(source),
|
|
725
|
+
};
|
|
726
|
+
} catch {
|
|
727
|
+
// Ignore malformed automation entries.
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return out;
|
|
731
|
+
}
|
|
732
|
+
|
|
622
733
|
async function indexSnippets(
|
|
623
734
|
snippetsDir: string,
|
|
624
735
|
source: IndexedSource
|
|
@@ -770,6 +881,7 @@ async function indexSourceAssets(
|
|
|
770
881
|
): Promise<SourceAssets> {
|
|
771
882
|
const skillsDir = join(source.rootDir, "skills");
|
|
772
883
|
const agentsDir = join(source.rootDir, "agents");
|
|
884
|
+
const automationsDir = join(source.rootDir, "automations");
|
|
773
885
|
const snippetsDir = join(source.rootDir, "snippets");
|
|
774
886
|
const instructionsDir = join(source.rootDir, "instructions");
|
|
775
887
|
const toolsDir = join(source.rootDir, "tools");
|
|
@@ -782,6 +894,9 @@ async function indexSourceAssets(
|
|
|
782
894
|
const prevSkills = isPlainObject(previousIndex?.skills)
|
|
783
895
|
? (previousIndex?.skills as Record<string, unknown>)
|
|
784
896
|
: undefined;
|
|
897
|
+
const prevAgents = isPlainObject(previousIndex?.agents)
|
|
898
|
+
? (previousIndex?.agents as Record<string, unknown>)
|
|
899
|
+
: undefined;
|
|
785
900
|
const prevMcpMap =
|
|
786
901
|
isPlainObject(previousIndex?.mcp) &&
|
|
787
902
|
isPlainObject((previousIndex.mcp as Record<string, unknown>).servers)
|
|
@@ -791,20 +906,29 @@ async function indexSourceAssets(
|
|
|
791
906
|
>)
|
|
792
907
|
: undefined;
|
|
793
908
|
|
|
794
|
-
const [
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
909
|
+
const [
|
|
910
|
+
skills,
|
|
911
|
+
mcpServers,
|
|
912
|
+
agents,
|
|
913
|
+
automations,
|
|
914
|
+
snippets,
|
|
915
|
+
instructions,
|
|
916
|
+
toolAssets,
|
|
917
|
+
] = await Promise.all([
|
|
918
|
+
indexSkills(skillsDir, source, prevSkills),
|
|
919
|
+
indexMcpServers(canonicalMcpPath, source, prevMcpMap),
|
|
920
|
+
indexAgents(agentsDir, source, prevAgents),
|
|
921
|
+
indexAutomations(automationsDir, source),
|
|
922
|
+
indexSnippets(snippetsDir, source),
|
|
923
|
+
indexInstructions(instructionsDir, source),
|
|
924
|
+
indexToolAssets(toolsDir, source),
|
|
925
|
+
]);
|
|
803
926
|
|
|
804
927
|
return {
|
|
805
928
|
skills,
|
|
806
929
|
mcpServers,
|
|
807
930
|
agents,
|
|
931
|
+
automations,
|
|
808
932
|
snippets,
|
|
809
933
|
instructions,
|
|
810
934
|
toolConfigs: toolAssets.toolConfigs,
|
|
@@ -836,6 +960,7 @@ function registerGraphEntries<
|
|
|
836
960
|
| "skill"
|
|
837
961
|
| "mcp"
|
|
838
962
|
| "agent"
|
|
963
|
+
| "automation"
|
|
839
964
|
| "snippet"
|
|
840
965
|
| "instruction"
|
|
841
966
|
| "doc"
|
|
@@ -935,6 +1060,11 @@ function buildActiveEntryMap(
|
|
|
935
1060
|
for (const [name, entry] of Object.entries(sourceEntry.assets.agents)) {
|
|
936
1061
|
active.set(activeEntryKey("agent", name), sourceIdentity(entry));
|
|
937
1062
|
}
|
|
1063
|
+
for (const [name, entry] of Object.entries(
|
|
1064
|
+
sourceEntry.assets.automations
|
|
1065
|
+
)) {
|
|
1066
|
+
active.set(activeEntryKey("automation", name), sourceIdentity(entry));
|
|
1067
|
+
}
|
|
938
1068
|
for (const [name, entry] of Object.entries(sourceEntry.assets.snippets)) {
|
|
939
1069
|
active.set(activeEntryKey("snippet", name), sourceIdentity(entry));
|
|
940
1070
|
}
|
|
@@ -1018,6 +1148,7 @@ async function addReferenceEdgesForEntries<
|
|
|
1018
1148
|
kind:
|
|
1019
1149
|
| "skill"
|
|
1020
1150
|
| "agent"
|
|
1151
|
+
| "automation"
|
|
1021
1152
|
| "snippet"
|
|
1022
1153
|
| "instruction"
|
|
1023
1154
|
| "doc"
|
|
@@ -1172,6 +1303,7 @@ function sourceNodeIdForEntry(args: {
|
|
|
1172
1303
|
| "skill"
|
|
1173
1304
|
| "mcp"
|
|
1174
1305
|
| "agent"
|
|
1306
|
+
| "automation"
|
|
1175
1307
|
| "snippet"
|
|
1176
1308
|
| "instruction"
|
|
1177
1309
|
| "doc"
|
|
@@ -1463,6 +1595,9 @@ export async function buildIndex(opts?: {
|
|
|
1463
1595
|
sourceIndexes.map((entry) => entry.assets.mcpServers)
|
|
1464
1596
|
);
|
|
1465
1597
|
const agents = mergeByName(sourceIndexes.map((entry) => entry.assets.agents));
|
|
1598
|
+
const automations = mergeByName(
|
|
1599
|
+
sourceIndexes.map((entry) => entry.assets.automations)
|
|
1600
|
+
);
|
|
1466
1601
|
const snippets = mergeByName(
|
|
1467
1602
|
sourceIndexes.map((entry) => entry.assets.snippets)
|
|
1468
1603
|
);
|
|
@@ -1476,6 +1611,7 @@ export async function buildIndex(opts?: {
|
|
|
1476
1611
|
skills,
|
|
1477
1612
|
mcp: { servers },
|
|
1478
1613
|
agents,
|
|
1614
|
+
automations,
|
|
1479
1615
|
snippets,
|
|
1480
1616
|
instructions,
|
|
1481
1617
|
};
|
|
@@ -1508,6 +1644,12 @@ export async function buildIndex(opts?: {
|
|
|
1508
1644
|
"agent",
|
|
1509
1645
|
activeSelections
|
|
1510
1646
|
);
|
|
1647
|
+
registerGraphEntries(
|
|
1648
|
+
graph,
|
|
1649
|
+
sourceEntry.assets.automations,
|
|
1650
|
+
"automation",
|
|
1651
|
+
activeSelections
|
|
1652
|
+
);
|
|
1511
1653
|
registerGraphEntries(
|
|
1512
1654
|
graph,
|
|
1513
1655
|
sourceEntry.assets.snippets,
|
|
@@ -1562,6 +1704,12 @@ export async function buildIndex(opts?: {
|
|
|
1562
1704
|
"agent",
|
|
1563
1705
|
refsByRoot
|
|
1564
1706
|
);
|
|
1707
|
+
await addReferenceEdgesForEntries(
|
|
1708
|
+
graph,
|
|
1709
|
+
sourceEntry.assets.automations,
|
|
1710
|
+
"automation",
|
|
1711
|
+
refsByRoot
|
|
1712
|
+
);
|
|
1565
1713
|
await addReferenceEdgesForEntries(
|
|
1566
1714
|
graph,
|
|
1567
1715
|
sourceEntry.assets.snippets,
|
package/src/trust-list.ts
CHANGED
package/src/trust.ts
CHANGED
|
@@ -23,6 +23,7 @@ function ensureIndexStructure(index: FacultIndex): FacultIndex {
|
|
|
23
23
|
skills: index.skills ?? {},
|
|
24
24
|
mcp: index.mcp ?? { servers: {} },
|
|
25
25
|
agents: index.agents ?? {},
|
|
26
|
+
automations: index.automations ?? {},
|
|
26
27
|
snippets: index.snippets ?? {},
|
|
27
28
|
instructions: index.instructions ?? {},
|
|
28
29
|
};
|