@rashidee/co2 1.3.9 → 1.3.11
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/.co2-dat/app.db-shm +0 -0
- package/dist/.co2-dat/app.db-wal +0 -0
- package/dist/index.js +267 -74
- package/package.json +1 -1
- package/plugin/skills/mockgen-shadcn/SKILL.md +11 -7
- package/plugin/skills/mockgen-shadcn/references/admin-layout-template.md +14 -3
- package/plugin/skills/mockgen-shadcn/references/mockup-hub-template.md +98 -40
- package/plugin/skills/mockgen-tailwind/references/mockup-hub-template.md +98 -40
- package/plugin/skills/util-gencicdscript/SKILL.md +34 -8
- package/plugin/skills/util-gencicdscript/references/cicd-app-template.md +127 -20
- package/plugin/skills/util-plancicd/SKILL.md +62 -1
- package/static/assets/{abnfDiagram-VRR7QNED-C0CrqPXX.js → abnfDiagram-VRR7QNED-DBzgA_2G.js} +1 -1
- package/static/assets/{arc-BFSRYIcI.js → arc-Bc02_4l6.js} +1 -1
- package/static/assets/{architectureDiagram-ZJ3FMSHR-DuwTK2W9.js → architectureDiagram-ZJ3FMSHR-ixN9wSDW.js} +1 -1
- package/static/assets/{blockDiagram-677ZJIJ3-Bn9tAB0n.js → blockDiagram-677ZJIJ3-Ob4lZkCY.js} +1 -1
- package/static/assets/{c4Diagram-LMCZKHZV-CDiCEjY7.js → c4Diagram-LMCZKHZV-BeJY3Zks.js} +1 -1
- package/static/assets/channel-CJFxgMC1.js +1 -0
- package/static/assets/{chunk-2Q5K7J3B-BMwS7NgW.js → chunk-2Q5K7J3B-DTFIWNGb.js} +1 -1
- package/static/assets/{chunk-32BRIVSS-8l0XBCjq.js → chunk-32BRIVSS-DLTvoPpT.js} +1 -1
- package/static/assets/{chunk-5VM5RSS4-C6Cv-67E.js → chunk-5VM5RSS4-BKlvf6hI.js} +1 -1
- package/static/assets/{chunk-EX3LRPZG-DjWs4lB9.js → chunk-EX3LRPZG-B9ej8_ma.js} +1 -1
- package/static/assets/{chunk-JWPE2WC7-DuK_Mu9c.js → chunk-JWPE2WC7-DAYaiy17.js} +1 -1
- package/static/assets/{chunk-MOJQB5TN-K-bFFmpr.js → chunk-MOJQB5TN-D6rRKzWc.js} +1 -1
- package/static/assets/{chunk-RYQCIY6F-B-b4TyDb.js → chunk-RYQCIY6F-CE4CHN6p.js} +1 -1
- package/static/assets/{chunk-V7JOEXUC-BZRKjyVr.js → chunk-V7JOEXUC-BR-Kl6S2.js} +1 -1
- package/static/assets/{chunk-VR4S4FIN-BcvbM_n3.js → chunk-VR4S4FIN-Bo9J3WGe.js} +1 -1
- package/static/assets/{chunk-XXDRQBXY-Z2nhcpRg.js → chunk-XXDRQBXY-DjI5dJHR.js} +1 -1
- package/static/assets/classDiagram-OUVF2IWQ-B5OYUyBf.js +1 -0
- package/static/assets/classDiagram-v2-EOCWNBFH-B5OYUyBf.js +1 -0
- package/static/assets/{cose-bilkent-JH36ORCC-CPBw8Z2X.js → cose-bilkent-JH36ORCC-DLciz-3w.js} +1 -1
- package/static/assets/{cynefin-VYW2F7L2-DeJ1X-1F.js → cynefin-VYW2F7L2-DqfVJKpm.js} +1 -1
- package/static/assets/{cynefinDiagram-TSTJHNR4-BPs3jIZR.js → cynefinDiagram-TSTJHNR4-D14oLdNM.js} +1 -1
- package/static/assets/{dagre-VKFMJZFB-Bn5Xp63O.js → dagre-VKFMJZFB-BduMbW80.js} +1 -1
- package/static/assets/{diagram-FQU43EPY-DWIlVMUR.js → diagram-FQU43EPY-CLQg7RWT.js} +1 -1
- package/static/assets/{diagram-G47NLZAW-BWxpunVI.js → diagram-G47NLZAW-Dq3Ymr1b.js} +1 -1
- package/static/assets/{diagram-NH7WQ7WH-CpoAYUis.js → diagram-NH7WQ7WH-BPjov8S5.js} +1 -1
- package/static/assets/{diagram-OA4YK3LP-Dv1XfQGK.js → diagram-OA4YK3LP-BgQgpiJD.js} +1 -1
- package/static/assets/{diagram-WEI45ONY-DSk6wZtO.js → diagram-WEI45ONY-BeOPSl27.js} +1 -1
- package/static/assets/{ebnfDiagram-CCIWWBDH-DIDhI2dD.js → ebnfDiagram-CCIWWBDH-DFsTw8OM.js} +1 -1
- package/static/assets/{erDiagram-Q63AITRT-CGO6ep6G.js → erDiagram-Q63AITRT-scBEBawL.js} +1 -1
- package/static/assets/{flowDiagram-23GEKE2U-D8nzLjfG.js → flowDiagram-23GEKE2U-BfX-2ZO-.js} +1 -1
- package/static/assets/{ganttDiagram-NO4QXBWP-Usz8f26d.js → ganttDiagram-NO4QXBWP-BR5IJ1mv.js} +1 -1
- package/static/assets/{gitGraphDiagram-IHSO6WYX-WEJUXa7P.js → gitGraphDiagram-IHSO6WYX-zPu_QDUM.js} +1 -1
- package/static/assets/{index-CM4GfOLV.css → index-DKI3BgkF.css} +1 -1
- package/static/assets/{index-j3pCmOym.js → index-Dnp-sAA_.js} +111 -115
- package/static/assets/{infoDiagram-FWYZ7A6U-BRPwqRvz.js → infoDiagram-FWYZ7A6U-CpyKTQb9.js} +1 -1
- package/static/assets/{ishikawaDiagram-FXEZZL3T-CrntEiqz.js → ishikawaDiagram-FXEZZL3T-C2SXt-2Y.js} +1 -1
- package/static/assets/{journeyDiagram-5HDEW3XC-BmhRsz4F.js → journeyDiagram-5HDEW3XC-DJavk0C4.js} +1 -1
- package/static/assets/{kanban-definition-HUTT4EX6-CWxUXdc3.js → kanban-definition-HUTT4EX6-xN4pVGL7.js} +1 -1
- package/static/assets/{linear-BGjzqzT6.js → linear-BMWKojRX.js} +1 -1
- package/static/assets/{mindmap-definition-LN4V7U3C-CoVNmO4b.js → mindmap-definition-LN4V7U3C-DOaDf7u0.js} +1 -1
- package/static/assets/{pegDiagram-2B236MQR-hBHOzL7x.js → pegDiagram-2B236MQR-B1px906A.js} +1 -1
- package/static/assets/{pieDiagram-ENE6RG2P-Cpv7VZPG.js → pieDiagram-ENE6RG2P-s0vEagFS.js} +1 -1
- package/static/assets/{quadrantDiagram-ABIIQ3AL-BIQAB21D.js → quadrantDiagram-ABIIQ3AL-BEhIl8IZ.js} +1 -1
- package/static/assets/{railroadDiagram-RFXS5EU6-DX6hST3S.js → railroadDiagram-RFXS5EU6-fFsin92S.js} +1 -1
- package/static/assets/{requirementDiagram-TGXJPOKE-Gas2cE_l.js → requirementDiagram-TGXJPOKE-Cf9J7tii.js} +1 -1
- package/static/assets/{sankeyDiagram-HTMAVEWB-BpwoyJDe.js → sankeyDiagram-HTMAVEWB-Cy5gaZqM.js} +1 -1
- package/static/assets/{sequenceDiagram-DBY2YBRQ-CzBxna5k.js → sequenceDiagram-DBY2YBRQ-DI61Vnk1.js} +1 -1
- package/static/assets/{sizeCapture-X5ZJPWSS-Cn-5NsLr.js → sizeCapture-X5ZJPWSS-CmUBUW3B.js} +1 -1
- package/static/assets/{stateDiagram-2N3HPSRC-BiW03iCW.js → stateDiagram-2N3HPSRC-CBMhhwuE.js} +1 -1
- package/static/assets/stateDiagram-v2-6OUMAXLB-BD1I889C.js +1 -0
- package/static/assets/{swimlanes-5IMT3BWC-3jPuufWt.js → swimlanes-5IMT3BWC-CtZlr9wD.js} +2 -2
- package/static/assets/swimlanesDiagram-G3AALYLV-BfEZlw_9.js +8 -0
- package/static/assets/{timeline-definition-FHXFAJF6-CzThWt1O.js → timeline-definition-FHXFAJF6-BC69PWR-.js} +1 -1
- package/static/assets/{vennDiagram-L72KCM5P-D1Axj0CM.js → vennDiagram-L72KCM5P-jEaqKPSP.js} +1 -1
- package/static/assets/{wardleyDiagram-EHGQE667-mKj7UT6Q.js → wardleyDiagram-EHGQE667-CKFWi3EK.js} +1 -1
- package/static/assets/{xychartDiagram-FW5EYKEG-CSAkvAer.js → xychartDiagram-FW5EYKEG-CjyCKfOu.js} +1 -1
- package/static/index.html +2 -2
- package/static/assets/channel-CZGeGYqv.js +0 -1
- package/static/assets/classDiagram-OUVF2IWQ-DV5beYlE.js +0 -1
- package/static/assets/classDiagram-v2-EOCWNBFH-DV5beYlE.js +0 -1
- package/static/assets/stateDiagram-v2-6OUMAXLB-CmQ_Kjkj.js +0 -1
- package/static/assets/swimlanesDiagram-G3AALYLV-OaMW2HRF.js +0 -8
package/dist/index.js
CHANGED
|
@@ -6809,7 +6809,7 @@ var {
|
|
|
6809
6809
|
// package.json
|
|
6810
6810
|
var package_default = {
|
|
6811
6811
|
name: "@rashidee/co2",
|
|
6812
|
-
version: "1.3.
|
|
6812
|
+
version: "1.3.11",
|
|
6813
6813
|
description: "Compound Context Studio \u2014 self-hosted team context authoring for CO2 projects",
|
|
6814
6814
|
type: "module",
|
|
6815
6815
|
license: "MIT",
|
|
@@ -6937,7 +6937,7 @@ ${install.output}`));
|
|
|
6937
6937
|
}
|
|
6938
6938
|
|
|
6939
6939
|
// src/commands/start.ts
|
|
6940
|
-
import { existsSync as
|
|
6940
|
+
import { existsSync as existsSync26 } from "fs";
|
|
6941
6941
|
import { networkInterfaces } from "os";
|
|
6942
6942
|
import { dirname as dirname3, join as join29 } from "path";
|
|
6943
6943
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -19151,6 +19151,14 @@ var gitResolveRequestSchema = external_exports.object({
|
|
|
19151
19151
|
message: "Manual resolution requires the merged content",
|
|
19152
19152
|
path: ["content"]
|
|
19153
19153
|
});
|
|
19154
|
+
var gitPullResponseSchema = external_exports.object({
|
|
19155
|
+
status: external_exports.enum(["up_to_date", "merged", "conflicts"]),
|
|
19156
|
+
branch: external_exports.string(),
|
|
19157
|
+
/** New short HEAD hash — present only for `merged`. */
|
|
19158
|
+
commitHash: external_exports.string().optional(),
|
|
19159
|
+
/** Git's own summary (e.g. the conflict list) — display verbatim. */
|
|
19160
|
+
message: external_exports.string().optional()
|
|
19161
|
+
});
|
|
19154
19162
|
|
|
19155
19163
|
// ../core/src/schemas/import.ts
|
|
19156
19164
|
var importCandidateSchema = external_exports.object({
|
|
@@ -19905,6 +19913,64 @@ async function startMockupHub(db, workspacePath, projectId, requestHost, port) {
|
|
|
19905
19913
|
}
|
|
19906
19914
|
return toStatus({ location, running: false, activePort: targetPort }, requestHost, projectId);
|
|
19907
19915
|
}
|
|
19916
|
+
var STRIP_HEADERS = /* @__PURE__ */ new Set([
|
|
19917
|
+
"connection",
|
|
19918
|
+
"keep-alive",
|
|
19919
|
+
"proxy-authenticate",
|
|
19920
|
+
"proxy-authorization",
|
|
19921
|
+
"te",
|
|
19922
|
+
"trailer",
|
|
19923
|
+
"transfer-encoding",
|
|
19924
|
+
"upgrade",
|
|
19925
|
+
"host",
|
|
19926
|
+
"content-length",
|
|
19927
|
+
"content-encoding",
|
|
19928
|
+
"accept-encoding"
|
|
19929
|
+
]);
|
|
19930
|
+
async function proxyHubRequest(db, workspacePath, projectId, prefix, subPath, req) {
|
|
19931
|
+
const location = resolveHub(db, workspacePath, projectId);
|
|
19932
|
+
if (!location.present) throw svcError("MOCKUP_HUB_MISSING", 404);
|
|
19933
|
+
if (!location.configPort) throw svcError("MOCKUP_HUB_DOWN", 502);
|
|
19934
|
+
const url = new URL(req.url);
|
|
19935
|
+
const target = `http://127.0.0.1:${location.configPort}${subPath}${url.search}`;
|
|
19936
|
+
const headers = new Headers();
|
|
19937
|
+
req.headers.forEach((value, name) => {
|
|
19938
|
+
if (!STRIP_HEADERS.has(name.toLowerCase())) headers.set(name, value);
|
|
19939
|
+
});
|
|
19940
|
+
headers.set("x-forwarded-prefix", prefix);
|
|
19941
|
+
headers.set("x-forwarded-host", url.host);
|
|
19942
|
+
headers.set("x-forwarded-proto", url.protocol.replace(/:$/, ""));
|
|
19943
|
+
const hasBody = req.method !== "GET" && req.method !== "HEAD";
|
|
19944
|
+
let upstream;
|
|
19945
|
+
try {
|
|
19946
|
+
upstream = await fetch(target, {
|
|
19947
|
+
method: req.method,
|
|
19948
|
+
headers,
|
|
19949
|
+
body: hasBody ? await req.arrayBuffer() : void 0,
|
|
19950
|
+
redirect: "manual"
|
|
19951
|
+
});
|
|
19952
|
+
} catch {
|
|
19953
|
+
throw svcError("MOCKUP_HUB_DOWN", 502);
|
|
19954
|
+
}
|
|
19955
|
+
const responseHeaders = new Headers();
|
|
19956
|
+
upstream.headers.forEach((value, name) => {
|
|
19957
|
+
if (!STRIP_HEADERS.has(name.toLowerCase())) responseHeaders.set(name, value);
|
|
19958
|
+
});
|
|
19959
|
+
const redirectTo = responseHeaders.get("location");
|
|
19960
|
+
if (redirectTo?.startsWith("/") && redirectTo !== prefix && !redirectTo.startsWith(`${prefix}/`)) {
|
|
19961
|
+
responseHeaders.set("location", `${prefix}${redirectTo}`);
|
|
19962
|
+
}
|
|
19963
|
+
const prefixAware = upstream.headers.get("x-hub-prefix") !== null;
|
|
19964
|
+
responseHeaders.delete("x-hub-prefix");
|
|
19965
|
+
if (!prefixAware && responseHeaders.get("content-type")?.includes("text/html")) {
|
|
19966
|
+
const html = (await upstream.text()).replace(
|
|
19967
|
+
/(href|src|action|hx-get|hx-post|hx-put|hx-patch|hx-delete)="(\/[^"]*)"/g,
|
|
19968
|
+
(match2, attr, url2) => url2 === prefix || url2.startsWith(`${prefix}/`) ? match2 : `${attr}="${prefix}${url2}"`
|
|
19969
|
+
);
|
|
19970
|
+
return new Response(html, { status: upstream.status, headers: responseHeaders });
|
|
19971
|
+
}
|
|
19972
|
+
return new Response(upstream.body, { status: upstream.status, headers: responseHeaders });
|
|
19973
|
+
}
|
|
19908
19974
|
function stopMockupHub(projectId) {
|
|
19909
19975
|
const child = spawnedHubs.get(projectId);
|
|
19910
19976
|
if (!child) return false;
|
|
@@ -20201,6 +20267,24 @@ function artifactRoutes(db, workspacePath) {
|
|
|
20201
20267
|
return errorResponse(c, e);
|
|
20202
20268
|
}
|
|
20203
20269
|
});
|
|
20270
|
+
app.all(
|
|
20271
|
+
"/mockup-proxy/:projectId",
|
|
20272
|
+
(c) => (
|
|
20273
|
+
// Normalize to the trailing-slash form so the prefix always maps to the hub root.
|
|
20274
|
+
c.redirect(`${c.req.path}/`, 301)
|
|
20275
|
+
)
|
|
20276
|
+
);
|
|
20277
|
+
app.all("/mockup-proxy/:projectId/*", async (c) => {
|
|
20278
|
+
const projectId = Number(c.req.param("projectId"));
|
|
20279
|
+
if (!Number.isInteger(projectId) || projectId <= 0) return c.json({ code: "INVALID_ID" }, 400);
|
|
20280
|
+
const prefix = `/api/artifacts/mockup-proxy/${projectId}`;
|
|
20281
|
+
const subPath = c.req.path.slice(prefix.length) || "/";
|
|
20282
|
+
try {
|
|
20283
|
+
return await proxyHubRequest(db, workspacePath, projectId, prefix, subPath, c.req.raw);
|
|
20284
|
+
} catch (e) {
|
|
20285
|
+
return errorResponse(c, e);
|
|
20286
|
+
}
|
|
20287
|
+
});
|
|
20204
20288
|
app.get("/:id/content", (c) => {
|
|
20205
20289
|
const id = Number(c.req.param("id"));
|
|
20206
20290
|
if (Number.isNaN(id)) return c.json({ code: "INVALID_ID" }, 400);
|
|
@@ -22666,11 +22750,11 @@ function cicdGuardRoutes(db, workspacePath) {
|
|
|
22666
22750
|
}
|
|
22667
22751
|
|
|
22668
22752
|
// ../server/src/features/project/service.ts
|
|
22669
|
-
import { existsSync as
|
|
22753
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
22670
22754
|
import { join as join16 } from "path";
|
|
22671
22755
|
|
|
22672
22756
|
// ../server/src/features/project-config/service.ts
|
|
22673
|
-
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
22757
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
22674
22758
|
import { join as join15 } from "path";
|
|
22675
22759
|
function svcError9(code, status) {
|
|
22676
22760
|
return Object.assign(new Error(code), { code, status });
|
|
@@ -22742,6 +22826,27 @@ function importProjectDevtool(db, workspacePath, projectId, content, importedBy)
|
|
|
22742
22826
|
writeProjectFile(workspacePath, folder, "DEVTOOL.md", content);
|
|
22743
22827
|
return toDto5(db, updated, "devtoolMd");
|
|
22744
22828
|
}
|
|
22829
|
+
function reloadProjectConfigFromFile(db, workspacePath, projectId, fileName, field) {
|
|
22830
|
+
const { folder } = requireProject2(db, projectId);
|
|
22831
|
+
const filePath = join15(workspacePath, folder, fileName);
|
|
22832
|
+
if (!existsSync14(filePath)) throw svcError9("FILE_NOT_FOUND", 404);
|
|
22833
|
+
const content = readFileSync9(filePath, "utf8");
|
|
22834
|
+
const row = getOrCreate(db, projectId);
|
|
22835
|
+
const updated = db.update(projectConfigs).set({ [field]: content, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq(projectConfigs.id, row.id)).returning().get();
|
|
22836
|
+
return toDto5(db, updated, field);
|
|
22837
|
+
}
|
|
22838
|
+
function reloadProjectEnvironment(db, workspacePath, projectId) {
|
|
22839
|
+
return reloadProjectConfigFromFile(
|
|
22840
|
+
db,
|
|
22841
|
+
workspacePath,
|
|
22842
|
+
projectId,
|
|
22843
|
+
"ENVIRONMENT.md",
|
|
22844
|
+
"environmentMd"
|
|
22845
|
+
);
|
|
22846
|
+
}
|
|
22847
|
+
function reloadProjectDevtool(db, workspacePath, projectId) {
|
|
22848
|
+
return reloadProjectConfigFromFile(db, workspacePath, projectId, "DEVTOOL.md", "devtoolMd");
|
|
22849
|
+
}
|
|
22745
22850
|
function adoptProjectConfig(db, projectId, content, importedBy) {
|
|
22746
22851
|
if (content.environmentMd === void 0 && content.devtoolMd === void 0) return;
|
|
22747
22852
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -22868,8 +22973,8 @@ function getBrainstormMd(db, workspacePath, projectId) {
|
|
|
22868
22973
|
project.workspaceFolderName,
|
|
22869
22974
|
`${project.workspaceFolderName}.brainstorm.md`
|
|
22870
22975
|
);
|
|
22871
|
-
if (!
|
|
22872
|
-
return { content:
|
|
22976
|
+
if (!existsSync15(filePath)) throw svcError10("BRAINSTORM_MD_MISSING", 404);
|
|
22977
|
+
return { content: readFileSync10(filePath, "utf8"), filePath };
|
|
22873
22978
|
}
|
|
22874
22979
|
function updateBrainstormMd(db, workspacePath, projectId, content) {
|
|
22875
22980
|
const project = db.select().from(projects).where(eq(projects.id, projectId)).limit(1).get();
|
|
@@ -22922,7 +23027,7 @@ function getProjectDetail(db, workspacePath, projectId) {
|
|
|
22922
23027
|
project.workspaceFolderName,
|
|
22923
23028
|
`${project.workspaceFolderName}.brainstorm.md`
|
|
22924
23029
|
);
|
|
22925
|
-
if (
|
|
23030
|
+
if (existsSync15(brainstormMdPath) && isBrainstormSessionCompleted(readFileSync10(brainstormMdPath, "utf8"))) {
|
|
22926
23031
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
22927
23032
|
db.update(projects).set({ creationStatus: "fully_created", updatedAt: now }).where(eq(projects.id, projectId)).run();
|
|
22928
23033
|
creationStatus = "fully_created";
|
|
@@ -23078,9 +23183,9 @@ function rescanClaudeMd(db, workspacePath, projectId) {
|
|
|
23078
23183
|
const claudeMdPath = [
|
|
23079
23184
|
join16(projectDir2, "CLAUDE.md"),
|
|
23080
23185
|
join16(projectDir2, "source", "CLAUDE.md")
|
|
23081
|
-
].find((p) =>
|
|
23186
|
+
].find((p) => existsSync15(p));
|
|
23082
23187
|
if (!claudeMdPath) throw svcError10("CLAUDE_MD_MISSING", 404);
|
|
23083
|
-
const content =
|
|
23188
|
+
const content = readFileSync10(claudeMdPath, "utf8");
|
|
23084
23189
|
const names = parseApplicationNames(content);
|
|
23085
23190
|
const known = new Set(
|
|
23086
23191
|
db.select({ name: applications.name }).from(applications).where(eq(applications.projectId, projectId)).all().map((r) => toKebabCase(r.name))
|
|
@@ -23412,7 +23517,7 @@ function dashboardRoutes(db) {
|
|
|
23412
23517
|
}
|
|
23413
23518
|
|
|
23414
23519
|
// ../server/src/features/defect/service.ts
|
|
23415
|
-
import { existsSync as
|
|
23520
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
23416
23521
|
import { join as join17 } from "path";
|
|
23417
23522
|
|
|
23418
23523
|
// ../server/src/features/project-import/bug-md.ts
|
|
@@ -23848,10 +23953,10 @@ function writeBugMdFile(db, workspacePath, app, projectFolderName) {
|
|
|
23848
23953
|
return { content, bugCount: bugs.length };
|
|
23849
23954
|
}
|
|
23850
23955
|
function syncBugStatusesFromMaster(db, trackingFilePath, applicationId) {
|
|
23851
|
-
if (!
|
|
23956
|
+
if (!existsSync16(trackingFilePath)) return 0;
|
|
23852
23957
|
let entries;
|
|
23853
23958
|
try {
|
|
23854
|
-
entries = parseBugMaster(
|
|
23959
|
+
entries = parseBugMaster(readFileSync11(trackingFilePath, "utf8"));
|
|
23855
23960
|
} catch {
|
|
23856
23961
|
return 0;
|
|
23857
23962
|
}
|
|
@@ -23879,14 +23984,14 @@ function syncBugMdToDisk(db, workspacePath, applicationId, bugId, mode = "replac
|
|
|
23879
23984
|
if (bugId !== void 0) {
|
|
23880
23985
|
const projectDir2 = join17(workspacePath, project.workspaceFolderName);
|
|
23881
23986
|
const file = join17(projectDir2, resolveAppFolderName(projectDir2, app.name), "context", "BUG.md");
|
|
23882
|
-
if (
|
|
23987
|
+
if (existsSync16(file)) {
|
|
23883
23988
|
const bug = db.select().from(bugReports).where(and(eq(bugReports.id, bugId), eq(bugReports.isDeleted, 0))).get();
|
|
23884
23989
|
if (bug) {
|
|
23885
23990
|
const semver = (bug.prdVersionId !== null ? db.select({ semver: prdVersions.semver }).from(prdVersions).where(eq(prdVersions.id, bug.prdVersionId)).get()?.semver : void 0) ?? "v1.0.0";
|
|
23886
23991
|
const category = (bug.module ? db.select({ name: projectModules.name, category: projectModules.category }).from(projectModules).where(
|
|
23887
23992
|
and(eq(projectModules.applicationId, app.id), eq(projectModules.isDeleted, 0))
|
|
23888
23993
|
).all().find((m) => m.name.toLowerCase() === bug.module?.toLowerCase())?.category : void 0) ?? null;
|
|
23889
|
-
const merged = mergeBugIntoBugMd(
|
|
23994
|
+
const merged = mergeBugIntoBugMd(readFileSync11(file, "utf8"), bug, semver, category, mode);
|
|
23890
23995
|
if (merged !== null) {
|
|
23891
23996
|
writeFileSync9(file, merged, "utf8");
|
|
23892
23997
|
return;
|
|
@@ -24022,7 +24127,7 @@ function defectRoutes(db, workspacePath) {
|
|
|
24022
24127
|
}
|
|
24023
24128
|
|
|
24024
24129
|
// ../server/src/features/document/service.ts
|
|
24025
|
-
import { existsSync as
|
|
24130
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
24026
24131
|
import { join as join18 } from "path";
|
|
24027
24132
|
function svcError12(code, status) {
|
|
24028
24133
|
return Object.assign(new Error(code), { code, status });
|
|
@@ -24053,8 +24158,8 @@ function getDocumentContent(db, dataDir, documentId) {
|
|
|
24053
24158
|
const doc = db.select().from(documents).where(and(eq(documents.id, documentId), eq(documents.isDeleted, 0))).limit(1).get();
|
|
24054
24159
|
if (!doc) throw svcError12("NOT_FOUND", 404);
|
|
24055
24160
|
const fullPath = join18(dataDir, "files", doc.relativePath);
|
|
24056
|
-
if (!
|
|
24057
|
-
return { mimeType: doc.mimeType, bytes:
|
|
24161
|
+
if (!existsSync17(fullPath)) throw svcError12("FILE_MISSING", 404);
|
|
24162
|
+
return { mimeType: doc.mimeType, bytes: readFileSync12(fullPath), name: doc.name };
|
|
24058
24163
|
}
|
|
24059
24164
|
function listProjectDocuments(db, projectId) {
|
|
24060
24165
|
return db.select({
|
|
@@ -24122,7 +24227,7 @@ function documentRoutes(db, dataDir) {
|
|
|
24122
24227
|
|
|
24123
24228
|
// ../server/src/features/git/service.ts
|
|
24124
24229
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
24125
|
-
import { existsSync as
|
|
24230
|
+
import { existsSync as existsSync18, readFileSync as readFileSync13, rmSync, writeFileSync as writeFileSync11 } from "fs";
|
|
24126
24231
|
import { join as join19 } from "path";
|
|
24127
24232
|
var GitServiceError = class extends Error {
|
|
24128
24233
|
code;
|
|
@@ -24161,7 +24266,7 @@ function projectDir(db, workspacePath, projectId) {
|
|
|
24161
24266
|
return join19(workspacePath, project.folder);
|
|
24162
24267
|
}
|
|
24163
24268
|
function isGitRepo(dir) {
|
|
24164
|
-
return
|
|
24269
|
+
return existsSync18(join19(dir, ".git"));
|
|
24165
24270
|
}
|
|
24166
24271
|
function classifyStatus(x, y) {
|
|
24167
24272
|
const conflictPairs = /* @__PURE__ */ new Set(["DD", "AU", "UD", "UA", "DU", "AA", "UU"]);
|
|
@@ -24225,7 +24330,7 @@ function getGitStatus(db, workspacePath, projectId) {
|
|
|
24225
24330
|
files: [],
|
|
24226
24331
|
changedCount: 0
|
|
24227
24332
|
};
|
|
24228
|
-
if (!
|
|
24333
|
+
if (!existsSync18(dir) || !isGitRepo(dir)) return empty;
|
|
24229
24334
|
let raw2;
|
|
24230
24335
|
try {
|
|
24231
24336
|
raw2 = execFileSync3("git", ["status", "--porcelain=v1", "-b", "-z"], {
|
|
@@ -24256,7 +24361,7 @@ function looksBinary(s) {
|
|
|
24256
24361
|
}
|
|
24257
24362
|
function getFileDiff(db, workspacePath, projectId, path) {
|
|
24258
24363
|
const dir = projectDir(db, workspacePath, projectId);
|
|
24259
|
-
if (!
|
|
24364
|
+
if (!existsSync18(dir) || !isGitRepo(dir)) {
|
|
24260
24365
|
throw new GitServiceError("NO_GIT_REPO", 404, "No git repository for this project");
|
|
24261
24366
|
}
|
|
24262
24367
|
const status = getGitStatus(db, workspacePath, projectId);
|
|
@@ -24299,9 +24404,9 @@ function getFileDiff(db, workspacePath, projectId, path) {
|
|
|
24299
24404
|
}
|
|
24300
24405
|
function readWorking(dir, path) {
|
|
24301
24406
|
const abs = join19(dir, path);
|
|
24302
|
-
if (!
|
|
24407
|
+
if (!existsSync18(abs)) return null;
|
|
24303
24408
|
try {
|
|
24304
|
-
return
|
|
24409
|
+
return readFileSync13(abs, "utf8");
|
|
24305
24410
|
} catch {
|
|
24306
24411
|
return null;
|
|
24307
24412
|
}
|
|
@@ -24319,7 +24424,7 @@ function withIdentityHint(message) {
|
|
|
24319
24424
|
}
|
|
24320
24425
|
function commitChanges(db, workspacePath, projectId, input, userId) {
|
|
24321
24426
|
const dir = projectDir(db, workspacePath, projectId);
|
|
24322
|
-
if (!
|
|
24427
|
+
if (!existsSync18(dir) || !isGitRepo(dir)) {
|
|
24323
24428
|
throw new GitServiceError("NO_GIT_REPO", 404, "No git repository for this project");
|
|
24324
24429
|
}
|
|
24325
24430
|
try {
|
|
@@ -24345,7 +24450,7 @@ function commitChanges(db, workspacePath, projectId, input, userId) {
|
|
|
24345
24450
|
}
|
|
24346
24451
|
function discardChanges(db, workspacePath, projectId, paths) {
|
|
24347
24452
|
const dir = projectDir(db, workspacePath, projectId);
|
|
24348
|
-
if (!
|
|
24453
|
+
if (!existsSync18(dir) || !isGitRepo(dir)) {
|
|
24349
24454
|
throw new GitServiceError("NO_GIT_REPO", 404, "No git repository for this project");
|
|
24350
24455
|
}
|
|
24351
24456
|
for (const path of paths) {
|
|
@@ -24359,13 +24464,13 @@ function discardChanges(db, workspacePath, projectId, paths) {
|
|
|
24359
24464
|
}
|
|
24360
24465
|
} else {
|
|
24361
24466
|
const abs = join19(dir, path);
|
|
24362
|
-
if (
|
|
24467
|
+
if (existsSync18(abs)) rmSync(abs, { force: true });
|
|
24363
24468
|
}
|
|
24364
24469
|
}
|
|
24365
24470
|
}
|
|
24366
24471
|
function resolveConflict(db, workspacePath, projectId, input) {
|
|
24367
24472
|
const dir = projectDir(db, workspacePath, projectId);
|
|
24368
|
-
if (!
|
|
24473
|
+
if (!existsSync18(dir) || !isGitRepo(dir)) {
|
|
24369
24474
|
throw new GitServiceError("NO_GIT_REPO", 404, "No git repository for this project");
|
|
24370
24475
|
}
|
|
24371
24476
|
try {
|
|
@@ -24383,6 +24488,67 @@ function resolveConflict(db, workspacePath, projectId, input) {
|
|
|
24383
24488
|
throw new GitServiceError("GIT_RESOLVE_FAILED", 409, detail(e));
|
|
24384
24489
|
}
|
|
24385
24490
|
}
|
|
24491
|
+
function pullChanges(db, workspacePath, projectId, userId) {
|
|
24492
|
+
const dir = projectDir(db, workspacePath, projectId);
|
|
24493
|
+
if (!existsSync18(dir) || !isGitRepo(dir)) {
|
|
24494
|
+
throw new GitServiceError("NO_GIT_REPO", 404, "No git repository for this project");
|
|
24495
|
+
}
|
|
24496
|
+
const status = getGitStatus(db, workspacePath, projectId);
|
|
24497
|
+
if (!status.clean) {
|
|
24498
|
+
throw new GitServiceError(
|
|
24499
|
+
"UNCOMMITTED_CHANGES",
|
|
24500
|
+
409,
|
|
24501
|
+
"Commit or discard your local changes before pulling"
|
|
24502
|
+
);
|
|
24503
|
+
}
|
|
24504
|
+
const branch = safe(() => git3(dir, ["branch", "--show-current"])) ?? "";
|
|
24505
|
+
if (branch === "") {
|
|
24506
|
+
throw new GitServiceError(
|
|
24507
|
+
"DETACHED_HEAD",
|
|
24508
|
+
409,
|
|
24509
|
+
"The repository is in detached HEAD state \u2014 check out a branch before pulling"
|
|
24510
|
+
);
|
|
24511
|
+
}
|
|
24512
|
+
const ctx = resolveGitPushContext(db, projectId, userId);
|
|
24513
|
+
if (ctx.remoteUrl) ensureOrigin(dir, ctx.remoteUrl);
|
|
24514
|
+
const remotes = safe(() => git3(dir, ["remote"])) ?? "";
|
|
24515
|
+
if (!remotes.split("\n").includes("origin")) {
|
|
24516
|
+
throw new GitServiceError("NO_REMOTE", 400, "No git remote configured for this project");
|
|
24517
|
+
}
|
|
24518
|
+
const headBefore = safe(() => git3(dir, ["rev-parse", "--short", "HEAD"])) ?? "";
|
|
24519
|
+
const authB64 = ctx.auth ? Buffer.from(`${ctx.auth.username}:${ctx.auth.token}`).toString("base64") : null;
|
|
24520
|
+
try {
|
|
24521
|
+
execFileSync3(
|
|
24522
|
+
"git",
|
|
24523
|
+
[
|
|
24524
|
+
...buildPushAuthArgs(ctx.auth),
|
|
24525
|
+
...identityArgs(db, userId),
|
|
24526
|
+
"pull",
|
|
24527
|
+
"--no-rebase",
|
|
24528
|
+
"--no-edit",
|
|
24529
|
+
"origin",
|
|
24530
|
+
branch
|
|
24531
|
+
],
|
|
24532
|
+
{
|
|
24533
|
+
cwd: dir,
|
|
24534
|
+
stdio: "pipe",
|
|
24535
|
+
timeout: 12e4,
|
|
24536
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
24537
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
|
|
24538
|
+
}
|
|
24539
|
+
);
|
|
24540
|
+
} catch (e) {
|
|
24541
|
+
if (authB64) redactAuthHeaderFromError(e, authB64);
|
|
24542
|
+
const after = getGitStatus(db, workspacePath, projectId);
|
|
24543
|
+
if (after.hasConflicts) {
|
|
24544
|
+
return { status: "conflicts", branch, message: gitErrorDetail(e) };
|
|
24545
|
+
}
|
|
24546
|
+
throw new GitServiceError("GIT_PULL_FAILED", 409, withIdentityHint(gitErrorDetail(e)));
|
|
24547
|
+
}
|
|
24548
|
+
const headAfter = safe(() => git3(dir, ["rev-parse", "--short", "HEAD"])) ?? "";
|
|
24549
|
+
if (headAfter === headBefore) return { status: "up_to_date", branch };
|
|
24550
|
+
return { status: "merged", branch, commitHash: headAfter };
|
|
24551
|
+
}
|
|
24386
24552
|
function detail(e) {
|
|
24387
24553
|
const stderr = e.stderr?.toString().trim();
|
|
24388
24554
|
return stderr || e.message || String(e);
|
|
@@ -24454,6 +24620,15 @@ function gitRoutes(db, workspacePath) {
|
|
|
24454
24620
|
return errorResponse7(c, e);
|
|
24455
24621
|
}
|
|
24456
24622
|
});
|
|
24623
|
+
app.post("/pull/:projectId", (c) => {
|
|
24624
|
+
const projectId = Number(c.req.param("projectId"));
|
|
24625
|
+
if (Number.isNaN(projectId)) return c.json({ code: "INVALID_ID" }, 400);
|
|
24626
|
+
try {
|
|
24627
|
+
return c.json(pullChanges(db, workspacePath, projectId, c.get("user")?.id));
|
|
24628
|
+
} catch (e) {
|
|
24629
|
+
return errorResponse7(c, e);
|
|
24630
|
+
}
|
|
24631
|
+
});
|
|
24457
24632
|
return app;
|
|
24458
24633
|
}
|
|
24459
24634
|
|
|
@@ -24590,6 +24765,15 @@ function projectConfigRoutes(db, workspacePath) {
|
|
|
24590
24765
|
}
|
|
24591
24766
|
}
|
|
24592
24767
|
);
|
|
24768
|
+
app.post("/:projectId/environment/reload", (c) => {
|
|
24769
|
+
const projectId = parseProjectId2(c);
|
|
24770
|
+
if (projectId === null) return c.json({ code: "INVALID_ID" }, 400);
|
|
24771
|
+
try {
|
|
24772
|
+
return c.json(reloadProjectEnvironment(db, workspacePath, projectId));
|
|
24773
|
+
} catch (e) {
|
|
24774
|
+
return errorResponse9(c, e);
|
|
24775
|
+
}
|
|
24776
|
+
});
|
|
24593
24777
|
app.get("/:projectId/devtool", (c) => {
|
|
24594
24778
|
const projectId = parseProjectId2(c);
|
|
24595
24779
|
if (projectId === null) return c.json({ code: "INVALID_ID" }, 400);
|
|
@@ -24626,11 +24810,20 @@ function projectConfigRoutes(db, workspacePath) {
|
|
|
24626
24810
|
}
|
|
24627
24811
|
}
|
|
24628
24812
|
);
|
|
24813
|
+
app.post("/:projectId/devtool/reload", (c) => {
|
|
24814
|
+
const projectId = parseProjectId2(c);
|
|
24815
|
+
if (projectId === null) return c.json({ code: "INVALID_ID" }, 400);
|
|
24816
|
+
try {
|
|
24817
|
+
return c.json(reloadProjectDevtool(db, workspacePath, projectId));
|
|
24818
|
+
} catch (e) {
|
|
24819
|
+
return errorResponse9(c, e);
|
|
24820
|
+
}
|
|
24821
|
+
});
|
|
24629
24822
|
return app;
|
|
24630
24823
|
}
|
|
24631
24824
|
|
|
24632
24825
|
// ../server/src/features/project-import/scanner.ts
|
|
24633
|
-
import { existsSync as
|
|
24826
|
+
import { existsSync as existsSync19, readFileSync as readFileSync14, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
|
|
24634
24827
|
import { join as join20 } from "path";
|
|
24635
24828
|
|
|
24636
24829
|
// ../server/src/features/project-import/changelog-md.ts
|
|
@@ -24779,7 +24972,7 @@ function svcError13(code, status) {
|
|
|
24779
24972
|
return Object.assign(new Error(code), { code, status });
|
|
24780
24973
|
}
|
|
24781
24974
|
function readIfExists(path) {
|
|
24782
|
-
return
|
|
24975
|
+
return existsSync19(path) ? readFileSync14(path, "utf8") : null;
|
|
24783
24976
|
}
|
|
24784
24977
|
function emptyArtifactCounts() {
|
|
24785
24978
|
return { erd: 0, data_model: 0, mockup: 0, technical_spec: 0, test_spec: 0, source_code: 0 };
|
|
@@ -24788,18 +24981,18 @@ function countArtifacts(appDir) {
|
|
|
24788
24981
|
const counts = emptyArtifactCounts();
|
|
24789
24982
|
const contextDir = join20(appDir, "context");
|
|
24790
24983
|
const modelDir = join20(contextDir, "model");
|
|
24791
|
-
if (
|
|
24984
|
+
if (existsSync19(modelDir)) {
|
|
24792
24985
|
for (const slug of readdirSync3(modelDir)) {
|
|
24793
24986
|
try {
|
|
24794
24987
|
if (!statSync5(join20(modelDir, slug)).isDirectory()) continue;
|
|
24795
24988
|
} catch {
|
|
24796
24989
|
continue;
|
|
24797
24990
|
}
|
|
24798
|
-
if (
|
|
24991
|
+
if (existsSync19(join20(modelDir, slug, "erd.mermaid")) || existsSync19(join20(modelDir, slug, "document-model.mermaid")))
|
|
24799
24992
|
counts.erd++;
|
|
24800
|
-
if (
|
|
24801
|
-
if (
|
|
24802
|
-
if (
|
|
24993
|
+
if (existsSync19(join20(modelDir, slug, "model.md"))) counts.data_model++;
|
|
24994
|
+
if (existsSync19(join20(contextDir, "specification", slug, "SPEC.md"))) counts.technical_spec++;
|
|
24995
|
+
if (existsSync19(join20(contextDir, "test", slug, "TEST_SPEC.md"))) counts.test_spec++;
|
|
24803
24996
|
}
|
|
24804
24997
|
}
|
|
24805
24998
|
for (const [sub, key, file] of [
|
|
@@ -24807,29 +25000,29 @@ function countArtifacts(appDir) {
|
|
|
24807
25000
|
["test", "test_spec", "TEST_SPEC.md"]
|
|
24808
25001
|
]) {
|
|
24809
25002
|
const dir = join20(contextDir, sub);
|
|
24810
|
-
if (!
|
|
25003
|
+
if (!existsSync19(dir)) continue;
|
|
24811
25004
|
let total = 0;
|
|
24812
25005
|
for (const slug of readdirSync3(dir)) {
|
|
24813
25006
|
try {
|
|
24814
|
-
if (statSync5(join20(dir, slug)).isDirectory() &&
|
|
25007
|
+
if (statSync5(join20(dir, slug)).isDirectory() && existsSync19(join20(dir, slug, file))) total++;
|
|
24815
25008
|
} catch {
|
|
24816
25009
|
}
|
|
24817
25010
|
}
|
|
24818
25011
|
counts[key] = Math.max(counts[key], total);
|
|
24819
25012
|
}
|
|
24820
|
-
if (
|
|
25013
|
+
if (existsSync19(join20(contextDir, "mockup", "MOCKUP.html")) || existsSync19(join20(contextDir, "mockup", "index.html")))
|
|
24821
25014
|
counts.mockup = 1;
|
|
24822
25015
|
counts.source_code = sweepSourceFiles(appDir).length;
|
|
24823
25016
|
return counts;
|
|
24824
25017
|
}
|
|
24825
25018
|
function findClaudeMd(folderDir) {
|
|
24826
|
-
if (
|
|
24827
|
-
if (
|
|
25019
|
+
if (existsSync19(join20(folderDir, "CLAUDE.md"))) return { relPath: "CLAUDE.md", prefix: "" };
|
|
25020
|
+
if (existsSync19(join20(folderDir, "source", "CLAUDE.md")))
|
|
24828
25021
|
return { relPath: "source/CLAUDE.md", prefix: "source" };
|
|
24829
25022
|
return null;
|
|
24830
25023
|
}
|
|
24831
25024
|
function listImportCandidates(db, workspacePath) {
|
|
24832
|
-
if (!
|
|
25025
|
+
if (!existsSync19(workspacePath)) return [];
|
|
24833
25026
|
const registered = new Set(
|
|
24834
25027
|
db.select({ folder: projects.workspaceFolderName }).from(projects).all().map((r) => r.folder)
|
|
24835
25028
|
);
|
|
@@ -24845,7 +25038,7 @@ function listImportCandidates(db, workspacePath) {
|
|
|
24845
25038
|
const found = findClaudeMd(dir);
|
|
24846
25039
|
if (!found) continue;
|
|
24847
25040
|
const detail2 = parseProjectDetail(
|
|
24848
|
-
|
|
25041
|
+
readFileSync14(join20(workspacePath, entry, found.relPath), "utf8")
|
|
24849
25042
|
);
|
|
24850
25043
|
candidates.push({
|
|
24851
25044
|
folderName: entry,
|
|
@@ -24860,10 +25053,10 @@ function scanRepo(db, workspacePath, folderName) {
|
|
|
24860
25053
|
const registered = db.select({ id: projects.id }).from(projects).where(eq(projects.workspaceFolderName, folderName)).limit(1).get();
|
|
24861
25054
|
if (registered) throw svcError13("FOLDER_ALREADY_IMPORTED", 409);
|
|
24862
25055
|
const folderDir = join20(workspacePath, folderName);
|
|
24863
|
-
const found =
|
|
25056
|
+
const found = existsSync19(folderDir) ? findClaudeMd(folderDir) : null;
|
|
24864
25057
|
if (!found) throw svcError13("CLAUDE_MD_MISSING", 404);
|
|
24865
25058
|
const repoRoot = found.prefix ? join20(folderDir, found.prefix) : folderDir;
|
|
24866
|
-
const claudeMdRaw =
|
|
25059
|
+
const claudeMdRaw = readFileSync14(join20(folderDir, found.relPath), "utf8");
|
|
24867
25060
|
const detail2 = parseProjectDetail(claudeMdRaw);
|
|
24868
25061
|
const claudeApps = parseClaudeMdApplications(claudeMdRaw);
|
|
24869
25062
|
const claudeModules = new Set(parseModuleNames(claudeMdRaw).map((m) => m.name));
|
|
@@ -24886,7 +25079,7 @@ function scanRepo(db, workspacePath, folderName) {
|
|
|
24886
25079
|
for (const claude of claudeApps) {
|
|
24887
25080
|
const name = toKebabCase(claude.heading);
|
|
24888
25081
|
const resolvedInRoot = resolveAppFolderName(repoRoot, name);
|
|
24889
|
-
const folderExists =
|
|
25082
|
+
const folderExists = existsSync19(join20(repoRoot, resolvedInRoot));
|
|
24890
25083
|
const folderRel = folderExists ? found.prefix ? `${found.prefix}/${resolvedInRoot}` : resolvedInRoot : null;
|
|
24891
25084
|
const appDir = folderRel ? join20(folderDir, folderRel) : null;
|
|
24892
25085
|
const prdRaw = appDir ? readIfExists(join20(appDir, "context", "PRD.md")) : null;
|
|
@@ -24908,8 +25101,8 @@ function scanRepo(db, workspacePath, folderName) {
|
|
|
24908
25101
|
for (const [, m] of bugMaster) if (m.semver) semverUnion.add(m.semver);
|
|
24909
25102
|
const preparePath = appDir ? join20(appDir, "context", "prepare", "PREPARE_MASTER.md") : "";
|
|
24910
25103
|
const developPath = appDir ? join20(appDir, "context", "develop", "IMPLEMENTATION_MASTER.md") : "";
|
|
24911
|
-
const prepareMasterExists = !!appDir &&
|
|
24912
|
-
const developMasterExists = !!appDir &&
|
|
25104
|
+
const prepareMasterExists = !!appDir && existsSync19(preparePath);
|
|
25105
|
+
const developMasterExists = !!appDir && existsSync19(developPath);
|
|
24913
25106
|
const prepareCompleted = prepareMasterExists && parseTrackingStatus(preparePath) === "COMPLETED";
|
|
24914
25107
|
const developCompleted = developMasterExists && parseTrackingStatus(developPath) === "COMPLETED";
|
|
24915
25108
|
const changelogRaw = appDir ? readIfExists(join20(appDir, "CHANGELOG.md")) : null;
|
|
@@ -24998,7 +25191,7 @@ function scanRepo(db, workspacePath, folderName) {
|
|
|
24998
25191
|
const devtoolMd = readIfExists(join20(repoRoot, "DEVTOOL.md")) ?? readIfExists(join20(folderDir, "DEVTOOL.md"));
|
|
24999
25192
|
const origin = readOriginUrl(folderDir);
|
|
25000
25193
|
const gitRemoteUrl = origin ? stripHttpsCredentials(origin) : origin;
|
|
25001
|
-
const defaultBranch =
|
|
25194
|
+
const defaultBranch = existsSync19(join20(folderDir, ".git")) ? detectTrunkBranch(folderDir, readCurrentBranch(folderDir)) : "main";
|
|
25002
25195
|
const gitProvider = /gitlab/i.test(gitRemoteUrl ?? "") ? "gitlab" : "github";
|
|
25003
25196
|
return {
|
|
25004
25197
|
folderName,
|
|
@@ -25057,7 +25250,7 @@ function scanProject(db, workspacePath, folderName) {
|
|
|
25057
25250
|
import { join as join22, relative as relative2 } from "path";
|
|
25058
25251
|
|
|
25059
25252
|
// ../server/src/features/workflow/service.ts
|
|
25060
|
-
import { existsSync as
|
|
25253
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "fs";
|
|
25061
25254
|
import { join as join21, relative, resolve as resolve2, sep } from "path";
|
|
25062
25255
|
var ACTIVE_RUN_STATUSES = ["pending", "in_progress"];
|
|
25063
25256
|
function svcError14(code, status) {
|
|
@@ -25368,8 +25561,8 @@ function backfillWorkflowHistoryFromChangelogs(db, workspacePath, projectId) {
|
|
|
25368
25561
|
for (const app of apps) {
|
|
25369
25562
|
const appRel = resolveAppFolderName(projectDir2, app.name);
|
|
25370
25563
|
const changelogPath = join21(projectDir2, appRel, "CHANGELOG.md");
|
|
25371
|
-
if (!
|
|
25372
|
-
for (const entry of parseChangelogConductorEntries(
|
|
25564
|
+
if (!existsSync20(changelogPath)) continue;
|
|
25565
|
+
for (const entry of parseChangelogConductorEntries(readFileSync15(changelogPath, "utf8"))) {
|
|
25373
25566
|
collected.push({ appName: app.name, appRel, entry });
|
|
25374
25567
|
}
|
|
25375
25568
|
}
|
|
@@ -25530,8 +25723,8 @@ function getWorkflowRunFileContent(db, workspacePath, workflowMarkdownId) {
|
|
|
25530
25723
|
const absolute = resolve2(projectDir2, wfm.filePath);
|
|
25531
25724
|
if (absolute !== projectDir2 && !absolute.startsWith(projectDir2 + sep))
|
|
25532
25725
|
throw svcError14("INVALID_PATH", 400);
|
|
25533
|
-
if (!
|
|
25534
|
-
return { filePath: wfm.filePath, content:
|
|
25726
|
+
if (!existsSync20(absolute)) throw svcError14("FILE_NOT_FOUND", 404);
|
|
25727
|
+
return { filePath: wfm.filePath, content: readFileSync15(absolute, "utf-8") };
|
|
25535
25728
|
}
|
|
25536
25729
|
function getRunApplicationChangelog(db, workspacePath, workflowMarkdownId, appName) {
|
|
25537
25730
|
const wfm = db.select().from(workflowMarkdowns).where(eq(workflowMarkdowns.id, workflowMarkdownId)).get();
|
|
@@ -25551,11 +25744,11 @@ function getRunApplicationChangelog(db, workspacePath, workflowMarkdownId, appNa
|
|
|
25551
25744
|
const absolute = resolve2(projectDir2, appFolder, "CHANGELOG.md");
|
|
25552
25745
|
if (absolute !== projectDir2 && !absolute.startsWith(projectDir2 + sep))
|
|
25553
25746
|
throw svcError14("INVALID_PATH", 400);
|
|
25554
|
-
if (!
|
|
25747
|
+
if (!existsSync20(absolute)) throw svcError14("CHANGELOG_NOT_FOUND", 404);
|
|
25555
25748
|
return {
|
|
25556
25749
|
applicationName: appName,
|
|
25557
25750
|
filePath: relative(workspacePath, absolute).replace(/\\/g, "/"),
|
|
25558
|
-
content:
|
|
25751
|
+
content: readFileSync15(absolute, "utf-8")
|
|
25559
25752
|
};
|
|
25560
25753
|
}
|
|
25561
25754
|
function toDetail(db, projectFolder, wfm, workspacePath) {
|
|
@@ -25597,7 +25790,7 @@ function toDetail(db, projectFolder, wfm, workspacePath) {
|
|
|
25597
25790
|
return {
|
|
25598
25791
|
applicationName: appName,
|
|
25599
25792
|
status: r.status,
|
|
25600
|
-
trackingFileExists:
|
|
25793
|
+
trackingFileExists: existsSync20(trackingPath),
|
|
25601
25794
|
trackingFilePath: relative(workspacePath, trackingPath).replace(/\\/g, "/")
|
|
25602
25795
|
};
|
|
25603
25796
|
});
|
|
@@ -26128,7 +26321,7 @@ function projectRoutes(db, workspacePath) {
|
|
|
26128
26321
|
}
|
|
26129
26322
|
|
|
26130
26323
|
// ../server/src/features/shared-context/service.ts
|
|
26131
|
-
import { existsSync as
|
|
26324
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync16, readdirSync as readdirSync4, statSync as statSync6, writeFileSync as writeFileSync13 } from "fs";
|
|
26132
26325
|
import { join as join23, resolve as resolve3, sep as sep2 } from "path";
|
|
26133
26326
|
function svcError16(code, status) {
|
|
26134
26327
|
return Object.assign(new Error(code), { code, status });
|
|
@@ -26217,7 +26410,7 @@ function uploadFile(db, workspacePath, projectId, folder, file) {
|
|
|
26217
26410
|
if (file.bytes.length > MAX_DOCUMENT_BYTES) throw svcError16("FILE_TOO_LARGE", 413);
|
|
26218
26411
|
const root = resolveSharedRoot(db, workspacePath, projectId);
|
|
26219
26412
|
const dir = folder ? safeResolve(root, folder) : root;
|
|
26220
|
-
if (folder && !
|
|
26413
|
+
if (folder && !existsSync21(dir)) throw svcError16("FOLDER_NOT_FOUND", 404);
|
|
26221
26414
|
const safeName = sanitizeSegment(file.name);
|
|
26222
26415
|
writeFileSync13(join23(dir, safeName), file.bytes);
|
|
26223
26416
|
return { path: folder ? `${folder}/${safeName}` : safeName };
|
|
@@ -26225,15 +26418,15 @@ function uploadFile(db, workspacePath, projectId, folder, file) {
|
|
|
26225
26418
|
function getFileContent(db, workspacePath, projectId, relPath) {
|
|
26226
26419
|
const root = resolveSharedRoot(db, workspacePath, projectId);
|
|
26227
26420
|
const full = safeResolve(root, relPath);
|
|
26228
|
-
if (!
|
|
26421
|
+
if (!existsSync21(full) || !statSync6(full).isFile()) throw svcError16("NOT_FOUND", 404);
|
|
26229
26422
|
const name = relPath.split("/").pop() ?? relPath;
|
|
26230
|
-
return { mimeType: mimeForName(name), bytes:
|
|
26423
|
+
return { mimeType: mimeForName(name), bytes: readFileSync16(full), name };
|
|
26231
26424
|
}
|
|
26232
26425
|
function saveMarkdown(db, workspacePath, projectId, relPath, content) {
|
|
26233
26426
|
if (mimeForName(relPath) !== "text/markdown") throw svcError16("NOT_MARKDOWN", 400);
|
|
26234
26427
|
const root = resolveSharedRoot(db, workspacePath, projectId);
|
|
26235
26428
|
const full = safeResolve(root, relPath);
|
|
26236
|
-
if (!
|
|
26429
|
+
if (!existsSync21(full) || !statSync6(full).isFile()) throw svcError16("NOT_FOUND", 404);
|
|
26237
26430
|
writeFileSync13(full, content, "utf8");
|
|
26238
26431
|
}
|
|
26239
26432
|
|
|
@@ -27147,7 +27340,7 @@ function terminalRoutes(db) {
|
|
|
27147
27340
|
import { execSync } from "child_process";
|
|
27148
27341
|
|
|
27149
27342
|
// ../server/src/lib/claude-plugin.ts
|
|
27150
|
-
import { existsSync as
|
|
27343
|
+
import { existsSync as existsSync22, readFileSync as readFileSync17, readdirSync as readdirSync5 } from "fs";
|
|
27151
27344
|
import { homedir } from "os";
|
|
27152
27345
|
import { join as join24 } from "path";
|
|
27153
27346
|
var PLUGIN_NAME = "co2-skills";
|
|
@@ -27156,7 +27349,7 @@ function detectCo2SkillsPlugin(claudeDir = join24(homedir(), ".claude")) {
|
|
|
27156
27349
|
}
|
|
27157
27350
|
function readRegistry(claudeDir) {
|
|
27158
27351
|
try {
|
|
27159
|
-
const raw2 =
|
|
27352
|
+
const raw2 = readFileSync17(join24(claudeDir, "plugins", "installed_plugins.json"), "utf8");
|
|
27160
27353
|
const json = JSON.parse(raw2);
|
|
27161
27354
|
for (const [key, entries] of Object.entries(json.plugins ?? {})) {
|
|
27162
27355
|
if (!key.startsWith(`${PLUGIN_NAME}@`)) continue;
|
|
@@ -27170,7 +27363,7 @@ function readRegistry(claudeDir) {
|
|
|
27170
27363
|
}
|
|
27171
27364
|
function readCacheDir(claudeDir) {
|
|
27172
27365
|
const base = join24(claudeDir, "plugins", "cache", "co2", PLUGIN_NAME);
|
|
27173
|
-
if (!
|
|
27366
|
+
if (!existsSync22(base)) return { installed: false };
|
|
27174
27367
|
try {
|
|
27175
27368
|
const versions = readdirSync5(base).filter((d) => /^\d+\.\d+/.test(d)).sort();
|
|
27176
27369
|
return { installed: true, version: versions.at(-1) };
|
|
@@ -27224,7 +27417,7 @@ function workspaceRoutes(_db, config, port, host, workspacePath) {
|
|
|
27224
27417
|
}
|
|
27225
27418
|
|
|
27226
27419
|
// ../server/src/lib/config.ts
|
|
27227
|
-
import { existsSync as
|
|
27420
|
+
import { existsSync as existsSync23, readFileSync as readFileSync18, writeFileSync as writeFileSync14 } from "fs";
|
|
27228
27421
|
import { join as join25 } from "path";
|
|
27229
27422
|
var configSchema = external_exports.object({
|
|
27230
27423
|
port: external_exports.number().int().min(1).max(65535).optional(),
|
|
@@ -27234,9 +27427,9 @@ var configSchema = external_exports.object({
|
|
|
27234
27427
|
});
|
|
27235
27428
|
function loadConfig(dataDir) {
|
|
27236
27429
|
const file = join25(dataDir, "config.json");
|
|
27237
|
-
if (!
|
|
27430
|
+
if (!existsSync23(file)) return {};
|
|
27238
27431
|
try {
|
|
27239
|
-
return configSchema.parse(JSON.parse(
|
|
27432
|
+
return configSchema.parse(JSON.parse(readFileSync18(file, "utf8")));
|
|
27240
27433
|
} catch {
|
|
27241
27434
|
return {};
|
|
27242
27435
|
}
|
|
@@ -27289,7 +27482,7 @@ function loggerMiddleware() {
|
|
|
27289
27482
|
}
|
|
27290
27483
|
|
|
27291
27484
|
// ../server/src/lib/static.ts
|
|
27292
|
-
import { existsSync as
|
|
27485
|
+
import { existsSync as existsSync24, readFileSync as readFileSync19, statSync as statSync7 } from "fs";
|
|
27293
27486
|
import { extname, join as join26, normalize, resolve as resolve4, sep as sep3 } from "path";
|
|
27294
27487
|
var MIME = {
|
|
27295
27488
|
".html": "text/html; charset=utf-8",
|
|
@@ -27327,14 +27520,14 @@ function serveSpa(staticDir) {
|
|
|
27327
27520
|
}
|
|
27328
27521
|
const rel = path === "/" ? "/index.html" : decodeURIComponent(path);
|
|
27329
27522
|
const filePath = safeResolve2(staticDir, rel);
|
|
27330
|
-
if (filePath &&
|
|
27331
|
-
const body =
|
|
27523
|
+
if (filePath && existsSync24(filePath) && statSync7(filePath).isFile()) {
|
|
27524
|
+
const body = readFileSync19(filePath);
|
|
27332
27525
|
return c.body(body, 200, {
|
|
27333
27526
|
"Content-Type": MIME[extname(filePath)] ?? "application/octet-stream"
|
|
27334
27527
|
});
|
|
27335
27528
|
}
|
|
27336
|
-
if (
|
|
27337
|
-
return c.body(
|
|
27529
|
+
if (existsSync24(indexPath)) {
|
|
27530
|
+
return c.body(readFileSync19(indexPath), 200, { "Content-Type": "text/html; charset=utf-8" });
|
|
27338
27531
|
}
|
|
27339
27532
|
await next();
|
|
27340
27533
|
};
|
|
@@ -27387,7 +27580,7 @@ function createApp(db, opts) {
|
|
|
27387
27580
|
}
|
|
27388
27581
|
|
|
27389
27582
|
// ../server/src/db/index.ts
|
|
27390
|
-
import { existsSync as
|
|
27583
|
+
import { existsSync as existsSync25 } from "fs";
|
|
27391
27584
|
import { dirname as dirname2, join as join27 } from "path";
|
|
27392
27585
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
27393
27586
|
import Database from "better-sqlite3";
|
|
@@ -27599,7 +27792,7 @@ function resolveMigrationsFolder() {
|
|
|
27599
27792
|
join27(here, "drizzle")
|
|
27600
27793
|
].filter((c) => Boolean(c));
|
|
27601
27794
|
for (const c of candidates) {
|
|
27602
|
-
if (
|
|
27795
|
+
if (existsSync25(join27(c, "meta", "_journal.json"))) return c;
|
|
27603
27796
|
}
|
|
27604
27797
|
return join27(here, "../../drizzle");
|
|
27605
27798
|
}
|
|
@@ -28303,7 +28496,7 @@ var startOptionsSchema = external_exports.object({
|
|
|
28303
28496
|
});
|
|
28304
28497
|
function resolveStaticDir() {
|
|
28305
28498
|
const dir = join29(dirname3(fileURLToPath3(import.meta.url)), "../static");
|
|
28306
|
-
return
|
|
28499
|
+
return existsSync26(join29(dir, "index.html")) ? dir : void 0;
|
|
28307
28500
|
}
|
|
28308
28501
|
function registerStart(program3, version2) {
|
|
28309
28502
|
program3.command("start").description("Start the co2-cli web application (foreground)").option("-p, --port <n>", "Listen port (default: 3001)").option("-H, --host <addr>", "Listen host (default: 0.0.0.0 for LAN access)").option("-d, --data-dir <path>", "Override the data directory").option("-w, --workspace-path <path>", "Override the Workspace root folder").action(async (rawOpts) => {
|