skill-flow 1.0.3 → 1.0.4
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/README.md +39 -2
- package/README.zh.md +39 -2
- package/dist/cli.js +9 -35
- package/dist/cli.js.map +1 -1
- package/dist/domain/types.d.ts +12 -1
- package/dist/services/skill-flow.d.ts +16 -13
- package/dist/services/skill-flow.js +157 -4
- package/dist/services/skill-flow.js.map +1 -1
- package/dist/services/source-service.d.ts +11 -1
- package/dist/services/source-service.js +56 -14
- package/dist/services/source-service.js.map +1 -1
- package/dist/services/workflow-service.d.ts +2 -2
- package/dist/services/workflow-service.js +17 -4
- package/dist/services/workflow-service.js.map +1 -1
- package/dist/services/workspace-bootstrap-service.d.ts +25 -0
- package/dist/services/workspace-bootstrap-service.js +148 -0
- package/dist/services/workspace-bootstrap-service.js.map +1 -0
- package/dist/state/store.js +1 -0
- package/dist/state/store.js.map +1 -1
- package/dist/tests/skill-flow.test.js +47 -16
- package/dist/tests/skill-flow.test.js.map +1 -1
- package/dist/tui/config-app.d.ts +3 -0
- package/dist/tui/config-app.js +60 -0
- package/dist/tui/config-app.js.map +1 -1
- package/dist/tui/find-app.d.ts +1 -1
- package/dist/tui/find-app.js +36 -4
- package/dist/tui/find-app.js.map +1 -1
- package/dist/utils/naming.d.ts +1 -0
- package/dist/utils/naming.js +7 -1
- package/dist/utils/naming.js.map +1 -1
- package/dist/utils/source-id.js +4 -0
- package/dist/utils/source-id.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { TARGET_DEFINITIONS, TARGET_ORDER } from "../utils/constants.js";
|
|
5
|
+
import { hashDirectory, pathExists, readJsonFile } from "../utils/fs.js";
|
|
6
|
+
import { deriveSourceId } from "../utils/source-id.js";
|
|
7
|
+
export class WorkspaceBootstrapService {
|
|
8
|
+
store;
|
|
9
|
+
constructor(store) {
|
|
10
|
+
this.store = store;
|
|
11
|
+
}
|
|
12
|
+
async detectUnmanagedExternalSkills(manifest, lockFile, onEvent) {
|
|
13
|
+
const managedLocators = new Set(manifest.sources
|
|
14
|
+
.filter((source) => source.kind === "local")
|
|
15
|
+
.map((source) => path.resolve(source.locator)));
|
|
16
|
+
const managedCheckouts = new Set(lockFile.sources.map((source) => path.resolve(source.checkoutPath)));
|
|
17
|
+
const managedTargetPaths = new Set(lockFile.deployments.map((deployment) => path.resolve(deployment.targetPath)));
|
|
18
|
+
const agentsOrigins = await this.readAgentsOrigins();
|
|
19
|
+
const grouped = new Map();
|
|
20
|
+
onEvent?.({
|
|
21
|
+
phase: "scan-external-roots",
|
|
22
|
+
level: "info",
|
|
23
|
+
message: "Scanning detected agent roots for unmanaged skills...",
|
|
24
|
+
});
|
|
25
|
+
for (const target of TARGET_ORDER) {
|
|
26
|
+
const definition = TARGET_DEFINITIONS[target];
|
|
27
|
+
const overrideRoot = process.env[definition.envVar]?.trim();
|
|
28
|
+
const roots = [
|
|
29
|
+
...new Set([
|
|
30
|
+
...(overrideRoot ? [path.resolve(overrideRoot)] : []),
|
|
31
|
+
...definition.writeRootCandidates,
|
|
32
|
+
...definition.compatReadRootCandidates,
|
|
33
|
+
]),
|
|
34
|
+
];
|
|
35
|
+
for (const root of roots) {
|
|
36
|
+
if (!(await pathExists(root))) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const entries = await fs.readdir(root, { withFileTypes: true });
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
const skillDir = path.join(root, entry.name);
|
|
42
|
+
const isDirectoryLike = entry.isDirectory() ||
|
|
43
|
+
(entry.isSymbolicLink() &&
|
|
44
|
+
(await fs.stat(skillDir).then((stats) => stats.isDirectory()).catch(() => false)));
|
|
45
|
+
if (!isDirectoryLike) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (!(await pathExists(path.join(skillDir, "SKILL.md")))) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const resolvedPath = await fs.realpath(skillDir).catch(() => path.resolve(skillDir));
|
|
52
|
+
if (this.isUnderSkillFlowStore(resolvedPath)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (managedLocators.has(resolvedPath) ||
|
|
56
|
+
managedCheckouts.has(resolvedPath) ||
|
|
57
|
+
managedTargetPaths.has(resolvedPath)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const contentHash = await hashDirectory(resolvedPath);
|
|
61
|
+
const groupKey = `${entry.name}\n${contentHash}`;
|
|
62
|
+
const current = grouped.get(groupKey);
|
|
63
|
+
if (current) {
|
|
64
|
+
current.targets.add(target);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
grouped.set(groupKey, {
|
|
68
|
+
path: resolvedPath,
|
|
69
|
+
displayName: entry.name,
|
|
70
|
+
hash: contentHash,
|
|
71
|
+
targets: new Set([target]),
|
|
72
|
+
origin: agentsOrigins.get(entry.name),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const takenSourceIds = new Set(manifest.sources.map((source) => source.id));
|
|
78
|
+
const results = [];
|
|
79
|
+
for (const item of grouped.values()) {
|
|
80
|
+
const baseId = deriveSourceId(item.path);
|
|
81
|
+
const sourceId = this.allocateSourceId(baseId, item.targets, takenSourceIds);
|
|
82
|
+
takenSourceIds.add(sourceId);
|
|
83
|
+
results.push({
|
|
84
|
+
path: item.path,
|
|
85
|
+
displayName: item.displayName,
|
|
86
|
+
sourceId,
|
|
87
|
+
importedFromTargets: TARGET_ORDER.filter((target) => item.targets.has(target)),
|
|
88
|
+
...(item.origin?.originLocator ? { originLocator: item.origin.originLocator } : {}),
|
|
89
|
+
...(item.origin?.originRequestedPath
|
|
90
|
+
? { originRequestedPath: item.origin.originRequestedPath }
|
|
91
|
+
: {}),
|
|
92
|
+
...(item.origin?.originBranch ? { originBranch: item.origin.originBranch } : {}),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return results.sort((left, right) => left.displayName.localeCompare(right.displayName));
|
|
96
|
+
}
|
|
97
|
+
isUnderSkillFlowStore(candidatePath) {
|
|
98
|
+
const relative = path.relative(this.store.rootPath, candidatePath);
|
|
99
|
+
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
100
|
+
}
|
|
101
|
+
allocateSourceId(baseId, targets, takenSourceIds) {
|
|
102
|
+
if (!takenSourceIds.has(baseId)) {
|
|
103
|
+
return baseId;
|
|
104
|
+
}
|
|
105
|
+
for (const target of TARGET_ORDER) {
|
|
106
|
+
if (!targets.has(target)) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const suffixed = `${baseId}-${TARGET_DEFINITIONS[target].writerKey}`;
|
|
110
|
+
if (!takenSourceIds.has(suffixed)) {
|
|
111
|
+
return suffixed;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
let index = 2;
|
|
115
|
+
while (takenSourceIds.has(`${baseId}-${index}`)) {
|
|
116
|
+
index += 1;
|
|
117
|
+
}
|
|
118
|
+
return `${baseId}-${index}`;
|
|
119
|
+
}
|
|
120
|
+
async readAgentsOrigins() {
|
|
121
|
+
const lockPath = path.join(os.homedir(), ".agents", ".skill-lock.json");
|
|
122
|
+
const lockFile = await readJsonFile(lockPath, {});
|
|
123
|
+
const results = new Map();
|
|
124
|
+
for (const [name, record] of Object.entries(lockFile.skills ?? {})) {
|
|
125
|
+
if (!record || record.sourceType !== "github") {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
results.set(name, {
|
|
129
|
+
originLocator: record.source ? `https://github.com/${record.source}.git` : undefined,
|
|
130
|
+
originRequestedPath: record.skillPath,
|
|
131
|
+
originBranch: record.branch ?? record.sourceBranch ?? this.parseBranchFromSourceUrl(record.sourceUrl),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return results;
|
|
135
|
+
}
|
|
136
|
+
parseBranchFromSourceUrl(sourceUrl) {
|
|
137
|
+
if (!sourceUrl) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
const treeIndex = sourceUrl.indexOf("/tree/");
|
|
141
|
+
if (treeIndex === -1) {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
const tail = sourceUrl.slice(treeIndex + "/tree/".length);
|
|
145
|
+
return tail.split("/")[0] || undefined;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=workspace-bootstrap-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-bootstrap-service.js","sourceRoot":"","sources":["../../src/services/workspace-bootstrap-service.ts"],"names":[],"mappings":"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"}
|
package/dist/state/store.js
CHANGED
|
@@ -34,6 +34,7 @@ export class StateStore {
|
|
|
34
34
|
return path.join(this.stateRoot, "lock.json");
|
|
35
35
|
}
|
|
36
36
|
async init() {
|
|
37
|
+
await ensureDir(this.getSourceRoot("local"));
|
|
37
38
|
await ensureDir(this.getSourceRoot("git"));
|
|
38
39
|
await ensureDir(this.getSourceRoot("clawhub"));
|
|
39
40
|
await ensureDir(this.catalogRoot);
|
package/dist/state/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/state/store.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/state/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -342,7 +342,7 @@ describe.sequential("skill-flow", () => {
|
|
|
342
342
|
id: "garrytan-gstack",
|
|
343
343
|
locator: "git@github.com:garrytan/gstack.git",
|
|
344
344
|
displayName: "gstack",
|
|
345
|
-
})).toBe("gstack
|
|
345
|
+
})).toBe("gstack@garrytan");
|
|
346
346
|
});
|
|
347
347
|
test("prefers groupName-skillName for projected collisions", () => {
|
|
348
348
|
const projected = resolveProjectedSkillNames([
|
|
@@ -482,7 +482,7 @@ description: |
|
|
|
482
482
|
"good/SKILL.md": skillDoc("good", "Good description."),
|
|
483
483
|
});
|
|
484
484
|
const app = new SkillFlowApp();
|
|
485
|
-
const added = await app.addSource(repoPath);
|
|
485
|
+
const added = await app.addSource(repoPath, { project: false });
|
|
486
486
|
expect(added.ok).toBe(true);
|
|
487
487
|
if (!added.ok) {
|
|
488
488
|
return;
|
|
@@ -509,7 +509,7 @@ description: |
|
|
|
509
509
|
"browse/SKILL.md": skillDoc("browse", "Browser flow."),
|
|
510
510
|
});
|
|
511
511
|
const app = new SkillFlowApp();
|
|
512
|
-
const added = await app.addSource(repoPath);
|
|
512
|
+
const added = await app.addSource(repoPath, { project: false });
|
|
513
513
|
expect(added.ok).toBe(true);
|
|
514
514
|
if (!added.ok) {
|
|
515
515
|
return;
|
|
@@ -537,7 +537,7 @@ description: |
|
|
|
537
537
|
"browse/SKILL.md": skillDoc("browse", "Browser flow."),
|
|
538
538
|
});
|
|
539
539
|
const app = new SkillFlowApp();
|
|
540
|
-
const added = await app.addSource(repoPath);
|
|
540
|
+
const added = await app.addSource(repoPath, { project: false });
|
|
541
541
|
expect(added.ok).toBe(true);
|
|
542
542
|
if (!added.ok) {
|
|
543
543
|
return;
|
|
@@ -551,14 +551,14 @@ description: |
|
|
|
551
551
|
selectedLeafIds: [leafId],
|
|
552
552
|
});
|
|
553
553
|
expect(applied.ok).toBe(true);
|
|
554
|
-
expect(path.resolve(await fs.readlink(targetPath))).toBe(path.join(
|
|
554
|
+
expect(path.resolve(await fs.readlink(targetPath))).toBe(path.join(added.data.lock.checkoutPath, "browse"));
|
|
555
555
|
});
|
|
556
556
|
test("keeps external different-content skill and renames our projection instead", async () => {
|
|
557
557
|
const repoPath = await createRepo(sandboxRoot, {
|
|
558
558
|
"browse/SKILL.md": skillDoc("browse", "Managed browser flow."),
|
|
559
559
|
});
|
|
560
560
|
const app = new SkillFlowApp();
|
|
561
|
-
const added = await app.addSource(repoPath);
|
|
561
|
+
const added = await app.addSource(repoPath, { project: false });
|
|
562
562
|
expect(added.ok).toBe(true);
|
|
563
563
|
if (!added.ok) {
|
|
564
564
|
return;
|
|
@@ -586,7 +586,7 @@ description: |
|
|
|
586
586
|
"browse/SKILL.md": skillDoc("browse", "Managed browser flow."),
|
|
587
587
|
});
|
|
588
588
|
const app = new SkillFlowApp();
|
|
589
|
-
const added = await app.addSource(repoPath);
|
|
589
|
+
const added = await app.addSource(repoPath, { project: false });
|
|
590
590
|
expect(added.ok).toBe(true);
|
|
591
591
|
if (!added.ok) {
|
|
592
592
|
return;
|
|
@@ -620,7 +620,7 @@ description: |
|
|
|
620
620
|
"good/SKILL.md": skillDoc("good", "Good description."),
|
|
621
621
|
});
|
|
622
622
|
const app = new SkillFlowApp();
|
|
623
|
-
const added = await app.addSource(repoPath);
|
|
623
|
+
const added = await app.addSource(repoPath, { project: false });
|
|
624
624
|
expect(added.ok).toBe(true);
|
|
625
625
|
if (!added.ok) {
|
|
626
626
|
return;
|
|
@@ -632,7 +632,7 @@ description: |
|
|
|
632
632
|
selectedLeafIds: [leafId],
|
|
633
633
|
});
|
|
634
634
|
expect(applied.ok).toBe(true);
|
|
635
|
-
await fs.rm(path.join(
|
|
635
|
+
await fs.rm(path.join(added.data.lock.checkoutPath, "good"), {
|
|
636
636
|
recursive: true,
|
|
637
637
|
force: true,
|
|
638
638
|
});
|
|
@@ -747,7 +747,7 @@ description: |
|
|
|
747
747
|
"browse/SKILL.md": skillDoc("browse", "Browser flow."),
|
|
748
748
|
});
|
|
749
749
|
const app = new SkillFlowApp();
|
|
750
|
-
const added = await app.addSource(repoPath);
|
|
750
|
+
const added = await app.addSource(`file://${repoPath}`);
|
|
751
751
|
expect(added.ok).toBe(true);
|
|
752
752
|
if (!added.ok) {
|
|
753
753
|
return;
|
|
@@ -863,7 +863,7 @@ description: |
|
|
|
863
863
|
"good/SKILL.md": skillDoc("good", "Good description."),
|
|
864
864
|
});
|
|
865
865
|
const app = new SkillFlowApp();
|
|
866
|
-
const added = await app.addSource(repoPath);
|
|
866
|
+
const added = await app.addSource(`file://${repoPath}`);
|
|
867
867
|
expect(added.ok).toBe(true);
|
|
868
868
|
if (!added.ok) {
|
|
869
869
|
return;
|
|
@@ -886,14 +886,16 @@ description: |
|
|
|
886
886
|
const repoPath = await createRepo(sandboxRoot, {
|
|
887
887
|
"good/SKILL.md": skillDoc("good", "Good description."),
|
|
888
888
|
});
|
|
889
|
+
const remotePath = await createBareRemote(repoPath, sandboxRoot);
|
|
889
890
|
const app = new SkillFlowApp();
|
|
890
|
-
const added = await app.addSource(
|
|
891
|
+
const added = await app.addSource(`file://${remotePath}`);
|
|
891
892
|
expect(added.ok).toBe(true);
|
|
892
893
|
await writeRepoFiles(repoPath, {
|
|
893
894
|
"extra/SKILL.md": skillDoc("extra", "Extra description."),
|
|
894
895
|
});
|
|
895
896
|
git(repoPath, ["add", "."]);
|
|
896
897
|
git(repoPath, ["commit", "-m", "add extra"]);
|
|
898
|
+
git(repoPath, ["push", "origin", "HEAD"]);
|
|
897
899
|
const updated = await app.updateSources([added.ok ? added.data.manifest.id : ""]);
|
|
898
900
|
expect(updated.ok).toBe(true);
|
|
899
901
|
if (!updated.ok) {
|
|
@@ -905,8 +907,9 @@ description: |
|
|
|
905
907
|
const repoPath = await createRepo(sandboxRoot, {
|
|
906
908
|
"good/SKILL.md": skillDoc("good", "Good description."),
|
|
907
909
|
});
|
|
910
|
+
const remotePath = await createBareRemote(repoPath, sandboxRoot);
|
|
908
911
|
const app = new SkillFlowApp();
|
|
909
|
-
const added = await app.addSource(
|
|
912
|
+
const added = await app.addSource(`file://${remotePath}`);
|
|
910
913
|
expect(added.ok).toBe(true);
|
|
911
914
|
if (!added.ok) {
|
|
912
915
|
return;
|
|
@@ -920,6 +923,7 @@ description: |
|
|
|
920
923
|
await fs.rm(path.join(repoPath, "good"), { recursive: true, force: true });
|
|
921
924
|
git(repoPath, ["add", "."]);
|
|
922
925
|
git(repoPath, ["commit", "-m", "remove good"]);
|
|
926
|
+
git(repoPath, ["push", "origin", "HEAD"]);
|
|
923
927
|
const updated = await app.updateSources([sourceId]);
|
|
924
928
|
expect(updated.ok).toBe(true);
|
|
925
929
|
if (!updated.ok) {
|
|
@@ -932,8 +936,9 @@ description: |
|
|
|
932
936
|
const repoPath = await createRepo(sandboxRoot, {
|
|
933
937
|
"good/SKILL.md": skillDoc("good", "Good description."),
|
|
934
938
|
});
|
|
939
|
+
const remotePath = await createBareRemote(repoPath, sandboxRoot);
|
|
935
940
|
const app = new SkillFlowApp();
|
|
936
|
-
const added = await app.addSource(
|
|
941
|
+
const added = await app.addSource(`file://${remotePath}`);
|
|
937
942
|
expect(added.ok).toBe(true);
|
|
938
943
|
if (!added.ok) {
|
|
939
944
|
return;
|
|
@@ -943,6 +948,7 @@ description: |
|
|
|
943
948
|
});
|
|
944
949
|
git(repoPath, ["add", "."]);
|
|
945
950
|
git(repoPath, ["commit", "-m", "invalidate"]);
|
|
951
|
+
git(repoPath, ["push", "origin", "HEAD"]);
|
|
946
952
|
const updated = await app.updateSources([added.data.manifest.id]);
|
|
947
953
|
expect(updated.ok).toBe(true);
|
|
948
954
|
if (!updated.ok) {
|
|
@@ -979,8 +985,13 @@ description: |
|
|
|
979
985
|
enabledTargets: ["openclaw"],
|
|
980
986
|
selectedLeafIds: [leafId],
|
|
981
987
|
});
|
|
982
|
-
await
|
|
983
|
-
|
|
988
|
+
const lock = await app.store.readLock();
|
|
989
|
+
const deployment = lock.deployments.find((item) => item.sourceId === sourceId && item.leafId === leafId && item.target === "openclaw");
|
|
990
|
+
if (!deployment) {
|
|
991
|
+
throw new Error("expected deployment for openclaw");
|
|
992
|
+
}
|
|
993
|
+
await writeRepoFiles(path.dirname(deployment.targetPath), {
|
|
994
|
+
[`${path.basename(deployment.targetPath)}/SKILL.md`]: "# Good\nMutated copy.",
|
|
984
995
|
});
|
|
985
996
|
const doctor = await app.doctor();
|
|
986
997
|
expect(doctor.ok).toBe(true);
|
|
@@ -989,6 +1000,19 @@ description: |
|
|
|
989
1000
|
}
|
|
990
1001
|
expect(doctor.data.issues.some((issue) => issue.code === "DRIFT_COPY")).toBe(true);
|
|
991
1002
|
});
|
|
1003
|
+
test("bootstrap detects symlinked skills inside agent roots", async () => {
|
|
1004
|
+
const app = new SkillFlowApp();
|
|
1005
|
+
const externalRoot = path.join(sandboxRoot, "external-skill");
|
|
1006
|
+
await writeRepoFiles(externalRoot, {
|
|
1007
|
+
"SKILL.md": skillDoc("linked-skill", "Symlinked external skill."),
|
|
1008
|
+
});
|
|
1009
|
+
await fs.symlink(externalRoot, path.join(process.env.SKILL_FLOW_TARGET_CODEX, "linked-skill"), "junction");
|
|
1010
|
+
await app.store.init();
|
|
1011
|
+
const manifest = await app.store.readManifest();
|
|
1012
|
+
const lock = await app.store.readLock();
|
|
1013
|
+
const detected = await app.workspaceBootstrapService.detectUnmanagedExternalSkills(manifest, lock);
|
|
1014
|
+
expect(detected.some((item) => item.displayName === "linked-skill")).toBe(true);
|
|
1015
|
+
});
|
|
992
1016
|
test("keeps metadata warnings on valid skills", async () => {
|
|
993
1017
|
const repoPath = await createRepo(sandboxRoot, {
|
|
994
1018
|
"folder-name/SKILL.md": skillDoc("bad--name", "x".repeat(1025)),
|
|
@@ -1389,6 +1413,13 @@ async function createRepo(root, files) {
|
|
|
1389
1413
|
git(repoPath, ["commit", "-m", "initial"]);
|
|
1390
1414
|
return repoPath;
|
|
1391
1415
|
}
|
|
1416
|
+
async function createBareRemote(repoPath, root) {
|
|
1417
|
+
const remotePath = await fs.mkdtemp(path.join(root, "remote-"));
|
|
1418
|
+
git(remotePath, ["init", "--bare"]);
|
|
1419
|
+
git(repoPath, ["remote", "add", "origin", remotePath]);
|
|
1420
|
+
git(repoPath, ["push", "-u", "origin", "HEAD"]);
|
|
1421
|
+
return remotePath;
|
|
1422
|
+
}
|
|
1392
1423
|
async function seedBuiltinCatalog(app) {
|
|
1393
1424
|
for (const builtin of builtinGitSources.getBuiltinGitSources()) {
|
|
1394
1425
|
await fs.mkdir(app.store.getCatalogCheckoutPath(deriveSourceId(builtin.locator)), {
|