diff --git a/.claude/scheduled_tasks.json b/.claude/scheduled_tasks.json new file mode 100644 index 0000000..850eef8 --- /dev/null +++ b/.claude/scheduled_tasks.json @@ -0,0 +1,11 @@ +{ + "tasks": [ + { + "id": "d572d1d5", + "cron": "30 10 * * *", + "prompt": "Run the daily git sync script at D:/fork_project/obsidian-notes/git_sync_daily.ps1. Execute: pwsh -ExecutionPolicy Bypass -File \"D:/fork_project/obsidian-notes/git_sync_daily.ps1\"", + "createdAt": 1777459843227, + "recurring": true + } + ] +} diff --git a/.claude/scheduled_tasks.lock b/.claude/scheduled_tasks.lock new file mode 100644 index 0000000..0d45975 --- /dev/null +++ b/.claude/scheduled_tasks.lock @@ -0,0 +1 @@ +{"sessionId":"1edcf1ba-95d0-4aa3-b979-c6be03a8dec5","pid":37752,"acquiredAt":1777459843947} \ No newline at end of file diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..49b14f7 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(python -c \"import graphify; print\\('installed'\\)\")", + "Bash(python -c ':*)", + "Bash(python)" + ] + } +} diff --git a/.gitignore b/.gitignore index a94f168..2be711a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ Thumbs.db $RECYCLE.BIN/ # Windows shortcuts -*.lnk \ No newline at end of file +*.lnk +.obsidian/workspace.json diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json deleted file mode 100644 index 6509ed6..0000000 --- a/.obsidian/workspace.json +++ /dev/null @@ -1,264 +0,0 @@ -{ - "main": { - "id": "c01acc1e0c3642a1", - "type": "split", - "children": [ - { - "id": "4463cbe9dee439a2", - "type": "tabs", - "children": [ - { - "id": "bf4a47cd3f5340ef", - "type": "leaf", - "state": { - "type": "markdown", - "state": { - "file": "1Project/大富翁Demo/关于AI/离全自动发起PR有多远.md", - "mode": "source", - "source": false, - "backlinks": true, - "backlinkOpts": { - "collapseAll": false, - "extraContext": false, - "sortOrder": "alphabetical", - "showSearch": false, - "searchQuery": "", - "backlinkCollapsed": false, - "unlinkedCollapsed": true - } - }, - "icon": "lucide-file", - "title": "离全自动发起PR有多远" - } - } - ] - } - ], - "direction": "vertical" - }, - "left": { - "id": "b3f2fe956c600b2b", - "type": "split", - "children": [ - { - "id": "b892947aee3a10a9", - "type": "tabs", - "children": [ - { - "id": "f2ac97a7addb8678", - "type": "leaf", - "state": { - "type": "file-explorer", - "state": { - "sortOrder": "alphabetical", - "autoReveal": false - }, - "icon": "lucide-folder-closed", - "title": "文件列表" - } - }, - { - "id": "bd33cd6e5600118d", - "type": "leaf", - "state": { - "type": "search", - "state": { - "query": "", - "matchingCase": false, - "explainSearch": false, - "collapseAll": false, - "extraContext": false, - "sortOrder": "alphabetical" - }, - "icon": "lucide-search", - "title": "搜索" - } - }, - { - "id": "8c8dfe109a7f116f", - "type": "leaf", - "state": { - "type": "bookmarks", - "state": {}, - "icon": "lucide-bookmark", - "title": "书签" - } - }, - { - "id": "4c191f6555b427bd", - "type": "leaf", - "state": { - "type": "file-explorer", - "state": { - "sortOrder": "alphabetical", - "autoReveal": false - }, - "icon": "lucide-folder-closed", - "title": "文件列表" - } - } - ] - } - ], - "direction": "horizontal", - "width": 401.5 - }, - "right": { - "id": "d809b577c235ae94", - "type": "split", - "children": [ - { - "id": "c6a04719e9395783", - "type": "tabs", - "children": [ - { - "id": "a0097fbc2c860370", - "type": "leaf", - "state": { - "type": "backlink", - "state": { - "file": "4Archives/归档-目录.md", - "collapseAll": false, - "extraContext": false, - "sortOrder": "alphabetical", - "showSearch": false, - "searchQuery": "", - "backlinkCollapsed": false, - "unlinkedCollapsed": true - }, - "icon": "links-coming-in", - "title": "归档-目录 的反向链接列表" - } - }, - { - "id": "d6423d1f79769c25", - "type": "leaf", - "state": { - "type": "outgoing-link", - "state": { - "file": "4Archives/归档-目录.md", - "linksCollapsed": false, - "unlinkedCollapsed": true - }, - "icon": "links-going-out", - "title": "归档-目录 的出链列表" - } - }, - { - "id": "009d8bcaab15bbb9", - "type": "leaf", - "state": { - "type": "tag", - "state": { - "sortOrder": "frequency", - "useHierarchy": true, - "showSearch": false, - "searchQuery": "" - }, - "icon": "lucide-tags", - "title": "标签" - } - }, - { - "id": "11a36b370174df61", - "type": "leaf", - "state": { - "type": "outline", - "state": { - "file": "4Archives/归档-目录.md", - "followCursor": false, - "showSearch": false, - "searchQuery": "" - }, - "icon": "lucide-list", - "title": "归档-目录 的大纲" - } - }, - { - "id": "4a0e6c346bdcec3c", - "type": "leaf", - "state": { - "type": "calendar", - "state": {}, - "icon": "calendar-with-checkmark", - "title": "Calendar" - } - } - ] - } - ], - "direction": "horizontal", - "width": 408.5, - "collapsed": true - }, - "left-ribbon": { - "hiddenItems": { - "bases:新建数据库": false, - "switcher:打开快速切换": false, - "graph:查看关系图谱": false, - "canvas:新建白板": false, - "templates:插入模板": false, - "command-palette:打开命令面板": false, - "copilot:Open Copilot Chat": false - } - }, - "active": "bf4a47cd3f5340ef", - "lastOpenFiles": [ - "1Project/大富翁Demo/关于AI/护栏与AI.md", - "1Project/大富翁Demo/关于AI/离全自动发起PR有多远.md", - "笔记数据库.base", - "1Project/大富翁Demo/关于AI", - "1Project/大富翁Demo", - "未命名 1.base", - "未命名.base", - "卡片数据库.base", - "卡片盒skill.md", - "查询数据skill.md", - "00-Home.md", - "copilot-custom-prompts/Remove URLs.md", - "copilot-custom-prompts/Make shorter.md", - "copilot-custom-prompts/Explain like I am 5.md", - "copilot-custom-prompts/Emojify.md", - "1Project/GPU地形/地形优化.md", - "1Project/理财.md", - "1Project/GPU地形/Houdini PCG.md", - "1Project/GPU地形/GPU地形-目录.md", - "1Project/GPU地形/GPU Driven Terrain 跟学与实现.md", - "1Project/GPU地形/ComputeShader生成无限世界地形.md", - "1Project/海量渲染战斗/批量渲染gpu动画.md", - "1Project/外包/Project_城堡/_城堡.md", - "1Project/海量渲染战斗/基于GPU蒙皮动画的Spine实现.md", - "1Project/海量渲染战斗/基于GPU动画和ComputeShader的大批量动画渲染Demo(一)之GPU顶点动画.md", - "1Project/海量渲染战斗/海量渲染战斗-目录.md", - "1Project/海量渲染战斗/GPU动画工程/TODO转为Job组织数据.md", - "1Project/海量渲染战斗/GPU动画工程/TODO将Time存进buffer中,做成不同的实例可以使用不同的动画时间.md", - "1Project/海量渲染战斗/GPU动画工程/TODO不同动作存进Buffer中.md", - "1Project/海量渲染战斗/GPU动画工程/TODO 不同动作间的混合.md", - "1Project/海量渲染战斗/GPU动画工程/GPU蒙皮动画.md", - "1Project/海量渲染战斗/GPU动画工程/GPU顶点动画.md", - "skills/obsidian-markdown", - "skills/obsidian-bases", - "skills/json-canvas", - "skills", - "渲染/软渲染/图片/9702b7cbafa93d6e3d0cd59e7cf37e31.png", - "渲染/软渲染/图片/86aa46af36c4c3b1f1efef2a1ccc6310.png", - "渲染/软渲染/图片/62ad22d3e981954fc083018fb850413a.png", - "渲染/软渲染/图片/23d61a2b7376ea3149d74d6bd4ea9430.png", - "wallhaven-rq75r7.jpg", - "1Project/构建新框架/管道模式/未命名.canvas", - "2Areas/如何记录笔记/P.A.R.A/Pasted image 20250614192838.png", - "1Project/战斗编辑器/随想/动作时间轴 随想.canvas", - "2Areas/开发感悟/管道模式/未命名.canvas", - "1Project/宠物宇宙/地图编辑器/地图工作流.canvas", - "InBox/编辑器/时间轴编辑器/Timeline TODO.canvas", - "InBox/编辑器/图片/Pasted image 20221025121100.png", - "渲染/软渲染/图片/img_v3_02n6_ff40a1a4-d813-45f7-b132-6f14a74cfd7g.jpg", - "InBox/TODO.canvas", - "渲染/软渲染/图片/Pasted image 20250609171235.png", - "InBox/渲染/GPU/Pasted image 20230413163234.png", - "未命名 1.canvas", - "并行计算/GPU.canvas", - "并行计算/CPU.canvas", - "未命名 2.canvas" - ] -} \ No newline at end of file diff --git a/InBox/Hermes编排Agent_Web可观测性方案.md b/1Project/AI工程/agent工作流编排/Hermes编排Agent_Web可观测性方案.md similarity index 100% rename from InBox/Hermes编排Agent_Web可观测性方案.md rename to 1Project/AI工程/agent工作流编排/Hermes编排Agent_Web可观测性方案.md diff --git a/3Resources/AI/AutoHarness-论文解读.md b/3Resources/AI/AutoHarness-论文解读.md index 9e703c1..5ee830b 100644 --- a/3Resources/AI/AutoHarness-论文解读.md +++ b/3Resources/AI/AutoHarness-论文解读.md @@ -1,14 +1,13 @@ --- 原文发布链接: https://zhuanlan.zhihu.com/p/2016839356833341880 tags: - - AutoHarness - AI - 论文解读 - - AutoHerness - LLM - Agent - ProgramSynthesis - GRPO强化学习 + - harness --- ## 一句话总结 diff --git a/InBox/Harness Engineering最佳实践_深度解析AgentHamness的底层原理_核心组件和实战应用 学不会我_BV1Hn9UBrEsH_P1_笔记.md b/3Resources/AI/Harness Engineering最佳实践_深度解析AgentHamness的底层原理_核心组件和实战应用 学不会我_BV1Hn9UBrEsH_P1_笔记.md similarity index 99% rename from InBox/Harness Engineering最佳实践_深度解析AgentHamness的底层原理_核心组件和实战应用 学不会我_BV1Hn9UBrEsH_P1_笔记.md rename to 3Resources/AI/Harness Engineering最佳实践_深度解析AgentHamness的底层原理_核心组件和实战应用 学不会我_BV1Hn9UBrEsH_P1_笔记.md index 1211b26..8748223 100644 --- a/InBox/Harness Engineering最佳实践_深度解析AgentHamness的底层原理_核心组件和实战应用 学不会我_BV1Hn9UBrEsH_P1_笔记.md +++ b/3Resources/AI/Harness Engineering最佳实践_深度解析AgentHamness的底层原理_核心组件和实战应用 学不会我_BV1Hn9UBrEsH_P1_笔记.md @@ -1,3 +1,9 @@ +--- +tags: + - harness +--- + + # Harness Engineering 最佳实践:Agent Harness 底层原理、核心组件与实战应用 ## 目录 diff --git a/InBox/让AI真正读懂证据间的因果_深度验证框架解决逻辑断层_实现92.0_平衡准确率_BV1p9QnBtEMq_笔记.md b/3Resources/AI/让AI真正读懂证据间的因果_深度验证框架解决逻辑断层_实现92.0_平衡准确率_BV1p9QnBtEMq_笔记.md similarity index 100% rename from InBox/让AI真正读懂证据间的因果_深度验证框架解决逻辑断层_实现92.0_平衡准确率_BV1p9QnBtEMq_笔记.md rename to 3Resources/AI/让AI真正读懂证据间的因果_深度验证框架解决逻辑断层_实现92.0_平衡准确率_BV1p9QnBtEMq_笔记.md diff --git a/InBox/Karpathy_harness_llm_wiki.md b/InBox/Karpathy_harness_llm_wiki.md deleted file mode 100644 index fd81245..0000000 --- a/InBox/Karpathy_harness_llm_wiki.md +++ /dev/null @@ -1,114 +0,0 @@ -# Karpathy用「harness」彻底终结了RAG - -> 来源: https://mp.weixin.qq.com/s/ABzwrSGeFs1Wv2RUBjLtwg -> 抓取时间: 2025-04-10 - ---- - -假期的时候,Karpathy 大神发了一个llm.wiki的想法。 这条推文火爆了。 - -在LLM Agent时代,分享具体代码或应用的意义正在变弱,现在只需要分享想法,然后把它交给 Claude、Grok 等 Agent,它就可以根据你的需求,自动搭建一个属于你自己的个人知识库。 - -还有最近特别火的各种 personal skill ,同事.skill、前任.skill、自己的skill,甚至卡兹克把自己的创作skills都开源了。。。。 - -整体看下来我觉得它们都在做一件事情:把现实世界里原本只能"看"的东西,编译成 AI 可以持续操作的东西。 - -llm.wiki 在编译知识。创作 skill 编译方法论。persona skill 编译人格。 - -全网的博主都在分享理论。今天我们分享一下如何能跑通这种知识的编译。 - -llm.wiki这套理论虽然看起来就是又一次渐进式披露的实践。 - -但是很多人觉着,这不只是一个 AI 工具,而更像是一种元框架(meta-framework)。它并不依赖某个具体模型或技术栈,而是在尝试定义一种人类与 AI 协作管理知识的方式。随着模型不断迭代、框架持续演进,让 LLM 帮助编译并维护一个持续生长的 Wiki 这一模式,反而具备更长期的稳定性和适用性。 - -## 所以llm.wiki在干什么? - -过去,大模型使用文档,都是用RAG。问一个要综合五份文档的问题,模型每次都要重新找、重新拼。没有积累。NotebookLM、ChatGPT 的文件上传,其实都是这个模式。 - -但是llm.wiki的模式是: 你丢一份新材料进去,模型不是索引它等着以后检索,而是立刻读它、提炼它、把关键信息编入已有的 wiki。更新实体页、修订概念页、标注新旧数据的矛盾。一份材料可能触及十几个 wiki 页面。 - -而且知识编译一次,然后持续维护。不是每次都从头来。 - -这个模式其实非常有意思,不止可以用在建个人wiki场景,还可以往很多场景拓展,比如记忆。 - -karpathy大佬举了一些场景case,如下图,也很实用。尤其是今天的ai发展的这么快。前脚龙虾,后脚就hermes。上个月的harness,可能这个月就要拆掉一些了。 这种知识的管理。不论是对个人,还是对自己的agent系统都非常重要。 - -正常情况下,如果想打通这种自动wiki工作流,很容易遇到各种奇形怪状的数据。但是llm.wiki 这些,都假设数据是干净的markdown,这还还挺不符合实际场景的。 - -所以,我找了一批更符合真实场景的数据,但是也没有精挑细选。主要是Anthropic、OpenAI关于harness的博客。还有新模型mythos的博客、智谱glm5.1的博客、以及智谱的招股书(本来准备下载财报的,好像下错了,不过这个500多页pdf,也有很多复杂的图表)。 - -然后就可以开始按照llm wiki的要求3层架构构建了。 - -把llm.wiki丢给agent,会自动构建好目录结构。 我用的 cursor + opus 4.6。raw 放原始材料,wiki 放 AI 维护的知识中间层,AGENTS.md 告诉 AI 这个 wiki 怎么组织。 - -整体的一个壳子大概长下面这个样子。 - -然后第一道坎就来了。 - -如果你的实际数据不是规整的txt,或者markdown,ai用pdfplumber转成的markdown就会变成这个样子。文字换行、缩进、表格、图片,这些都没法保留,甚至可能混乱。 - -不管是简单的博客,还是复杂的文档,解析成这个样子其实对模型都特别不友好。 - -还好我用的opus 4.6,对这些东西会鲁棒一些,如果用国产平替估计影响就比较大了。 - -但是。正好,我们最近有一些业务涉及到复杂的word格式文档处理,订阅了合合信息 TextIn 的 API,所以我顺手做了个对比。 - -比如,这是TextIn转写的博客结果,图片和格式排版这些都有保留。 - -TextIn对表格的表示用的是用的html形式的,所以它可以表示更复杂的无线表、合并单元格这些。 - -可以看下图。在招股书的解析里边,图表的结果也非常的不错。 - -最后,还附上TextIn api的耗时参考。目前,这套解析,在我们现在内部的一个业务上跑的还不错。可以在这里测试TextIn的解析:https://cc.co/16YSdj - -搞定预编译之后,开始走 ingest 流程。这里有一个很蠢的坑,模型喜欢偷懒,一次性看一点文档,然后ingest很多的文档。 - -结果每份材料都是浅读,生成的 wiki 页面跟目录没什么区别。信息密度极低。 - -所以这里我优化了一下默认的AGENTS.md,让它一份份处理,超过的还要分段来处理。 - -这个小优化会带来比较明显的数据处理质量的提升。 - -10 份材料全部 ingest 完之后,结构是这样的: - -大概的一个流程是,解析->然后模型会按照AGENTS.md 梳理每份内容的要点,文档要点示例如下: - -然后会整理出实体、概念。 以下是二者的示例。都会有明确的跟其他文件的link关系。 - -concept之间还会自动构建起对比,comparisons示例: - -最后,从结果来看,因为我已经用了最顶级的Opus4.6模型了,所以不论是不是最好的解析方式。 - -带来的wiki结构密度其实差异不大。但是信息密度差异比较大。用TextIn API解析的数据可以保留更多的原始信息,让整个库的信息密度更高。 - -所有有考虑搭建这种自动更新wiki的同学,可以考虑,尽量用最好的解析策略。 - -接下来就可以看出来这种关联wiki的魅力了。 - -比如Harness,我放了4篇博客,包含Ralph Wiggum的反对多Agent的博客,以及OpenAI、Anthropic的相关博客。 - -这样,在Agent Harness概念页就出现了同时容纳了正反两方的观点,还用表格对比了两种流派的差异。 - -这种跨文档的交叉引用和矛盾标注,RAG 是做不到的。RAG 能从单份文档里检索片段,但它不会主动发现两个人其实在用不同方式解决同一个问题。但是通过这种模式,构建的wiki 它就全都懂了。 - -或者需要结合多个跨文档综合的问题。比如「智谱跟 Anthropic 的商业化策略有什么不同」。 - -Agent就可以依据信息的链接跳转,自动的去探索需要的信息,找到最终的答案了。 - -而传统的利用单文档的longcontext chatbot 或者 RAG,其实很难做这些事情。但是wiki已经把他们编译好了。 - -## 写在最后 - -坦率的讲,跑完整个流程之后我有一个很强的感受。 - -llm.wiki 这个模式从理论上肯定是跑得通的。你在里面能看到 GraphRAG 的影子,能看到 Skills 的影子,能看到 Context Engineering 的影子。这些东西换了不同的名字,但做的事情有很大的重叠。 - -而在 Harness Engineering 爆火的今天,llm.wiki 其实又是在强调,过去那些手动维护知识库的包袱,可以扔了。一整套编译工作,交给模型就行。 - -但一个东西没变。 - -garbage in, garbage out。今天依然成立。 - -解析,仍然是很多项目真正的卡点。如果你现在还在被这个问题困扰,可以试试 TextIn,地址在这里:https://cc.co/16YSdj - -实验的完整目录结构、AGENTS.md、解析脚本均已开源。https://github.com/Nipi64310/llmwiki-test diff --git a/git_sync_daily.ps1 b/git_sync_daily.ps1 new file mode 100644 index 0000000..24e4341 --- /dev/null +++ b/git_sync_daily.ps1 @@ -0,0 +1,252 @@ +#!/usr/bin/env pwsh +# Git Sync Script with Gantt Integration +# Runs daily at 10:30 AM + +param( + [string]$RepoPath = "D:/fork_project/obsidian-notes" +) + +$InBoxPath = Join-Path $RepoPath "InBox" +$GanttTag = "obsidian" +$GitArgs = @("-c", "safe.directory=$RepoPath") + +function Resolve-GanttApp { + $candidates = @( + "C:/Users/Administrator/Desktop/我的/app_gant2/src-tauri/target/release/gantt-app.exe", + "C:/Users/Administrator/Desktop/我的/app_gant2/src-tauri/target/debug/gantt-app.exe" + ) + + foreach ($candidate in $candidates) { + if (Test-Path $candidate) { + return $candidate + } + } + + $searchRoot = "C:/Users/Administrator/Desktop" + if (Test-Path $searchRoot) { + $found = Get-ChildItem -Path $searchRoot -Filter "gantt-app.exe" -Recurse -ErrorAction SilentlyContinue | + Sort-Object FullName -Descending | + Select-Object -First 1 -ExpandProperty FullName + if ($found) { + return $found + } + } + + return $null +} + +$GanttApp = Resolve-GanttApp + +# Change to repo directory +Set-Location $RepoPath + +function Invoke-GitCommand { + param( + [Parameter(Mandatory)] + [string[]]$Arguments + ) + + $output = & git @GitArgs @Arguments 2>&1 + return [PSCustomObject]@{ + Output = @($output) + ExitCode = $LASTEXITCODE + } +} + +function Get-InBoxFileNames { + if (Test-Path $InBoxPath) { + return Get-ChildItem -Path $InBoxPath -File | Select-Object -ExpandProperty Name + } + + return @() +} + +# Function to get all Gantt tasks +function Get-GanttTasks { + if ($GanttApp -and (Test-Path $GanttApp)) { + try { + $result = & $GanttApp --cli list-tasks 2>$null | ConvertFrom-Json + if ($result.ok -and $result.data.tasks) { + return $result.data.tasks + } + } catch { + Write-Host "Failed to get Gantt tasks: $_" + } + } + return @() +} + +# Function to show Windows notification +function Show-Notification { + param([string]$Title, [string]$Message) + Add-Type -AssemblyName System.Windows.Forms + $global:balloon = New-Object System.Windows.Forms.NotifyIcon + $path = (Get-Process -Id $pid).Path + $balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path) + $balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Warning + $balloon.BalloonTipText = $Message + $balloon.BalloonTipTitle = $Title + $balloon.Visible = $true + $balloon.ShowBalloonTip(5000) +} + +function Fail-AndExit { + param( + [string]$Title, + [string]$Message + ) + + Write-Host $Message + Show-Notification -Title $Title -Message $Message + exit 1 +} + +function Test-RepoReady { + if (-not (Test-Path $RepoPath)) { + Fail-AndExit -Title "Git Sync Error" -Message "Repository path not found: $RepoPath" + } + + $statusResult = Invoke-GitCommand -Arguments @("status", "--short", "--branch") + if ($statusResult.ExitCode -ne 0) { + $message = ($statusResult.Output -join [Environment]::NewLine).Trim() + if ([string]::IsNullOrWhiteSpace($message)) { + $message = "Failed to read git status." + } + Fail-AndExit -Title "Git Sync Error" -Message $message + } + + $dirtyEntries = $statusResult.Output | Where-Object { + $_ -and $_ -notmatch "^## " + } + + if ($dirtyEntries.Count -gt 0) { + $preview = ($dirtyEntries | Select-Object -First 5) -join "; " + $message = "Working tree is not clean. Resolve or commit local changes before auto sync. $preview" + Fail-AndExit -Title "Git Sync Blocked" -Message $message + } +} + +function Add-GanttTask { + param([string]$TaskName) + $today = Get-Date -Format "yyyy-MM-dd" + $taskId = [Guid]::NewGuid().ToString() + + if ($GanttApp -and (Test-Path $GanttApp)) { + try { + & $GanttApp --cli add-task --id $taskId --name $TaskName --start $today --description "Auto-created from InBox sync" --tag $GanttTag 2>$null + Write-Host "Created Gantt task: $TaskName" + } catch { + Write-Host "Failed to create Gantt task: $_" + } + } else { + Write-Host "Gantt app not found" + } +} + +function Update-GanttTaskTag { + param( + [string]$TaskId, + [string]$TaskName + ) + + if ($GanttApp -and (Test-Path $GanttApp)) { + try { + & $GanttApp --cli update-task --id $TaskId --tag $GanttTag 2>$null + Write-Host "Updated Gantt task tag: $TaskName" + } catch { + Write-Host "Failed to update Gantt task tag: $_" + } + } +} + +function Remove-GanttTask { + param([string]$TaskId) + if ($GanttApp -and (Test-Path $GanttApp)) { + try { + & $GanttApp --cli delete-task --id $TaskId 2>$null + Write-Host "Deleted Gantt task: $TaskId" + } catch { + Write-Host "Failed to delete Gantt task: $_" + } + } +} + +function Sync-InBoxTasks { + if (-not ($GanttApp -and (Test-Path $GanttApp))) { + Write-Host "Skipping Gantt sync because gantt-app.exe was not found" + return + } + + $inboxFiles = Get-InBoxFileNames + $ganttTasks = Get-GanttTasks + $existingInboxTasks = $ganttTasks | Where-Object { $_.name -match "^Process InBox: " } + + foreach ($task in $existingInboxTasks) { + $taskFileName = $task.name -replace "^Process InBox: ", "" + if ($taskFileName -notin $inboxFiles) { + Write-Host "File no longer exists, deleting task: $($task.name)" + Remove-GanttTask -TaskId $task.id + } + } + + foreach ($file in $inboxFiles) { + $taskName = "Process InBox: $file" + $matchingTasks = @($existingInboxTasks | Where-Object { $_.name -eq $taskName }) + + if ($matchingTasks.Count -eq 0) { + Add-GanttTask -TaskName $taskName + continue + } + + foreach ($task in $matchingTasks) { + if ($task.tag -ne $GanttTag) { + Update-GanttTaskTag -TaskId $task.id -TaskName $task.name + } else { + Write-Host "Task already exists for: $file" + } + } + } +} + +# Perform git pull +Test-RepoReady + +Write-Host "Starting git pull at $(Get-Date)..." +$pullResult = Invoke-GitCommand -Arguments @("pull") +$pullOutput = $pullResult.Output +$pullExitCode = $pullResult.ExitCode + +if ($pullExitCode -ne 0) { + $message = "Git pull failed: " + (($pullOutput -join [Environment]::NewLine).Trim()) + Fail-AndExit -Title "Git Sync Error" -Message $message +} + +Write-Host "Git pull completed: $($pullOutput -join [Environment]::NewLine)" + +# Check for merge conflicts +if ($pullOutput -match "CONFLICT|conflict|Automatic merge failed") { + Show-Notification -Title "Git Sync Conflict" -Message "Merge conflicts detected during git pull. Please resolve manually." + exit 1 +} + +# Sync Gantt tasks against the full current InBox state +Start-Sleep -Seconds 2 +Sync-InBoxTasks + +# Perform git push +Write-Host "Starting git push..." +$pushResult = Invoke-GitCommand -Arguments @("push") +$pushOutput = $pushResult.Output +$pushExitCode = $pushResult.ExitCode + +if ($pushExitCode -ne 0) { + $pushText = ($pushOutput -join [Environment]::NewLine).Trim() + if ($pushText -match "rejected|failed|conflict|non-fast-forward") { + Show-Notification -Title "Git Push Conflict" -Message "Push rejected. Please pull and resolve conflicts manually." + } else { + Show-Notification -Title "Git Push Error" -Message "Git push failed: $pushText" + } + exit 1 +} + +Write-Host "Git push completed successfully at $(Get-Date)" diff --git a/setup-task.ps1 b/setup-task.ps1 new file mode 100644 index 0000000..ca98f51 --- /dev/null +++ b/setup-task.ps1 @@ -0,0 +1,37 @@ +#!/usr/bin/env pwsh +# Register the daily 10:30 AM git sync task for this repository. + +param( + [string]$TaskName = "Obsidian-Git-Sync-Daily", + [string]$RepoPath = "D:\fork_project\obsidian-notes" +) + +$scriptPath = Join-Path $RepoPath "git_sync_daily.ps1" + +if (-not (Test-Path $scriptPath)) { + throw "Sync script not found: $scriptPath" +} + +$existing = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue +if ($existing) { + Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false + Write-Host "Removed existing task: $TaskName" +} + +$action = New-ScheduledTaskAction -Execute "powershell.exe" ` + -Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$scriptPath`" -RepoPath `"$RepoPath`"" +$trigger = New-ScheduledTaskTrigger -Daily -At 10:30AM +$settings = New-ScheduledTaskSettingsSet ` + -AllowStartIfOnBatteries ` + -DontStopIfGoingOnBatteries ` + -StartWhenAvailable + +Register-ScheduledTask -TaskName $TaskName ` + -Action $action ` + -Trigger $trigger ` + -Settings $settings ` + -Description "Daily 10:30 AM git sync for obsidian-notes and InBox/Gantt sync" + +Write-Host "Task '$TaskName' registered." +Write-Host "Schedule: daily at 10:30 AM" +Write-Host "Script: $scriptPath"