crewx 0.8.7-rc.2 → 0.8.7-rc.21
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/assets/MarketPage-aY16UW1_.js +51 -0
- package/dist/assets/{PromptTab-DPxKgALd.js → PromptTab-C3aTJS6u.js} +7 -7
- package/dist/assets/_baseUniq-DxEFlwNt.js +1 -0
- package/dist/assets/{arc-Wd7DG8CX.js → arc-BCQAokB1.js} +1 -1
- package/dist/assets/architectureDiagram-UYN6MBPD-Bc87ujv2.js +36 -0
- package/dist/assets/blockDiagram-ZHA2E4KO-wC9uH8Lb.js +121 -0
- package/dist/assets/{c4Diagram-6F5ED5ID-CcfPHYky.js → c4Diagram-6F5ED5ID-CqB7lqni.js} +1 -1
- package/dist/assets/channel-DNLHkiNp.js +1 -0
- package/dist/assets/{chunk-5HRBRIJM-TGnRph8o.js → chunk-5HRBRIJM-Cc1L17Eh.js} +1 -1
- package/dist/assets/{chunk-7U56Z5CX-D24Jb5U0.js → chunk-7U56Z5CX-Df3nu_7G.js} +1 -1
- package/dist/assets/{chunk-ASOPGD6M-zBk7x36Z.js → chunk-ASOPGD6M-DIXslLG-.js} +1 -1
- package/dist/assets/{chunk-KFBOBJHC-U1tpWuJd.js → chunk-KFBOBJHC-FytVljyP.js} +1 -1
- package/dist/assets/{chunk-T2TOU4HS-P78s0i18.js → chunk-T2TOU4HS-CU5z-cXq.js} +1 -1
- package/dist/assets/{chunk-TMUBEWPD-_9HBqU-T.js → chunk-TMUBEWPD-CWo1AFyn.js} +1 -1
- package/dist/assets/classDiagram-LNE6IOMH-B430Onym.js +1 -0
- package/dist/assets/classDiagram-v2-MQ7JQ4JX-B430Onym.js +1 -0
- package/dist/assets/clone-B9O3E3P1.js +1 -0
- package/dist/assets/dagre-4EVJKHTY-CgZW5tg4.js +4 -0
- package/dist/assets/diagram-QW4FP2JN-CJAng8RC.js +24 -0
- package/dist/assets/{erDiagram-6RL3IURR-CR3kiDSu.js → erDiagram-6RL3IURR-C1uHztHX.js} +2 -2
- package/dist/assets/{flowDiagram-7ASYPVHJ-B0gVEfBk.js → flowDiagram-7ASYPVHJ-Yiu2odO-.js} +1 -1
- package/dist/assets/{ganttDiagram-NTVNEXSI-CIEk1X3_.js → ganttDiagram-NTVNEXSI-tutc0dJP.js} +3 -3
- package/dist/assets/gitGraph-YCYPL57B-C3jM6T4G.js +133 -0
- package/dist/assets/gitGraphDiagram-NRZ2UAAF-0aqHEKzz.js +65 -0
- package/dist/assets/graph-DC224ILV.js +1 -0
- package/dist/assets/infoDiagram-A4XQUW5V-Do7Mpzkx.js +2 -0
- package/dist/assets/{journeyDiagram-G5WM74LC-U9w5k3my.js → journeyDiagram-G5WM74LC-DAruEJc7.js} +1 -1
- package/dist/assets/{kanban-definition-QRCXZQQD-CO8Lwd1_.js → kanban-definition-QRCXZQQD-DB63vLR0.js} +1 -1
- package/dist/assets/layout-BiYH5x6Q.js +1 -0
- package/dist/assets/{linear-CHGWcXFV.js → linear-CLyGW2s0.js} +1 -1
- package/dist/assets/main-CEKkUqZb.js +1094 -0
- package/dist/assets/main-D3YeRndF.css +10 -0
- package/dist/assets/min-ChJMFU2N.js +1 -0
- package/dist/assets/{mindmap-definition-GWI6TPTV-FRHfidFi.js → mindmap-definition-GWI6TPTV-CtADqQgd.js} +1 -1
- package/dist/assets/pieDiagram-YF2LJOPJ-BSOfzo3O.js +30 -0
- package/dist/assets/{quadrantDiagram-OS5C2QUG-N0MJL1hU.js → quadrantDiagram-OS5C2QUG-BLBQNFVb.js} +1 -1
- package/dist/assets/{requirementDiagram-MIRIMTAZ-n0yYIEdg.js → requirementDiagram-MIRIMTAZ-DqorvuS6.js} +2 -2
- package/dist/assets/{sankeyDiagram-Y46BX6SQ-DzRt1UUn.js → sankeyDiagram-Y46BX6SQ-4NDcrLkB.js} +1 -1
- package/dist/assets/{sequenceDiagram-G6AWOVSC-Bw73EL9L.js → sequenceDiagram-G6AWOVSC-yha6BxK2.js} +1 -1
- package/dist/assets/stateDiagram-MAYHULR4-XJ_I41ez.js +1 -0
- package/dist/assets/stateDiagram-v2-4JROLMXI-CxcyPJO2.js +1 -0
- package/dist/assets/{timeline-definition-U7ZMHBDA-BEgtmEeC.js → timeline-definition-U7ZMHBDA-DCNrmvE7.js} +1 -1
- package/dist/assets/{xychartDiagram-6QU3TZC5-bWuCFYmh.js → xychartDiagram-6QU3TZC5-9N-Ohhdp.js} +2 -2
- package/dist/index.html +2 -2
- package/dist-server/app.module.js +6 -0
- package/dist-server/common/analytics.client.js +180 -0
- package/dist-server/common/analytics.module.js +21 -0
- package/dist-server/common/device-id.js +33 -0
- package/dist-server/domain/cli/cli.service.js +66 -4
- package/dist-server/domain/document/document.service.js +6 -3
- package/dist-server/domain/goal/dto/goal.dto.js +49 -0
- package/dist-server/domain/goal/goal.controller.js +86 -0
- package/dist-server/domain/goal/goal.module.js +22 -0
- package/dist-server/domain/goal/goal.service.js +197 -0
- package/dist-server/domain/goal/parser/goal-md-parser.js +166 -0
- package/dist-server/domain/goal/parser/goal-md-serializer.js +110 -0
- package/dist-server/domain/market/market.controller.js +25 -1
- package/dist-server/domain/market/market.service.js +414 -18
- package/dist-server/domain/planner/dto/planner.dto.js +7 -44
- package/dist-server/domain/planner/planner.controller.js +2 -2
- package/dist-server/domain/planner/planner.service.js +24 -0
- package/dist-server/domain/settings/settings.controller.js +52 -0
- package/dist-server/domain/settings/settings.module.js +22 -0
- package/dist-server/domain/settings/settings.service.js +105 -0
- package/dist-server/domain/task/task.service.js +20 -0
- package/dist-server/domain/thread/thread.controller.js +28 -0
- package/dist-server/domain/thread/thread.service.js +20 -0
- package/dist-server/main.js +1 -0
- package/dist-server/repository/task.repository.js +4 -0
- package/dist-server/repository/thread.repository.js +22 -0
- package/package.json +13 -8
- package/packages/cli/dist/builtin.js +1 -0
- package/packages/cli/dist/commands/init.js +251 -8
- package/packages/cli/package.json +2 -1
- package/server.js +6 -3
- package/dist/assets/MarketPage-CjJYSssq.js +0 -56
- package/dist/assets/architectureDiagram-UYN6MBPD-CMavUkL9.js +0 -36
- package/dist/assets/blockDiagram-ZHA2E4KO-D1rNF19s.js +0 -121
- package/dist/assets/channel-CyMi7jVG.js +0 -1
- package/dist/assets/classDiagram-LNE6IOMH-DVWuJ-Df.js +0 -1
- package/dist/assets/classDiagram-v2-MQ7JQ4JX-DVWuJ-Df.js +0 -1
- package/dist/assets/dagre-4EVJKHTY-CcSwRLTq.js +0 -4
- package/dist/assets/diagram-QW4FP2JN-N887K_Ef.js +0 -24
- package/dist/assets/gitGraph-YCYPL57B-Zl60oDrh.js +0 -133
- package/dist/assets/gitGraphDiagram-NRZ2UAAF-CmIpkGbx.js +0 -65
- package/dist/assets/graph-BlwPajkw.js +0 -1
- package/dist/assets/infoDiagram-A4XQUW5V-D3UxyUCV.js +0 -2
- package/dist/assets/layout-Bvwu4dCi.js +0 -1
- package/dist/assets/main-Dnmo7KzM.js +0 -1064
- package/dist/assets/main-Fz5tpoGZ.css +0 -10
- package/dist/assets/pieDiagram-YF2LJOPJ-Eo_N9Dkd.js +0 -30
- package/dist/assets/stateDiagram-MAYHULR4-hqIdsHFt.js +0 -1
- package/dist/assets/stateDiagram-v2-4JROLMXI-BoqygJ0s.js +0 -1
- /package/dist/assets/{gemini-logo.svg → google-logo.svg} +0 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.GoalService = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const fs_1 = require("fs");
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
const goal_md_parser_js_1 = require("./parser/goal-md-parser.js");
|
|
14
|
+
const goal_md_serializer_js_1 = require("./parser/goal-md-serializer.js");
|
|
15
|
+
let GoalService = class GoalService {
|
|
16
|
+
goalDir(workspacePath) {
|
|
17
|
+
return (0, path_1.join)(workspacePath, 'docs', 'goal');
|
|
18
|
+
}
|
|
19
|
+
filePath(workspacePath, goalId) {
|
|
20
|
+
return (0, path_1.join)(this.goalDir(workspacePath), `${goalId}.md`);
|
|
21
|
+
}
|
|
22
|
+
listGoals(workspacePath, status) {
|
|
23
|
+
const dir = this.goalDir(workspacePath);
|
|
24
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
25
|
+
return { goals: [] };
|
|
26
|
+
}
|
|
27
|
+
const files = (0, fs_1.readdirSync)(dir).filter((f) => f.endsWith('.md') && !f.toUpperCase().includes('-TEMPLATE'));
|
|
28
|
+
const goals = [];
|
|
29
|
+
for (const file of files) {
|
|
30
|
+
const goalId = (0, path_1.basename)(file, '.md');
|
|
31
|
+
const fp = (0, path_1.join)(dir, file);
|
|
32
|
+
const raw = (0, fs_1.readFileSync)(fp, 'utf-8');
|
|
33
|
+
const parsed = (0, goal_md_parser_js_1.parseGoalMd)(goalId, raw);
|
|
34
|
+
if (status && parsed.period.status !== status)
|
|
35
|
+
continue;
|
|
36
|
+
const progress = this.computeOverallProgress(parsed.keyResults);
|
|
37
|
+
const stat = (0, fs_1.statSync)(fp);
|
|
38
|
+
goals.push({
|
|
39
|
+
goalId,
|
|
40
|
+
title: parsed.title,
|
|
41
|
+
status: parsed.period.status,
|
|
42
|
+
period: parsed.period,
|
|
43
|
+
progress,
|
|
44
|
+
krSummary: parsed.keyResults.slice(0, 4).map((kr) => ({
|
|
45
|
+
rank: kr.rank,
|
|
46
|
+
text: kr.text,
|
|
47
|
+
progress: this.getKRProgress(kr),
|
|
48
|
+
checked: kr.checked,
|
|
49
|
+
})),
|
|
50
|
+
krCount: parsed.keyResults.length,
|
|
51
|
+
updatedAt: stat.mtime.toISOString(),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
goals.sort((a, b) => {
|
|
55
|
+
const statusOrder = { active: 0, done: 1, dropped: 2 };
|
|
56
|
+
const oa = statusOrder[a.status] ?? 3;
|
|
57
|
+
const ob = statusOrder[b.status] ?? 3;
|
|
58
|
+
if (oa !== ob)
|
|
59
|
+
return oa - ob;
|
|
60
|
+
if (a.status === 'active')
|
|
61
|
+
return b.period.start.localeCompare(a.period.start);
|
|
62
|
+
if (a.status === 'done')
|
|
63
|
+
return (b.period.completedAt ?? '').localeCompare(a.period.completedAt ?? '');
|
|
64
|
+
return (b.period.droppedAt ?? '').localeCompare(a.period.droppedAt ?? '');
|
|
65
|
+
});
|
|
66
|
+
return { goals };
|
|
67
|
+
}
|
|
68
|
+
getGoal(workspacePath, goalId) {
|
|
69
|
+
const fp = this.filePath(workspacePath, goalId);
|
|
70
|
+
if (!(0, fs_1.existsSync)(fp)) {
|
|
71
|
+
throw new common_1.NotFoundException(`Goal not found: ${goalId}`);
|
|
72
|
+
}
|
|
73
|
+
const raw = (0, fs_1.readFileSync)(fp, 'utf-8');
|
|
74
|
+
const parsed = (0, goal_md_parser_js_1.parseGoalMd)(goalId, raw);
|
|
75
|
+
const stat = (0, fs_1.statSync)(fp);
|
|
76
|
+
return this.toGoalDetail(goalId, parsed, stat.mtime.toISOString());
|
|
77
|
+
}
|
|
78
|
+
putGoal(workspacePath, goalId, dto, createOnly = false) {
|
|
79
|
+
if (dto.period?.status === 'dropped' && !dto.period?.reason) {
|
|
80
|
+
throw new common_1.BadRequestException('Reason is required when status is dropped');
|
|
81
|
+
}
|
|
82
|
+
const dir = this.goalDir(workspacePath);
|
|
83
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
84
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
if (createOnly && (0, fs_1.existsSync)(this.filePath(workspacePath, goalId))) {
|
|
87
|
+
throw new common_1.ConflictException(`Goal already exists: ${goalId}`);
|
|
88
|
+
}
|
|
89
|
+
const keyResults = this.recalculateAutoProgress(dto.keyResults ?? []);
|
|
90
|
+
const parsed = {
|
|
91
|
+
frontmatter: {
|
|
92
|
+
type: 'goal',
|
|
93
|
+
description: 'CrewX Goal — OKR',
|
|
94
|
+
notation: {
|
|
95
|
+
weight: '(w:N) — KR weight, default 1 if omitted',
|
|
96
|
+
auto: 'N% auto — L1 progress auto-calculated as weighted average of children',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
title: dto.title,
|
|
100
|
+
period: dto.period ?? { start: '', end: '', status: 'active' },
|
|
101
|
+
objective: dto.objective ?? { body: '' },
|
|
102
|
+
keyResults,
|
|
103
|
+
notes: dto.notes ?? '',
|
|
104
|
+
reflection: dto.reflection ?? '',
|
|
105
|
+
};
|
|
106
|
+
const md = (0, goal_md_serializer_js_1.serializeGoalMd)(parsed);
|
|
107
|
+
const fp = this.filePath(workspacePath, goalId);
|
|
108
|
+
(0, fs_1.writeFileSync)(fp, md, 'utf-8');
|
|
109
|
+
const stat = (0, fs_1.statSync)(fp);
|
|
110
|
+
return this.toGoalDetail(goalId, parsed, stat.mtime.toISOString());
|
|
111
|
+
}
|
|
112
|
+
deleteGoal(workspacePath, goalId) {
|
|
113
|
+
const fp = this.filePath(workspacePath, goalId);
|
|
114
|
+
if (!(0, fs_1.existsSync)(fp)) {
|
|
115
|
+
throw new common_1.NotFoundException(`Goal not found: ${goalId}`);
|
|
116
|
+
}
|
|
117
|
+
(0, fs_1.unlinkSync)(fp);
|
|
118
|
+
return { goalId, deleted: true };
|
|
119
|
+
}
|
|
120
|
+
recalculateAutoProgress(keyResults) {
|
|
121
|
+
return keyResults.map((kr) => {
|
|
122
|
+
if (kr.children && kr.children.length > 0) {
|
|
123
|
+
let totalWeight = 0;
|
|
124
|
+
let weightedSum = 0;
|
|
125
|
+
for (const c of kr.children) {
|
|
126
|
+
const w = c.weight ?? 1;
|
|
127
|
+
const p = c.counter
|
|
128
|
+
? Math.round((c.counter.current / c.counter.target) * 100)
|
|
129
|
+
: (c.progress ?? 0);
|
|
130
|
+
weightedSum += p * w;
|
|
131
|
+
totalWeight += w;
|
|
132
|
+
}
|
|
133
|
+
const auto = totalWeight > 0 ? Math.round(weightedSum / totalWeight) : 0;
|
|
134
|
+
return { ...kr, progressAuto: auto, progress: undefined };
|
|
135
|
+
}
|
|
136
|
+
if (kr.counter) {
|
|
137
|
+
const pct = Math.round((kr.counter.current / kr.counter.target) * 100);
|
|
138
|
+
return { ...kr, progress: pct };
|
|
139
|
+
}
|
|
140
|
+
return kr;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
computeOverallProgress(keyResults) {
|
|
144
|
+
if (keyResults.length === 0)
|
|
145
|
+
return 0;
|
|
146
|
+
let totalWeight = 0;
|
|
147
|
+
let weightedSum = 0;
|
|
148
|
+
for (const kr of keyResults) {
|
|
149
|
+
const w = kr.weight ?? 1;
|
|
150
|
+
const p = this.getKRProgress(kr);
|
|
151
|
+
weightedSum += p * w;
|
|
152
|
+
totalWeight += w;
|
|
153
|
+
}
|
|
154
|
+
return totalWeight > 0 ? Math.round(weightedSum / totalWeight) : 0;
|
|
155
|
+
}
|
|
156
|
+
getKRProgress(kr) {
|
|
157
|
+
if (kr.children && kr.children.length > 0) {
|
|
158
|
+
let totalWeight = 0;
|
|
159
|
+
let weightedSum = 0;
|
|
160
|
+
for (const c of kr.children) {
|
|
161
|
+
const w = c.weight ?? 1;
|
|
162
|
+
const p = c.counter
|
|
163
|
+
? Math.round((c.counter.current / c.counter.target) * 100)
|
|
164
|
+
: (c.progress ?? 0);
|
|
165
|
+
weightedSum += p * w;
|
|
166
|
+
totalWeight += w;
|
|
167
|
+
}
|
|
168
|
+
return totalWeight > 0 ? Math.round(weightedSum / totalWeight) : 0;
|
|
169
|
+
}
|
|
170
|
+
if (kr.progressAuto !== undefined)
|
|
171
|
+
return kr.progressAuto;
|
|
172
|
+
if (kr.counter)
|
|
173
|
+
return Math.round((kr.counter.current / kr.counter.target) * 100);
|
|
174
|
+
return kr.progress ?? 0;
|
|
175
|
+
}
|
|
176
|
+
toGoalDetail(goalId, parsed, updatedAt) {
|
|
177
|
+
return {
|
|
178
|
+
goalId,
|
|
179
|
+
title: parsed.title,
|
|
180
|
+
description: parsed.frontmatter.description ?? 'CrewX Goal — OKR',
|
|
181
|
+
notation: parsed.frontmatter.notation ?? {
|
|
182
|
+
weight: '(w:N) — KR weight, default 1 if omitted',
|
|
183
|
+
auto: 'N% auto — L1 progress auto-calculated as weighted average of children',
|
|
184
|
+
},
|
|
185
|
+
period: parsed.period,
|
|
186
|
+
objective: parsed.objective,
|
|
187
|
+
keyResults: this.recalculateAutoProgress(parsed.keyResults),
|
|
188
|
+
notes: parsed.notes,
|
|
189
|
+
reflection: parsed.reflection,
|
|
190
|
+
updatedAt,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
exports.GoalService = GoalService;
|
|
195
|
+
exports.GoalService = GoalService = __decorate([
|
|
196
|
+
(0, common_1.Injectable)()
|
|
197
|
+
], GoalService);
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseGoalMd = parseGoalMd;
|
|
7
|
+
const gray_matter_1 = __importDefault(require("gray-matter"));
|
|
8
|
+
const WEIGHT_RE = /\(w:(\d+)\)/;
|
|
9
|
+
const AUTO_RE = /—\s+(\d+)%\s+auto/;
|
|
10
|
+
const COUNTER_RE = /—\s+(\d+)\/(\d+)\s+\((\d+)%\)/;
|
|
11
|
+
const SIMPLE_PCT_RE = /—\s+(\d+)%/;
|
|
12
|
+
const L1_RE = /^(\d+)\.\s+\[(x| )\]\s+(.+)$/;
|
|
13
|
+
const L2_RE = /^ {3}-\s+\[(x| )\]\s+(.+)$/;
|
|
14
|
+
function extractWeight(text) {
|
|
15
|
+
const m = text.match(WEIGHT_RE);
|
|
16
|
+
if (!m)
|
|
17
|
+
return { text: text.trim(), weight: 1 };
|
|
18
|
+
return {
|
|
19
|
+
text: text.replace(WEIGHT_RE, '').trim(),
|
|
20
|
+
weight: parseInt(m[1], 10),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function parseProgress(text) {
|
|
24
|
+
let autoMatch = text.match(AUTO_RE);
|
|
25
|
+
if (autoMatch) {
|
|
26
|
+
const cleanText = text.replace(AUTO_RE, '').trim();
|
|
27
|
+
return { cleanText, progressAuto: parseInt(autoMatch[1], 10) };
|
|
28
|
+
}
|
|
29
|
+
let counterMatch = text.match(COUNTER_RE);
|
|
30
|
+
if (counterMatch) {
|
|
31
|
+
const cleanText = text.replace(COUNTER_RE, '').trim();
|
|
32
|
+
return {
|
|
33
|
+
cleanText,
|
|
34
|
+
counter: {
|
|
35
|
+
current: parseInt(counterMatch[1], 10),
|
|
36
|
+
target: parseInt(counterMatch[2], 10),
|
|
37
|
+
},
|
|
38
|
+
progress: parseInt(counterMatch[3], 10),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
let pctMatch = text.match(SIMPLE_PCT_RE);
|
|
42
|
+
if (pctMatch) {
|
|
43
|
+
const cleanText = text.replace(SIMPLE_PCT_RE, '').trim();
|
|
44
|
+
return { cleanText, progress: parseInt(pctMatch[1], 10) };
|
|
45
|
+
}
|
|
46
|
+
return { cleanText: text.trim(), progress: 0 };
|
|
47
|
+
}
|
|
48
|
+
function parseL2(line) {
|
|
49
|
+
const m = line.match(L2_RE);
|
|
50
|
+
if (!m)
|
|
51
|
+
return null;
|
|
52
|
+
const checked = m[1] === 'x';
|
|
53
|
+
let rawText = m[2];
|
|
54
|
+
const { text: afterWeight, weight } = extractWeight(rawText);
|
|
55
|
+
const { cleanText, progress, counter } = parseProgress(afterWeight);
|
|
56
|
+
const child = { text: cleanText, checked, weight };
|
|
57
|
+
if (progress !== undefined)
|
|
58
|
+
child.progress = progress;
|
|
59
|
+
if (counter)
|
|
60
|
+
child.counter = counter;
|
|
61
|
+
return child;
|
|
62
|
+
}
|
|
63
|
+
function parseL1(line) {
|
|
64
|
+
const m = line.match(L1_RE);
|
|
65
|
+
if (!m)
|
|
66
|
+
return null;
|
|
67
|
+
const rank = parseInt(m[1], 10);
|
|
68
|
+
const checked = m[2] === 'x';
|
|
69
|
+
let rawText = m[3];
|
|
70
|
+
const { text: afterWeight, weight } = extractWeight(rawText);
|
|
71
|
+
const { cleanText, progress, progressAuto, counter } = parseProgress(afterWeight);
|
|
72
|
+
const item = { rank, text: cleanText, checked, weight };
|
|
73
|
+
if (progressAuto !== undefined)
|
|
74
|
+
item.progressAuto = progressAuto;
|
|
75
|
+
if (progress !== undefined)
|
|
76
|
+
item.progress = progress;
|
|
77
|
+
if (counter)
|
|
78
|
+
item.counter = counter;
|
|
79
|
+
return item;
|
|
80
|
+
}
|
|
81
|
+
function parsePeriod(body) {
|
|
82
|
+
const period = { start: '', end: '', status: 'active' };
|
|
83
|
+
const lines = body.split('\n');
|
|
84
|
+
for (const line of lines) {
|
|
85
|
+
const m = line.match(/^-\s+(\w[\w\s]*):\s*(.+)$/);
|
|
86
|
+
if (!m)
|
|
87
|
+
continue;
|
|
88
|
+
const key = m[1].trim().toLowerCase();
|
|
89
|
+
const val = m[2].trim();
|
|
90
|
+
if (key === 'start')
|
|
91
|
+
period.start = val;
|
|
92
|
+
else if (key === 'end')
|
|
93
|
+
period.end = val;
|
|
94
|
+
else if (key === 'status')
|
|
95
|
+
period.status = val;
|
|
96
|
+
else if (key === 'completed at')
|
|
97
|
+
period.completedAt = val;
|
|
98
|
+
else if (key === 'dropped at')
|
|
99
|
+
period.droppedAt = val;
|
|
100
|
+
else if (key === 'reason')
|
|
101
|
+
period.reason = val;
|
|
102
|
+
}
|
|
103
|
+
return period;
|
|
104
|
+
}
|
|
105
|
+
function parseKeyResults(body) {
|
|
106
|
+
const lines = body.split('\n');
|
|
107
|
+
const items = [];
|
|
108
|
+
let currentL1 = null;
|
|
109
|
+
for (const line of lines) {
|
|
110
|
+
const l1 = parseL1(line);
|
|
111
|
+
if (l1) {
|
|
112
|
+
if (currentL1)
|
|
113
|
+
items.push(currentL1);
|
|
114
|
+
currentL1 = l1;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const l2 = parseL2(line);
|
|
118
|
+
if (l2 && currentL1) {
|
|
119
|
+
if (!currentL1.children)
|
|
120
|
+
currentL1.children = [];
|
|
121
|
+
currentL1.children.push(l2);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (currentL1)
|
|
125
|
+
items.push(currentL1);
|
|
126
|
+
return items;
|
|
127
|
+
}
|
|
128
|
+
function splitSections(content) {
|
|
129
|
+
const sections = new Map();
|
|
130
|
+
const parts = content.split(/^(?=##\s)/m);
|
|
131
|
+
for (const part of parts) {
|
|
132
|
+
const m = part.match(/^##\s+(.+)$/m);
|
|
133
|
+
if (!m)
|
|
134
|
+
continue;
|
|
135
|
+
const heading = m[1].trim();
|
|
136
|
+
const body = part.slice(m[0].length).trimStart();
|
|
137
|
+
sections.set(heading, body);
|
|
138
|
+
}
|
|
139
|
+
return sections;
|
|
140
|
+
}
|
|
141
|
+
function parseGoalMd(_goalId, raw) {
|
|
142
|
+
const { data: fm, content: body } = (0, gray_matter_1.default)(raw);
|
|
143
|
+
const frontmatter = {
|
|
144
|
+
type: fm.type,
|
|
145
|
+
description: fm.description,
|
|
146
|
+
notation: fm.notation,
|
|
147
|
+
};
|
|
148
|
+
// Extract H1 title
|
|
149
|
+
const h1Match = body.match(/^#\s+(.+)$/m);
|
|
150
|
+
const title = h1Match ? h1Match[1].trim() : '';
|
|
151
|
+
const sections = splitSections(body);
|
|
152
|
+
const period = parsePeriod(sections.get('Period') ?? '');
|
|
153
|
+
const objectiveBody = (sections.get('Objective') ?? '').trim();
|
|
154
|
+
const keyResults = parseKeyResults(sections.get('Key Results') ?? '');
|
|
155
|
+
const notes = (sections.get('Notes') ?? '').trim();
|
|
156
|
+
const reflection = (sections.get('Reflection') ?? '').trim();
|
|
157
|
+
return {
|
|
158
|
+
frontmatter,
|
|
159
|
+
title,
|
|
160
|
+
period,
|
|
161
|
+
objective: { body: objectiveBody },
|
|
162
|
+
keyResults,
|
|
163
|
+
notes,
|
|
164
|
+
reflection,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serializeGoalMd = serializeGoalMd;
|
|
4
|
+
const DEFAULT_FRONTMATTER = `---
|
|
5
|
+
type: goal
|
|
6
|
+
description: CrewX Goal — OKR
|
|
7
|
+
notation:
|
|
8
|
+
weight: "(w:N) — KR weight, default 1 if omitted"
|
|
9
|
+
auto: "N% auto — L1 progress auto-calculated as weighted average of children"
|
|
10
|
+
---`;
|
|
11
|
+
function computeWeightedAverage(children) {
|
|
12
|
+
let totalWeight = 0;
|
|
13
|
+
let weightedSum = 0;
|
|
14
|
+
for (const c of children) {
|
|
15
|
+
const w = c.weight ?? 1;
|
|
16
|
+
const p = c.counter
|
|
17
|
+
? Math.round((c.counter.current / c.counter.target) * 100)
|
|
18
|
+
: (c.progress ?? 0);
|
|
19
|
+
weightedSum += p * w;
|
|
20
|
+
totalWeight += w;
|
|
21
|
+
}
|
|
22
|
+
return totalWeight > 0 ? Math.round(weightedSum / totalWeight) : 0;
|
|
23
|
+
}
|
|
24
|
+
function serializeKRProgress(kr, isL1WithChildren, autoProgress) {
|
|
25
|
+
if (isL1WithChildren && autoProgress !== undefined) {
|
|
26
|
+
return ` — ${autoProgress}% auto`;
|
|
27
|
+
}
|
|
28
|
+
if (kr.counter) {
|
|
29
|
+
const pct = Math.round((kr.counter.current / kr.counter.target) * 100);
|
|
30
|
+
return ` — ${kr.counter.current}/${kr.counter.target} (${pct}%)`;
|
|
31
|
+
}
|
|
32
|
+
if (kr.progress !== undefined && kr.progress !== 0) {
|
|
33
|
+
return ` — ${kr.progress}%`;
|
|
34
|
+
}
|
|
35
|
+
if (kr.progress === 0) {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
function serializeWeight(weight) {
|
|
41
|
+
return weight !== 1 ? ` (w:${weight})` : '';
|
|
42
|
+
}
|
|
43
|
+
function serializeL2(child) {
|
|
44
|
+
const check = child.checked ? 'x' : ' ';
|
|
45
|
+
const progress = serializeKRProgress(child, false);
|
|
46
|
+
const weight = serializeWeight(child.weight ?? 1);
|
|
47
|
+
return ` - [${check}] ${child.text}${progress}${weight}`;
|
|
48
|
+
}
|
|
49
|
+
function serializeL1(kr) {
|
|
50
|
+
const lines = [];
|
|
51
|
+
const check = kr.checked ? 'x' : ' ';
|
|
52
|
+
const hasChildren = kr.children && kr.children.length > 0;
|
|
53
|
+
let autoProgress;
|
|
54
|
+
if (hasChildren) {
|
|
55
|
+
autoProgress = computeWeightedAverage(kr.children);
|
|
56
|
+
}
|
|
57
|
+
const progress = serializeKRProgress(kr, !!hasChildren, autoProgress);
|
|
58
|
+
const weight = serializeWeight(kr.weight ?? 1);
|
|
59
|
+
lines.push(`${kr.rank}. [${check}] ${kr.text}${progress}${weight}`);
|
|
60
|
+
if (kr.children) {
|
|
61
|
+
for (const child of kr.children) {
|
|
62
|
+
lines.push(serializeL2(child));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return lines;
|
|
66
|
+
}
|
|
67
|
+
function serializePeriod(period) {
|
|
68
|
+
const lines = [];
|
|
69
|
+
lines.push(`- Start: ${period.start}`);
|
|
70
|
+
lines.push(`- End: ${period.end}`);
|
|
71
|
+
lines.push(`- Status: ${period.status}`);
|
|
72
|
+
if (period.completedAt)
|
|
73
|
+
lines.push(`- Completed At: ${period.completedAt}`);
|
|
74
|
+
if (period.droppedAt)
|
|
75
|
+
lines.push(`- Dropped At: ${period.droppedAt}`);
|
|
76
|
+
if (period.reason)
|
|
77
|
+
lines.push(`- Reason: ${period.reason}`);
|
|
78
|
+
return lines;
|
|
79
|
+
}
|
|
80
|
+
function serializeGoalMd(parsed) {
|
|
81
|
+
const lines = [];
|
|
82
|
+
lines.push(DEFAULT_FRONTMATTER);
|
|
83
|
+
lines.push('');
|
|
84
|
+
lines.push(`# ${parsed.title}`);
|
|
85
|
+
lines.push('');
|
|
86
|
+
lines.push('## Period');
|
|
87
|
+
lines.push(...serializePeriod(parsed.period));
|
|
88
|
+
lines.push('');
|
|
89
|
+
lines.push('## Objective');
|
|
90
|
+
if (parsed.objective.body) {
|
|
91
|
+
lines.push(parsed.objective.body);
|
|
92
|
+
}
|
|
93
|
+
lines.push('');
|
|
94
|
+
lines.push('## Key Results');
|
|
95
|
+
for (const kr of parsed.keyResults) {
|
|
96
|
+
lines.push(...serializeL1(kr));
|
|
97
|
+
}
|
|
98
|
+
lines.push('');
|
|
99
|
+
lines.push('## Notes');
|
|
100
|
+
if (parsed.notes) {
|
|
101
|
+
lines.push(parsed.notes);
|
|
102
|
+
}
|
|
103
|
+
lines.push('');
|
|
104
|
+
lines.push('## Reflection');
|
|
105
|
+
if (parsed.reflection) {
|
|
106
|
+
lines.push(parsed.reflection);
|
|
107
|
+
}
|
|
108
|
+
lines.push('');
|
|
109
|
+
return lines.join('\n');
|
|
110
|
+
}
|
|
@@ -47,10 +47,18 @@ let MarketController = class MarketController {
|
|
|
47
47
|
this.marketService.deleteRegistry(id);
|
|
48
48
|
return { success: true };
|
|
49
49
|
}
|
|
50
|
+
async listAllMarketItems() {
|
|
51
|
+
const data = await this.marketService.listAllMarketItems();
|
|
52
|
+
return { success: true, data };
|
|
53
|
+
}
|
|
50
54
|
async listMarketItems(id) {
|
|
51
55
|
const data = await this.marketService.listMarketItems(id);
|
|
52
56
|
return { success: true, data };
|
|
53
57
|
}
|
|
58
|
+
async getRemoteSkillDetail(id, name) {
|
|
59
|
+
const data = await this.marketService.getRemoteSkillDetail(id, name);
|
|
60
|
+
return { success: true, data };
|
|
61
|
+
}
|
|
54
62
|
async installMarketItem(dto) {
|
|
55
63
|
const data = await this.marketService.installMarketItem(dto.registryId, dto.marketName);
|
|
56
64
|
return { success: true, data };
|
|
@@ -108,13 +116,29 @@ __decorate([
|
|
|
108
116
|
__metadata("design:returntype", void 0)
|
|
109
117
|
], MarketController.prototype, "deleteRegistry", null);
|
|
110
118
|
__decorate([
|
|
111
|
-
(0, swagger_1.ApiOperation)({ operationId: 'MKT.LIST', summary: 'List items
|
|
119
|
+
(0, swagger_1.ApiOperation)({ operationId: 'MKT.LIST', summary: 'List all market items across registries' }),
|
|
120
|
+
(0, common_1.Get)('items'),
|
|
121
|
+
__metadata("design:type", Function),
|
|
122
|
+
__metadata("design:paramtypes", []),
|
|
123
|
+
__metadata("design:returntype", Promise)
|
|
124
|
+
], MarketController.prototype, "listAllMarketItems", null);
|
|
125
|
+
__decorate([
|
|
126
|
+
(0, swagger_1.ApiOperation)({ operationId: 'MKT.LIST.REGISTRY', summary: 'List items in a registry' }),
|
|
112
127
|
(0, common_1.Get)('registries/:id/items'),
|
|
113
128
|
__param(0, (0, common_1.Param)('id')),
|
|
114
129
|
__metadata("design:type", Function),
|
|
115
130
|
__metadata("design:paramtypes", [String]),
|
|
116
131
|
__metadata("design:returntype", Promise)
|
|
117
132
|
], MarketController.prototype, "listMarketItems", null);
|
|
133
|
+
__decorate([
|
|
134
|
+
(0, swagger_1.ApiOperation)({ operationId: 'MKT.REMOTE.DETAIL', summary: 'Get remote skill detail (SKILL.md)' }),
|
|
135
|
+
(0, common_1.Get)('registries/:id/items/:name/detail'),
|
|
136
|
+
__param(0, (0, common_1.Param)('id')),
|
|
137
|
+
__param(1, (0, common_1.Param)('name')),
|
|
138
|
+
__metadata("design:type", Function),
|
|
139
|
+
__metadata("design:paramtypes", [String, String]),
|
|
140
|
+
__metadata("design:returntype", Promise)
|
|
141
|
+
], MarketController.prototype, "getRemoteSkillDetail", null);
|
|
118
142
|
__decorate([
|
|
119
143
|
(0, swagger_1.ApiOperation)({ operationId: 'MKT.INSTALL', summary: 'Install an item from registry' }),
|
|
120
144
|
(0, common_1.Post)('install'),
|