@hupan56/wlkj 2.0.0
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/bin/cli.js +213 -0
- package/package.json +11 -0
- package/templates/cli.js +198 -0
- package/templates/qoder/commands/wl-code.md +43 -0
- package/templates/qoder/commands/wl-commit.md +30 -0
- package/templates/qoder/commands/wl-init.md +80 -0
- package/templates/qoder/commands/wl-insight.md +51 -0
- package/templates/qoder/commands/wl-prd.md +199 -0
- package/templates/qoder/commands/wl-report.md +166 -0
- package/templates/qoder/commands/wl-search.md +52 -0
- package/templates/qoder/commands/wl-spec.md +18 -0
- package/templates/qoder/commands/wl-status.md +51 -0
- package/templates/qoder/commands/wl-task.md +71 -0
- package/templates/qoder/commands/wl-test.md +42 -0
- package/templates/qoder/config.toml +5 -0
- package/templates/qoder/config.yaml +141 -0
- package/templates/qoder/hooks/inject-workflow-state.py +117 -0
- package/templates/qoder/hooks/session-start.py +204 -0
- package/templates/qoder/rules/wl-pipeline.md +105 -0
- package/templates/qoder/scripts/add_session.py +245 -0
- package/templates/qoder/scripts/benchmark.py +209 -0
- package/templates/qoder/scripts/build_style_index.py +268 -0
- package/templates/qoder/scripts/code_index.py +41 -0
- package/templates/qoder/scripts/collect_prds.py +31 -0
- package/templates/qoder/scripts/common/__init__.py +0 -0
- package/templates/qoder/scripts/common/active_task.py +230 -0
- package/templates/qoder/scripts/common/atomicio.py +172 -0
- package/templates/qoder/scripts/common/developer.py +161 -0
- package/templates/qoder/scripts/common/eval_api.py +144 -0
- package/templates/qoder/scripts/common/feishu.py +278 -0
- package/templates/qoder/scripts/common/filelock.py +211 -0
- package/templates/qoder/scripts/common/identity.py +285 -0
- package/templates/qoder/scripts/common/mentions.py +134 -0
- package/templates/qoder/scripts/common/paths.py +311 -0
- package/templates/qoder/scripts/common/reqid.py +218 -0
- package/templates/qoder/scripts/common/search_engine.py +205 -0
- package/templates/qoder/scripts/common/task_utils.py +342 -0
- package/templates/qoder/scripts/common/terms.py +234 -0
- package/templates/qoder/scripts/common/utf8.py +38 -0
- package/templates/qoder/scripts/context_pack.py +196 -0
- package/templates/qoder/scripts/eval_prd.py +225 -0
- package/templates/qoder/scripts/export.py +487 -0
- package/templates/qoder/scripts/git_sync.py +1087 -0
- package/templates/qoder/scripts/handoff.py +22 -0
- package/templates/qoder/scripts/init_developer.py +76 -0
- package/templates/qoder/scripts/init_doctor.py +527 -0
- package/templates/qoder/scripts/install_qoderwork.py +339 -0
- package/templates/qoder/scripts/learn.py +67 -0
- package/templates/qoder/scripts/notify.py +5 -0
- package/templates/qoder/scripts/parse_prds.py +33 -0
- package/templates/qoder/scripts/report.py +281 -0
- package/templates/qoder/scripts/role.py +39 -0
- package/templates/qoder/scripts/run_weekly_update.bat +17 -0
- package/templates/qoder/scripts/run_weekly_update.sh +20 -0
- package/templates/qoder/scripts/search_index.py +352 -0
- package/templates/qoder/scripts/setup.py +453 -0
- package/templates/qoder/scripts/setup_weekly_cron.bat +22 -0
- package/templates/qoder/scripts/setup_weekly_cron.sh +19 -0
- package/templates/qoder/scripts/status.py +389 -0
- package/templates/qoder/scripts/syncgate.py +330 -0
- package/templates/qoder/scripts/task.py +954 -0
- package/templates/qoder/scripts/team.py +29 -0
- package/templates/qoder/scripts/team_sync.py +419 -0
- package/templates/qoder/scripts/workspace_init.py +102 -0
- package/templates/qoder/settings.json +53 -0
- package/templates/qoder/skills/design-review/SKILL.md +25 -0
- package/templates/qoder/skills/prd-generator/SKILL.md +180 -0
- package/templates/qoder/skills/prd-review/SKILL.md +36 -0
- package/templates/qoder/skills/prototype-generator/SKILL.md +141 -0
- package/templates/qoder/skills/spec-coder/SKILL.md +69 -0
- package/templates/qoder/skills/spec-generator/SKILL.md +67 -0
- package/templates/qoder/skills/test-generator/SKILL.md +72 -0
- package/templates/qoder/skills/wl-commit/SKILL.md +76 -0
- package/templates/qoder/skills/wl-init/SKILL.md +67 -0
- package/templates/qoder/skills/wl-insight/SKILL.md +81 -0
- package/templates/qoder/skills/wl-report/SKILL.md +87 -0
- package/templates/qoder/skills/wl-search/SKILL.md +75 -0
- package/templates/qoder/skills/wl-status/SKILL.md +61 -0
- package/templates/qoder/skills/wl-task/SKILL.md +58 -0
- package/templates/qoder/templates/prd-full-template.md +103 -0
- package/templates/qoder/templates/prd-quick-template.md +69 -0
- package/templates/qoder/templates/prototype-app.html +344 -0
- package/templates/qoder/templates/prototype-web.html +310 -0
- package/templates/root/AGENTS.md +182 -0
- package/templates/root/README-pipeline.md +56 -0
- package/templates/root/ROLES.md +85 -0
- package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +186 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
report.py - 工作日报/周报生成 + 飞书推送 (阶段 D3)
|
|
5
|
+
|
|
6
|
+
支撑 /wl-report 命令的数据生成。AI 执行 markdown 指令, 本脚本提供数据。
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python report.py daily # 生成今日日报 (打印)
|
|
10
|
+
python report.py weekly # 生成本周周报 (打印)
|
|
11
|
+
python report.py daily --push-feishu # 生成并推送到飞书
|
|
12
|
+
python report.py weekly --push-feishu
|
|
13
|
+
|
|
14
|
+
输出: 中文格式, 保存到 workspace/members/{dev}/journal/
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import os
|
|
19
|
+
import subprocess
|
|
20
|
+
import sys
|
|
21
|
+
from datetime import datetime, date, timedelta
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
26
|
+
except (AttributeError, TypeError, OSError):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
30
|
+
sys.path.insert(0, THIS_DIR)
|
|
31
|
+
from common.paths import get_repo_root, get_developer, get_tasks_dir
|
|
32
|
+
from common.task_utils import load_task_json
|
|
33
|
+
|
|
34
|
+
BASE = get_repo_root()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _ensure_developer():
|
|
38
|
+
"""必须有开发者身份。"""
|
|
39
|
+
dev = get_developer(BASE)
|
|
40
|
+
if not dev:
|
|
41
|
+
print('[ERROR] 未设置开发者身份。先跑 /wl-init 注册。', file=sys.stderr)
|
|
42
|
+
sys.exit(4)
|
|
43
|
+
return dev
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _git_commits(dev: str, since_date: str) -> list:
|
|
47
|
+
"""获取开发者指定日期后的 git 提交。"""
|
|
48
|
+
try:
|
|
49
|
+
r = subprocess.run(
|
|
50
|
+
['git', 'log', '--author', dev, '--since', since_date,
|
|
51
|
+
'--pretty=format:%h|%s|%ar', '--no-merges'],
|
|
52
|
+
capture_output=True, text=True, encoding='utf-8', errors='replace',
|
|
53
|
+
cwd=str(BASE),
|
|
54
|
+
)
|
|
55
|
+
if r.returncode != 0:
|
|
56
|
+
return []
|
|
57
|
+
commits = []
|
|
58
|
+
for line in r.stdout.strip().splitlines():
|
|
59
|
+
parts = line.split('|', 2)
|
|
60
|
+
if len(parts) == 3:
|
|
61
|
+
commits.append({'hash': parts[0], 'msg': parts[1], 'when': parts[2]})
|
|
62
|
+
return commits
|
|
63
|
+
except Exception:
|
|
64
|
+
return []
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _my_tasks(dev: str, statuses=None) -> list:
|
|
68
|
+
"""获取我的任务。"""
|
|
69
|
+
tasks_dir = get_tasks_dir(BASE)
|
|
70
|
+
if not tasks_dir.is_dir():
|
|
71
|
+
return []
|
|
72
|
+
out = []
|
|
73
|
+
for d in tasks_dir.iterdir():
|
|
74
|
+
if not d.is_dir():
|
|
75
|
+
continue
|
|
76
|
+
data = load_task_json(d)
|
|
77
|
+
if not data:
|
|
78
|
+
continue
|
|
79
|
+
if dev not in (data.get('assignee'), data.get('creator')):
|
|
80
|
+
continue
|
|
81
|
+
if statuses and data.get('status') not in statuses:
|
|
82
|
+
continue
|
|
83
|
+
out.append({'name': d.name, 'data': data})
|
|
84
|
+
return out
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _finished_today(dev: str) -> list:
|
|
88
|
+
"""今天完成的任务 (从 stage_ts.completed 判断)。"""
|
|
89
|
+
today_str = date.today().isoformat()
|
|
90
|
+
out = []
|
|
91
|
+
tasks_dir = get_tasks_dir(BASE)
|
|
92
|
+
# 也查归档 (今天 finish 的会归档)
|
|
93
|
+
archive_dir = BASE / '.qoder' / 'archive'
|
|
94
|
+
search_dirs = [tasks_dir, archive_dir] if archive_dir.is_dir() else [tasks_dir]
|
|
95
|
+
for sd in search_dirs:
|
|
96
|
+
if not sd.is_dir():
|
|
97
|
+
continue
|
|
98
|
+
for d in sd.iterdir():
|
|
99
|
+
if not d.is_dir():
|
|
100
|
+
continue
|
|
101
|
+
data = load_task_json(d)
|
|
102
|
+
if not data:
|
|
103
|
+
continue
|
|
104
|
+
if dev not in (data.get('assignee'), data.get('creator')):
|
|
105
|
+
continue
|
|
106
|
+
completed_ts = (data.get('stage_ts') or {}).get('completed') or data.get('updated_at', '')
|
|
107
|
+
if completed_ts.startswith(today_str):
|
|
108
|
+
out.append({'name': d.name, 'data': data})
|
|
109
|
+
return out
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def generate_daily(dev: str) -> str:
|
|
113
|
+
"""生成日报 markdown。"""
|
|
114
|
+
today = date.today().isoformat()
|
|
115
|
+
commits = _git_commits(dev, today)
|
|
116
|
+
finished = _finished_today(dev)
|
|
117
|
+
in_progress = _my_tasks(dev, statuses=['in_progress'])
|
|
118
|
+
planning = _my_tasks(dev, statuses=['planning'])
|
|
119
|
+
|
|
120
|
+
lines = [
|
|
121
|
+
f'# 工作日报 - {dev} - {today}',
|
|
122
|
+
'',
|
|
123
|
+
'## 今日完成',
|
|
124
|
+
]
|
|
125
|
+
if finished:
|
|
126
|
+
for t in finished:
|
|
127
|
+
title = t['data'].get('title', t['name'])
|
|
128
|
+
lines.append(f'- [{t["name"]}] {title}')
|
|
129
|
+
elif commits:
|
|
130
|
+
# 无 finish 任务但有提交
|
|
131
|
+
seen = set()
|
|
132
|
+
for c in commits:
|
|
133
|
+
msg = c['msg']
|
|
134
|
+
if msg not in seen:
|
|
135
|
+
lines.append(f'- {msg} ({c["hash"]})')
|
|
136
|
+
seen.add(msg)
|
|
137
|
+
else:
|
|
138
|
+
lines.append('- (今日无完成任务或提交)')
|
|
139
|
+
|
|
140
|
+
lines.extend(['', '## 进行中'])
|
|
141
|
+
if in_progress:
|
|
142
|
+
for t in in_progress:
|
|
143
|
+
title = t['data'].get('title', t['name'])
|
|
144
|
+
due = t['data'].get('due_date', '')
|
|
145
|
+
due_str = f' (截止 {due})' if due else ''
|
|
146
|
+
lines.append(f'- [{t["name"]}] {title}{due_str}')
|
|
147
|
+
else:
|
|
148
|
+
lines.append('- (无)')
|
|
149
|
+
|
|
150
|
+
lines.extend(['', '## 明日计划'])
|
|
151
|
+
if planning:
|
|
152
|
+
for t in planning[:3]:
|
|
153
|
+
title = t['data'].get('title', t['name'])
|
|
154
|
+
lines.append(f'- [{t["name"]}] {title}')
|
|
155
|
+
elif in_progress:
|
|
156
|
+
lines.append('- (继续进行中的任务)')
|
|
157
|
+
else:
|
|
158
|
+
lines.append('- (待规划)')
|
|
159
|
+
|
|
160
|
+
lines.extend(['', f'## 提交统计', f'- 今日提交: {len(commits)} 次'])
|
|
161
|
+
|
|
162
|
+
return '\n'.join(lines)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def generate_weekly(dev: str) -> str:
|
|
166
|
+
"""生成周报 markdown。"""
|
|
167
|
+
# 周一为起点
|
|
168
|
+
today = date.today()
|
|
169
|
+
monday = today - timedelta(days=today.weekday())
|
|
170
|
+
week_str = f'{monday.isoformat()} ~ {today.isoformat()}'
|
|
171
|
+
since = monday.isoformat()
|
|
172
|
+
|
|
173
|
+
commits = _git_commits(dev, since)
|
|
174
|
+
finished = _finished_this_week(dev, since)
|
|
175
|
+
in_progress = _my_tasks(dev, statuses=['in_progress'])
|
|
176
|
+
|
|
177
|
+
lines = [
|
|
178
|
+
f'# 周报 - {dev} - {week_str}',
|
|
179
|
+
'',
|
|
180
|
+
'## 本周完成',
|
|
181
|
+
]
|
|
182
|
+
if finished:
|
|
183
|
+
for t in finished:
|
|
184
|
+
title = t['data'].get('title', t['name'])
|
|
185
|
+
lines.append(f'- [{t["name"]}] {title}')
|
|
186
|
+
else:
|
|
187
|
+
lines.append('- (本周无完成任务)')
|
|
188
|
+
|
|
189
|
+
lines.extend([
|
|
190
|
+
'', '## 关键产出',
|
|
191
|
+
f'- 提交数: {len(commits)} 次',
|
|
192
|
+
])
|
|
193
|
+
# 提取 REQ/PRD 相关提交
|
|
194
|
+
prd_commits = [c for c in commits if 'REQ-' in c['msg'].upper() or 'PRD' in c['msg'].upper()]
|
|
195
|
+
if prd_commits:
|
|
196
|
+
lines.append(f'- PRD 相关提交: {len(prd_commits)} 次')
|
|
197
|
+
|
|
198
|
+
lines.extend(['', '## 进行中'])
|
|
199
|
+
if in_progress:
|
|
200
|
+
for t in in_progress:
|
|
201
|
+
title = t['data'].get('title', t['name'])
|
|
202
|
+
lines.append(f'- [{t["name"]}] {title}')
|
|
203
|
+
else:
|
|
204
|
+
lines.append('- (无)')
|
|
205
|
+
|
|
206
|
+
lines.extend(['', '## 下周计划', '- (待规划)'])
|
|
207
|
+
|
|
208
|
+
return '\n'.join(lines)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _finished_this_week(dev: str, since: str) -> list:
|
|
212
|
+
"""本周完成的任务。"""
|
|
213
|
+
out = []
|
|
214
|
+
tasks_dir = get_tasks_dir(BASE)
|
|
215
|
+
archive_dir = BASE / '.qoder' / 'archive'
|
|
216
|
+
search_dirs = [tasks_dir, archive_dir] if archive_dir.is_dir() else [tasks_dir]
|
|
217
|
+
for sd in search_dirs:
|
|
218
|
+
if not sd.is_dir():
|
|
219
|
+
continue
|
|
220
|
+
for d in sd.iterdir():
|
|
221
|
+
if not d.is_dir():
|
|
222
|
+
continue
|
|
223
|
+
data = load_task_json(d)
|
|
224
|
+
if not data:
|
|
225
|
+
continue
|
|
226
|
+
if dev not in (data.get('assignee'), data.get('creator')):
|
|
227
|
+
continue
|
|
228
|
+
completed_ts = (data.get('stage_ts') or {}).get('completed') or data.get('updated_at', '')
|
|
229
|
+
if completed_ts >= since and data.get('status') == 'completed':
|
|
230
|
+
out.append({'name': d.name, 'data': data})
|
|
231
|
+
return out
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def save_and_maybe_push(content: str, mode: str, push_feishu: bool):
|
|
235
|
+
"""保存报告到 journal 目录, 可选推送飞书。"""
|
|
236
|
+
dev = get_developer(BASE)
|
|
237
|
+
journal_dir = BASE / 'workspace' / 'members' / dev / 'journal'
|
|
238
|
+
journal_dir.mkdir(parents=True, exist_ok=True)
|
|
239
|
+
|
|
240
|
+
today = date.today().isoformat()
|
|
241
|
+
filename = f'{today}-{mode}.md'
|
|
242
|
+
out_path = journal_dir / filename
|
|
243
|
+
out_path.write_text(content, encoding='utf-8')
|
|
244
|
+
print(f'报告已保存: workspace/members/{dev}/journal/{filename}')
|
|
245
|
+
print('---')
|
|
246
|
+
print(content)
|
|
247
|
+
|
|
248
|
+
if push_feishu:
|
|
249
|
+
try:
|
|
250
|
+
from common.feishu import send_card, is_enabled
|
|
251
|
+
if is_enabled():
|
|
252
|
+
# 报告作为长文本卡片推送
|
|
253
|
+
title = f'{dev} 的{"周报" if mode == "weekly" else "日报"} - {today}'
|
|
254
|
+
# 飞书卡片内容截断 (避免过长)
|
|
255
|
+
content_short = content[:2000] + ('\n...(截断)' if len(content) > 2000 else '')
|
|
256
|
+
send_card(title, [content_short], event_type=None, theme='blue')
|
|
257
|
+
print('\n[feishu] 报告已推送到飞书群')
|
|
258
|
+
else:
|
|
259
|
+
print('\n[feishu] 未启用, 跳过推送 (在 config.yaml 设 feishu.enabled: true)')
|
|
260
|
+
except Exception as e:
|
|
261
|
+
print(f'\n[feishu] 推送失败 (不影响报告): {e}')
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def main():
|
|
265
|
+
parser = argparse.ArgumentParser(description='工作日报/周报生成')
|
|
266
|
+
parser.add_argument('mode', choices=['daily', 'weekly'], help='日报 or 周报')
|
|
267
|
+
parser.add_argument('--push-feishu', action='store_true', help='推送到飞书群')
|
|
268
|
+
args = parser.parse_args()
|
|
269
|
+
|
|
270
|
+
dev = _ensure_developer()
|
|
271
|
+
|
|
272
|
+
if args.mode == 'daily':
|
|
273
|
+
content = generate_daily(dev)
|
|
274
|
+
else:
|
|
275
|
+
content = generate_weekly(dev)
|
|
276
|
+
|
|
277
|
+
save_and_maybe_push(content, args.mode, args.push_feishu)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
if __name__ == '__main__':
|
|
281
|
+
main()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# role.py - Resolve role from member info
|
|
2
|
+
import os, json, sys
|
|
3
|
+
|
|
4
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
5
|
+
from common.paths import get_developer, get_developer_info
|
|
6
|
+
|
|
7
|
+
BASE = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
8
|
+
|
|
9
|
+
def get_role(name=None):
|
|
10
|
+
if not name:
|
|
11
|
+
# Prefer role recorded directly in .developer
|
|
12
|
+
info = get_developer_info()
|
|
13
|
+
if info and info.get('role'):
|
|
14
|
+
return info['role']
|
|
15
|
+
name = get_developer()
|
|
16
|
+
if not name:
|
|
17
|
+
return None
|
|
18
|
+
mf = os.path.join(BASE, 'workspace', 'members', name, 'member.json')
|
|
19
|
+
if os.path.isfile(mf):
|
|
20
|
+
try:
|
|
21
|
+
with open(mf, encoding='utf-8') as f:
|
|
22
|
+
return json.load(f).get('role')
|
|
23
|
+
except (OSError, json.JSONDecodeError):
|
|
24
|
+
return None
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
def get_permissions(role):
|
|
28
|
+
import yaml
|
|
29
|
+
cfg = os.path.join(BASE, '.qoder', 'config.yaml')
|
|
30
|
+
if not os.path.isfile(cfg):
|
|
31
|
+
return []
|
|
32
|
+
try:
|
|
33
|
+
with open(cfg, encoding='utf-8') as f:
|
|
34
|
+
config = yaml.safe_load(f) or {}
|
|
35
|
+
except (OSError, yaml.YAMLError):
|
|
36
|
+
return []
|
|
37
|
+
roles = config.get('roles', {})
|
|
38
|
+
r = roles.get(role, {})
|
|
39
|
+
return r.get('permissions', [])
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM QODER Weekly Knowledge Graph Update
|
|
3
|
+
REM Runs every Friday at 18:00
|
|
4
|
+
REM %~dp0 = this script directory; project root is two levels up
|
|
5
|
+
|
|
6
|
+
cd /d "%~dp0..\.."
|
|
7
|
+
|
|
8
|
+
echo [%date% %time%] Starting weekly update... >> .qoder\logs\weekly-update.log
|
|
9
|
+
|
|
10
|
+
REM Step 1: Git pull + PRD collect + Index rebuild
|
|
11
|
+
python .qoder\scripts\git_sync.py >> .qoder\logs\weekly-update.log 2>&1
|
|
12
|
+
|
|
13
|
+
if errorlevel 1 (
|
|
14
|
+
echo [%date% %time%] UPDATE FAILED - check log above >> .qoder\logs\weekly-update.log
|
|
15
|
+
) else (
|
|
16
|
+
echo [%date% %time%] Update complete. >> .qoder\logs\weekly-update.log
|
|
17
|
+
)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# QODER Weekly Knowledge Graph Update (macOS / Linux)
|
|
3
|
+
# Runs every Friday at 18:00 via cron (see setup_weekly_cron.sh)
|
|
4
|
+
set -u
|
|
5
|
+
cd "$(dirname "$0")/../.." || exit 1
|
|
6
|
+
|
|
7
|
+
mkdir -p .qoder/logs
|
|
8
|
+
LOG=.qoder/logs/weekly-update.log
|
|
9
|
+
|
|
10
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting weekly update..." >> "$LOG"
|
|
11
|
+
|
|
12
|
+
python3 .qoder/scripts/git_sync.py >> "$LOG" 2>&1
|
|
13
|
+
STATUS=$?
|
|
14
|
+
|
|
15
|
+
if [ $STATUS -ne 0 ]; then
|
|
16
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] UPDATE FAILED (exit $STATUS) - check log above" >> "$LOG"
|
|
17
|
+
else
|
|
18
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Update complete." >> "$LOG"
|
|
19
|
+
fi
|
|
20
|
+
exit $STATUS
|