archgraph-argo 0.9.3 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,7 +26,7 @@ npm install -g archgraph-argo
26
26
  argo-deploy
27
27
  ```
28
28
 
29
- Done — the ARGO toolchain, skills, and rules are deployed, and the `argo` MCP server is registered automatically in **GitHub Copilot**, **Cursor**, and **OpenCode**.
29
+ Done — the ARGO toolchain, skills, and rules are deployed, and the `argo` MCP server is registered automatically in **GitHub Copilot**, **Cursor**, **OpenCode**, and **DeepSeek Harness** (dsh).
30
30
 
31
31
  > Semantic (Graph RAG) queries also need **Neo4j** and a **vector engine** configured in
32
32
  > `~/.argo/.env`; everything else works out of the box.
package/install-argo.ps1 CHANGED
@@ -16,6 +16,8 @@ param(
16
16
  [switch]$SkipEnv,
17
17
  [switch]$SkipDeps,
18
18
  [switch]$SkipMcp,
19
+ [switch]$SkipDsh,
20
+ [string]$DshHome = "$env:USERPROFILE\.dsh",
19
21
  [string]$McpPath
20
22
  )
21
23
 
@@ -235,70 +237,342 @@ function Add-AgentsRule {
235
237
  }
236
238
  }
237
239
 
240
+ # ---- DeepSeek Harness (dsh) conversion helpers ----
241
+ # The ArchGraph repository keeps ONE source file per artifact (rule / skill /
242
+ # mcp / plugin / agent). The targets below convert that single source into the
243
+ # DeepSeek Harness shape at deploy time, exactly like Convert-AgentFile and
244
+ # Convert-RuleFile do for Cursor / OpenCode.
245
+
246
+ function Get-MarkdownBody {
247
+ # Strip a leading YAML frontmatter block (--- ... ---) from markdown text.
248
+ # DeepSeek Harness injects AGENTS.md-style instruction files verbatim, so
249
+ # the frontmatter must not reach the model prompt.
250
+ param([string]$Content)
251
+ $m = [regex]::Match($Content, '(?s)^---\s*\r?\n(.*?)\r?\n---\s*\r?\n(.*)$')
252
+ if (-not $m.Success) { return $Content }
253
+ return $m.Groups[2].Value
254
+ }
255
+
256
+ function Get-WakeupGuideline {
257
+ # Extract the <WakeupGuideline>...</WakeupGuideline> block from the rule
258
+ # text, so the DSH wakeup plugin is generated from the same source the
259
+ # Copilot / Cursor / OpenCode rules use.
260
+ param([string]$RuleText)
261
+ $m = [regex]::Match($RuleText, '(?s)<WakeupGuideline>(.*?)</WakeupGuideline>')
262
+ if (-not $m.Success) { return '' }
263
+ return $m.Groups[1].Value.Trim()
264
+ }
265
+
266
+ function Write-DshAgentRule {
267
+ # Merge the frontmatter-stripped ArchGraph rule (plus a DSH adapter note
268
+ # explaining the mcp__argo__ tool prefix) into ~/.dsh/AGENTS.md, replacing
269
+ # the previous ArchGraph block while preserving surrounding user content.
270
+ param(
271
+ [string]$DshHome,
272
+ [string]$RuleText
273
+ )
274
+ $adapterNote = @'
275
+ # ArchGraph ARGO Workflow Rules (DeepSeek Harness edition)
276
+
277
+ > Deployed by install-argo.ps1 from argo/rules/archgraph.instructions.md
278
+ > (single source of truth; this file is a deployment artifact).
279
+ > DeepSeek Harness injects ~/.dsh/AGENTS.md through dsh-agent-instructions as
280
+ > user-global instructions; the file is injected verbatim, so the YAML
281
+ > frontmatter of the source rule is stripped here.
282
+
283
+ ## DSH adapter note
284
+ - The ARGO MCP server is registered under serverName "argo" through the
285
+ @deepseek-ai/dsh-mcp-client plugin; its tools are exposed to the model with
286
+ the mcp__argo__ prefix (e.g. mcp__argo__getSystemArchitecture). When a rule
287
+ below names a tool like getSystemArchitecture, call the mcp__argo__* form.
288
+ - The argo-init skill is installed at ~/.dsh/skills/argo-init/SKILL.md and is
289
+ loadable through the harness skill tool.
290
+ '@
291
+ $body = Get-MarkdownBody -Content $RuleText
292
+ $ruleContent = $adapterNote + "`n`n" + $body
293
+ $dest = Join-Path $DshHome 'AGENTS.md'
294
+ $marker = 'ArchGraph ARGO Workflow Rules'
295
+ New-Item -ItemType Directory -Force -Path $DshHome | Out-Null
296
+ if (Test-Path $dest) {
297
+ $existing = Get-Content $dest -Raw -Encoding UTF8
298
+ if ($existing -like "*$marker*") {
299
+ $endTag = '</ToolsGuideline>'
300
+ $markerIdx = $existing.IndexOf($marker)
301
+ if ($markerIdx -lt 0) { $markerIdx = 0 }
302
+ $startIdx = $existing.LastIndexOf('# ArchGraph', $markerIdx)
303
+ if ($startIdx -lt 0) { $startIdx = 0 }
304
+ $endIdx = $existing.IndexOf($endTag, $markerIdx)
305
+ $before = $existing.Substring(0, $startIdx).TrimEnd()
306
+ if ($endIdx -lt 0) {
307
+ $combined = $before
308
+ if ($combined.Length -gt 0) { $combined += "`n`n" }
309
+ $combined += $ruleContent
310
+ } else {
311
+ $after = $existing.Substring($endIdx + $endTag.Length)
312
+ $combined = $before
313
+ if ($combined.Length -gt 0) { $combined += "`n`n" }
314
+ $combined += $ruleContent
315
+ if ($after.Length -gt 0) { $combined += $after }
316
+ }
317
+ [System.IO.File]::WriteAllText($dest, $combined, (New-Object System.Text.UTF8Encoding $false))
318
+ } else {
319
+ $combined = $existing.TrimEnd() + "`n`n" + $ruleContent
320
+ [System.IO.File]::WriteAllText($dest, $combined, (New-Object System.Text.UTF8Encoding $false))
321
+ }
322
+ } else {
323
+ [System.IO.File]::WriteAllText($dest, $ruleContent, (New-Object System.Text.UTF8Encoding $false))
324
+ }
325
+ Write-Host " DSH rule installed -> $dest"
326
+ }
327
+
328
+ function Write-DshManagedBlock {
329
+ # Text-level upsert of a marker-delimited block into a file (used for the
330
+ # managed rows in ~/.dsh/cordis.patch.yml): replaces the previous managed
331
+ # block and preserves surrounding content. No YAML dependency needed.
332
+ param(
333
+ [string]$Path,
334
+ [string]$Block,
335
+ [string]$MarkerStart,
336
+ [string]$MarkerEnd
337
+ )
338
+ New-Item -ItemType Directory -Force -Path (Split-Path $Path) | Out-Null
339
+ $existing = if (Test-Path $Path) { Get-Content $Path -Raw -Encoding UTF8 } else { '' }
340
+ $startIdx = $existing.IndexOf($MarkerStart)
341
+ $endIdx = if ($startIdx -ge 0) { $existing.IndexOf($MarkerEnd, $startIdx) } else { -1 }
342
+ if ($startIdx -ge 0 -and $endIdx -ge 0) {
343
+ $endIdx += $MarkerEnd.Length
344
+ $combined = $existing.Substring(0, $startIdx).TrimEnd()
345
+ if ($combined.Length -gt 0) { $combined += "`n`n" }
346
+ $combined += $Block
347
+ $after = $existing.Substring($endIdx).TrimStart()
348
+ if ($after.Length -gt 0) { $combined += "`n`n" + $after }
349
+ [System.IO.File]::WriteAllText($Path, $combined, (New-Object System.Text.UTF8Encoding $false))
350
+ } else {
351
+ $combined = $existing.TrimEnd()
352
+ if ($combined.Length -gt 0) { $combined += "`n`n" }
353
+ $combined += $Block + "`n"
354
+ [System.IO.File]::WriteAllText($Path, $combined, (New-Object System.Text.UTF8Encoding $false))
355
+ }
356
+ }
357
+
358
+ function New-DshWakeupPlugin {
359
+ # Generate the DSH wakeup-gate Cordis plugin under ~/.dsh/plugins from the
360
+ # <WakeupGuideline> block of the rule file. This is the DeepSeek Harness
361
+ # equivalent of the OpenCode hook plugin argo/plugins/argo-wakeup.js: it
362
+ # registers the gate as the first system-prompt section after the harness
363
+ # identity (order -100), before the deployment persona (order 0).
364
+ param(
365
+ [string]$DshHome,
366
+ [string]$RuleText
367
+ )
368
+ $gate = Get-WakeupGuideline -RuleText $RuleText
369
+ if (-not $gate) {
370
+ Write-Warning ' <WakeupGuideline> not found in the rule file; DSH wakeup plugin skipped.'
371
+ return $null
372
+ }
373
+ $dir = Join-Path (Join-Path $DshHome 'plugins') 'dsh-argo-wakeup'
374
+ New-Item -ItemType Directory -Force -Path $dir | Out-Null
375
+ $gateJson = $gate | ConvertTo-Json
376
+ $plugin = @"
377
+ // dsh-argo-wakeup - generated by install-argo.ps1 from
378
+ // argo/rules/archgraph.instructions.md (single source of truth: the rule file;
379
+ // this file is a deployment artifact, do not edit by hand).
380
+ // DeepSeek Harness equivalent of the OpenCode hook argo/plugins/argo-wakeup.js:
381
+ // registers the unconditional wakeup gate as the first system-prompt section
382
+ // after the harness identity, so every session identifies its Business Actor
383
+ // through the argo MCP server before responding.
384
+ export const name = 'dsh-argo-wakeup'
385
+ export const inject = ['systemPrompt']
386
+ const WAKEUP_GATE = $gateJson
387
+ export function apply(ctx) {
388
+ ctx.effect(() => ctx.systemPrompt.section({
389
+ name: 'argo:wakeup',
390
+ order: -90,
391
+ text: WAKEUP_GATE,
392
+ }), 'argo:wakeup.section()')
393
+ }
394
+ "@
395
+ $indexPath = Join-Path $dir 'index.js'
396
+ [System.IO.File]::WriteAllText($indexPath, $plugin, (New-Object System.Text.UTF8Encoding $false))
397
+ Write-Host " DSH wakeup plugin generated -> $indexPath"
398
+ return $indexPath
399
+ }
400
+
401
+ function New-DshAgentPresets {
402
+ # Generate DSH agent presets under ~/.dsh/.agent-presets/<id>/ from
403
+ # argo/agents/*.agent.md (the same single source the Copilot / Cursor /
404
+ # OpenCode agent files are converted from). persona.md is a
405
+ # frontmatter-stripped copy of the agent body; persona.js is a fixed
406
+ # self-contained row that mounts it as the session persona
407
+ # (deployment:persona section, order 0).
408
+ param(
409
+ [string]$DshHome,
410
+ [string]$AgentsSrc
411
+ )
412
+ $files = @(Get-ChildItem -Path (Join-Path $AgentsSrc '*.agent.md') -ErrorAction SilentlyContinue)
413
+ if ($files.Count -eq 0) {
414
+ Write-Warning ' no *.agent.md files found; DSH agent presets skipped.'
415
+ return
416
+ }
417
+ foreach ($file in $files) {
418
+ $content = Get-Content $file.FullName -Raw -Encoding UTF8
419
+ $m = [regex]::Match($content, '(?s)^---\s*\r?\n(.*?)\r?\n---\s*\r?\n(.*)$')
420
+ $name = ''
421
+ $desc = ''
422
+ $body = $content
423
+ if ($m.Success) {
424
+ $front = $m.Groups[1].Value
425
+ $body = $m.Groups[2].Value.TrimStart("`r", "`n")
426
+ $nm = [regex]::Match($front, '(?m)^name:\s*(.*)$')
427
+ if ($nm.Success) { $name = $nm.Groups[1].Value.Trim().Trim('"').Trim("'") }
428
+ $dm = [regex]::Match($front, '(?m)^description:\s*(.*)$')
429
+ if ($dm.Success) { $desc = $dm.Groups[1].Value.Trim().Trim('"').Trim("'") }
430
+ }
431
+ $id = $file.BaseName -replace '\.agent$', ''
432
+ if (-not $name) { $name = $id }
433
+ $dir = Join-Path (Join-Path $DshHome '.agent-presets') $id
434
+ New-Item -ItemType Directory -Force -Path $dir | Out-Null
435
+
436
+ # preset.yml: display metadata (name + description).
437
+ $presetYml = "name: $name`n"
438
+ if ($desc) { $presetYml += "description: `"$($desc -replace '"', '\"')`"`n" }
439
+ [System.IO.File]::WriteAllText((Join-Path $dir 'preset.yml'), $presetYml, (New-Object System.Text.UTF8Encoding $false))
440
+
441
+ # persona.md: the agent body verbatim (single source: the .agent.md file).
442
+ [System.IO.File]::WriteAllText((Join-Path $dir 'persona.md'), $body, (New-Object System.Text.UTF8Encoding $false))
443
+
444
+ # agent.cordis.yml: mount the local persona row.
445
+ $cordisYml = @"
446
+ # ArchGraph agent preset "$name" - generated by install-argo.ps1 from
447
+ # argo/agents/$($file.Name) (single source of truth; this file is a deployment
448
+ # artifact, do not edit by hand). The persona is the frontmatter-stripped agent
449
+ # body (persona.md), mounted as the session's deployment:persona section.
450
+ - id: persona
451
+ name: './persona.js'
452
+ "@
453
+ [System.IO.File]::WriteAllText((Join-Path $dir 'agent.cordis.yml'), $cordisYml, (New-Object System.Text.UTF8Encoding $false))
454
+
455
+ # persona.js: fixed row implementation.
456
+ $personaJs = @'
457
+ // persona row for an ArchGraph agent preset (generated by install-argo.ps1).
458
+ // Loads persona.md next to this file and registers it as the
459
+ // deployment:persona system-prompt section (order 0), shadowing the
460
+ // deployment persona for the session that mounts this preset.
461
+ import { readFileSync } from 'node:fs'
462
+ import { fileURLToPath } from 'node:url'
463
+ export const name = 'persona'
464
+ export const inject = ['systemPrompt']
465
+ export function apply(ctx) {
466
+ const text = readFileSync(fileURLToPath(new URL('./persona.md', import.meta.url)), 'utf8')
467
+ ctx.effect(() => ctx.systemPrompt.section({
468
+ name: 'deployment:persona',
469
+ order: 0,
470
+ text,
471
+ }), 'persona.section()')
472
+ }
473
+ '@
474
+ [System.IO.File]::WriteAllText((Join-Path $dir 'persona.js'), $personaJs, (New-Object System.Text.UTF8Encoding $false))
475
+ Write-Host " DSH agent preset generated -> $dir"
476
+ }
477
+ }
478
+
238
479
  Write-Host '==> Deploying Argo toolchain'
239
480
 
240
481
  $schemaSrc = Join-Path $argoDir 'schema'
241
482
  $schemaDest = Join-Path $ArgoRoot 'schema'
242
- Write-Host "[1/14] argo\schema -> $schemaDest"
483
+ Write-Host "[1/19] argo\schema -> $schemaDest"
243
484
  Copy-Tree -Source $schemaSrc -Destination $schemaDest
244
485
 
245
486
  $scriptsSrc = Join-Path $argoDir 'scripts'
246
487
  $scriptsDest = Join-Path $ArgoRoot 'scripts'
247
- Write-Host "[2/14] argo\scripts -> $scriptsDest"
488
+ Write-Host "[2/19] argo\scripts -> $scriptsDest"
248
489
  Copy-Tree -Source $scriptsSrc -Destination $scriptsDest
249
490
 
250
491
  $defaultsSrc = Join-Path $argoDir 'defaults'
251
492
  $defaultsDest = Join-Path $ArgoRoot 'defaults'
252
- Write-Host "[3/14] argo\defaults -> $defaultsDest"
493
+ Write-Host "[3/19] argo\defaults -> $defaultsDest"
253
494
  Copy-Tree -Source $defaultsSrc -Destination $defaultsDest
254
495
 
255
496
  $skillSrc = Join-Path (Join-Path $argoDir 'skills') 'argo-init'
256
497
  $skillDest = Join-Path $SkillsRoot 'argo-init'
257
- Write-Host "[4/14] argo\skills\argo-init -> $skillDest"
498
+ Write-Host "[4/19] argo\skills\argo-init -> $skillDest"
258
499
  Copy-Tree -Source $skillSrc -Destination $skillDest
259
500
 
260
501
  $ruleSrc = Join-Path (Join-Path $argoDir 'rules') 'archgraph.instructions.md'
261
502
  $ruleDest = Join-Path $PromptsRoot 'archgraph.instructions.md'
262
- Write-Host "[5/14] argo\rules\archgraph.instructions.md -> $ruleDest"
503
+ Write-Host "[5/19] argo\rules\archgraph.instructions.md -> $ruleDest"
263
504
  New-Item -ItemType Directory -Force -Path $PromptsRoot | Out-Null
264
505
  Copy-Item -Force -Path $ruleSrc -Destination $ruleDest
265
506
 
266
507
  $depsSrc = Join-Path $argoDir 'package.json'
267
508
  $depsDest = Join-Path $ArgoRoot 'package.json'
268
- Write-Host "[6/14] argo\package.json -> $depsDest"
509
+ Write-Host "[6/19] argo\package.json -> $depsDest"
269
510
  Copy-Item -Force -Path $depsSrc -Destination $depsDest
270
511
 
271
512
  $cursorSkillDest = Join-Path $CursorSkillsRoot 'argo-init'
272
- Write-Host "[7/14] argo\skills\argo-init -> $cursorSkillDest (Cursor)"
513
+ Write-Host "[7/19] argo\skills\argo-init -> $cursorSkillDest (Cursor)"
273
514
  Copy-Tree -Source $skillSrc -Destination $cursorSkillDest
274
515
 
275
516
  $openCodeSkillDest = Join-Path $OpenCodeSkillsRoot 'argo-init'
276
- Write-Host "[8/14] argo\skills\argo-init -> $openCodeSkillDest (OpenCode)"
517
+ Write-Host "[8/19] argo\skills\argo-init -> $openCodeSkillDest (OpenCode)"
277
518
  Copy-Tree -Source $skillSrc -Destination $openCodeSkillDest
278
519
 
279
- Write-Host "[9/14] argo\rules\archgraph.instructions.md -> $OpenCodeAgentsPath (OpenCode global AGENTS.md)"
520
+ Write-Host "[9/19] argo\rules\archgraph.instructions.md -> $OpenCodeAgentsPath (OpenCode global AGENTS.md)"
280
521
  Add-AgentsRule -AgentsPath $OpenCodeAgentsPath -RulePath $ruleSrc
281
522
 
282
523
  $agentsSrc = Join-Path $argoDir 'agents'
283
- Write-Host "[10/14] argo\agents -> $CopilotAgentsRoot (Copilot user-level)"
524
+ Write-Host "[10/19] argo\agents -> $CopilotAgentsRoot (Copilot user-level)"
284
525
  Copy-Agents -Source $agentsSrc -Destination $CopilotAgentsRoot
285
526
 
286
- Write-Host "[11/14] argo\agents -> $CursorAgentsRoot (Cursor user-level, converted to .md)"
527
+ Write-Host "[11/19] argo\agents -> $CursorAgentsRoot (Cursor user-level, converted to .md)"
287
528
  Copy-Agents -Source $agentsSrc -Destination $CursorAgentsRoot -Target cursor
288
529
 
289
- Write-Host "[12/14] argo\agents -> $OpenCodeAgentsRoot (OpenCode user-level, converted to .md)"
530
+ Write-Host "[12/19] argo\agents -> $OpenCodeAgentsRoot (OpenCode user-level, converted to .md)"
290
531
  Copy-Agents -Source $agentsSrc -Destination $OpenCodeAgentsRoot -Target opencode
291
532
 
292
533
  $pluginsSrc = Join-Path $argoDir 'plugins'
293
- Write-Host "[13/14] argo\plugins -> $PluginsRoot (Argo opencode plugins)"
534
+ Write-Host "[13/19] argo\plugins -> $PluginsRoot (Argo opencode plugins)"
294
535
  Copy-Tree -Source $pluginsSrc -Destination $PluginsRoot
295
536
 
296
537
  $cursorRuleSrc = Join-Path (Join-Path $argoDir 'rules') 'archgraph.instructions.md'
297
538
  $cursorRuleDest = Join-Path $CursorRulesRoot 'archgraph.mdc'
298
- Write-Host "[14/14] argo\rules\archgraph.instructions.md -> $cursorRuleDest (Cursor global rule, alwaysApply)"
539
+ Write-Host "[14/19] argo\rules\archgraph.instructions.md -> $cursorRuleDest (Cursor global rule, alwaysApply)"
299
540
  New-Item -ItemType Directory -Force -Path $CursorRulesRoot | Out-Null
300
541
  Convert-RuleFile -SourceFile $cursorRuleSrc -DestinationFile $cursorRuleDest
301
542
 
543
+ if ($SkipDsh) {
544
+ Write-Host 'Skipped DeepSeek Harness integration (-SkipDsh).'
545
+ } else {
546
+ $ruleSrcContent = Get-Content $ruleSrc -Raw -Encoding UTF8
547
+ $dshSkillDest = Join-Path (Join-Path $DshHome 'skills') 'argo-init'
548
+ $patchPath = Join-Path $DshHome 'cordis.patch.yml'
549
+ $argoServer = (Join-Path $ArgoRoot 'scripts\argo-mcp-server.js').Replace('\', '/')
550
+
551
+ Write-Host "[15/19] argo\rules\archgraph.instructions.md -> $DshHome\AGENTS.md (DeepSeek Harness user-global rule, frontmatter stripped)"
552
+ Write-DshAgentRule -DshHome $DshHome -RuleText $ruleSrcContent
553
+
554
+ Write-Host "[16/19] argo\skills\argo-init -> $dshSkillDest (DeepSeek Harness skill)"
555
+ Copy-Tree -Source (Join-Path $argoDir 'skills\argo-init') -Destination $dshSkillDest
556
+
557
+ Write-Host "[17/19] argo\rules\<WakeupGuideline> -> $DshHome\plugins\dsh-argo-wakeup\index.js (DeepSeek Harness wakeup plugin)"
558
+ $wakeupDshPath = New-DshWakeupPlugin -DshHome $DshHome -RuleText $ruleSrcContent
559
+
560
+ Write-Host "[18/19] mcp-argo + argo-wakeup rows -> $patchPath (DeepSeek Harness MCP + wakeup plugin)"
561
+ $rows = " - id: mcp-argo`n name: '@deepseek-ai/dsh-mcp-client'`n config:`n serverName: argo`n transport: stdio`n command: node`n args:`n - $argoServer`n"
562
+ if ($wakeupDshPath) {
563
+ $pluginUrl = 'file:///' + (($wakeupDshPath -replace '\\', '/').TrimStart('/'))
564
+ $rows += " - id: argo-wakeup`n name: '$pluginUrl'`n"
565
+ }
566
+ $block = "# BEGIN ArchGraph ARGO deployment (managed by install-argo.ps1)`n- insert:`n" + $rows + "# END ArchGraph ARGO deployment"
567
+ Write-DshManagedBlock -Path $patchPath -Block $block -MarkerStart '# BEGIN ArchGraph ARGO deployment' -MarkerEnd '# END ArchGraph ARGO deployment'
568
+
569
+ Write-Host "[19/19] argo\agents -> $DshHome\.agent-presets\<id> (DeepSeek Harness agent presets)"
570
+ New-DshAgentPresets -DshHome $DshHome -AgentsSrc (Join-Path $argoDir 'agents')
571
+
572
+ Write-Host ' Restart `dsh web` to activate the MCP server and the wakeup plugin;'
573
+ Write-Host ' new sessions pick up the global rule and the argo-init skill automatically.'
574
+ }
575
+
302
576
  if ($SkipDeps) {
303
577
  Write-Host 'Skipped dependency install (-SkipDeps).'
304
578
  } elseif (Get-Command npm -ErrorAction SilentlyContinue) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archgraph-argo",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
4
4
  "description": "Deploy the ArchGraph ARGO toolchain, skills, and rules (schema, scripts, argo-init skill, global rule) with one command.",
5
5
  "license": "MIT",
6
6
  "bin": {