yaml-flow 5.2.5 → 5.2.6

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.
@@ -6,9 +6,9 @@
6
6
  <title>Example Board Demo (Browser Runtime)</title>
7
7
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
8
8
  <script src="https://cdn.jsdelivr.net/npm/jsonata/jsonata.min.js"></script>
9
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/card-compute.js"></script>
10
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/live-cards.js"></script>
11
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/board-livegraph-engine.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.6/browser/card-compute.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.6/browser/live-cards.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.6/browser/board-livegraph-engine.js"></script>
12
12
  </head>
13
13
  <body class="bg-light">
14
14
  <div class="container-fluid py-3">
@@ -16,10 +16,10 @@
16
16
  </style>
17
17
  <script src="https://cdn.jsdelivr.net/npm/jsonata/jsonata.min.js"></script>
18
18
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
19
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/card-compute.js"></script>
20
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/live-cards.js"></script>
21
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/board-livegraph-engine.js"></script>
22
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.5/browser/board-livecards-runtime-client.js"></script>
19
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.6/browser/card-compute.js"></script>
20
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.6/browser/live-cards.js"></script>
21
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.6/browser/board-livegraph-engine.js"></script>
22
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.2.6/browser/board-livecards-runtime-client.js"></script>
23
23
  </head>
24
24
  <body class="bg-light">
25
25
  <div class="container-fluid py-3">
@@ -0,0 +1,141 @@
1
+ @echo off
2
+ setlocal enabledelayedexpansion
3
+
4
+ REM Copilot Wrapper - Manages session isolation for GitHub Copilot CLI
5
+ REM Usage: copilot_wrapper.bat <output_file> <session_dir> <working_dir> <request_or_file> <result_type> [agent_name] [model] [result_shape_file]
6
+ REM
7
+ REM If request_or_file starts with @, it's treated as a file path containing the prompt.
8
+ REM Otherwise, it's treated as the prompt string directly.
9
+ REM result_type: "raw" to return plain text, "json" to extract JSON (passed to clean_copilot_output.ps1)
10
+ REM agent_name: name of the agent for log files (optional)
11
+ REM model: passed to copilot with --model flag (optional)
12
+
13
+ SET "OUTPUT_FILE=%~1"
14
+ SET "SESSION_DIR=%~2"
15
+ SET "WORKING_DIR=%~3"
16
+ SET "REQUEST_OR_FILE=%~4"
17
+ SET "RESULT_TYPE=%~5"
18
+ SET "AGENT_NAME=%~6"
19
+ SET "MODEL=%~7"
20
+ SET "RESULT_SHAPE_FILE=%~8"
21
+
22
+ if not defined RESULT_TYPE SET "RESULT_TYPE=raw"
23
+
24
+ SET "PROMPT_FILE="
25
+ SET "REQUEST="
26
+ echo !REQUEST_OR_FILE! | findstr /b "@" >nul
27
+ if !errorlevel! equ 0 (
28
+ SET "PROMPT_FILE=!REQUEST_OR_FILE:~1!"
29
+ ) else (
30
+ SET "REQUEST=!REQUEST_OR_FILE!"
31
+ )
32
+
33
+ SET "_WD_HASH=!WORKING_DIR:\=!"
34
+ SET "_WD_HASH=!_WD_HASH:/=!"
35
+ SET "_WD_HASH=!_WD_HASH::=!"
36
+ SET "_WD_HASH=!_WD_HASH:.=!"
37
+ SET "_WD_HASH=!_WD_HASH: =!"
38
+ SET "COPILOT_BASE=%TEMP%\copilot-sessions\!_WD_HASH!"
39
+ SET "COPILOT_CACHE=%COPILOT_BASE%\session-state"
40
+ SET "LOCK_FILE=%COPILOT_BASE%\copilot.lock"
41
+ SET "UUID_FILE=%SESSION_DIR%\session.uuid"
42
+
43
+ if not exist "%COPILOT_BASE%" mkdir "%COPILOT_BASE%"
44
+ if not exist "%COPILOT_CACHE%" mkdir "%COPILOT_CACHE%"
45
+ if not exist "%SESSION_DIR%" mkdir "%SESSION_DIR%"
46
+
47
+ if exist "%LOCK_FILE%" (
48
+ for /f "tokens=*" %%a in ('powershell -NoProfile -Command "if ((Get-Item '%LOCK_FILE%').LastWriteTime -lt (Get-Date).AddMinutes(-20)) { Write-Output 'STALE' }"') do (
49
+ if "%%a"=="STALE" (
50
+ del "%LOCK_FILE%" 2>nul
51
+ )
52
+ )
53
+ )
54
+ :acquire_lock
55
+ 2>nul (
56
+ >"%LOCK_FILE%" (
57
+ echo %DATE% %TIME%
58
+ )
59
+ ) || (
60
+ timeout /t 1 /nobreak >nul
61
+ goto acquire_lock
62
+ )
63
+
64
+ SET "SESSION_UUID="
65
+ if exist "%UUID_FILE%" (
66
+ set /p SESSION_UUID=<"%UUID_FILE%"
67
+ ) else (
68
+ for /f "tokens=*" %%a in ('powershell -NoProfile -Command "[guid]::NewGuid().ToString()"') do (
69
+ SET "SESSION_UUID=%%a"
70
+ )
71
+ echo !SESSION_UUID!>"%UUID_FILE%"
72
+ )
73
+
74
+ SET "CACHE_SESSION_PATH=%COPILOT_CACHE%\!SESSION_UUID!"
75
+
76
+ if exist "%SESSION_DIR%\workspace.yaml" (
77
+ if exist "!CACHE_SESSION_PATH!" rmdir /s /q "!CACHE_SESSION_PATH!" 2>nul
78
+ mkdir "!CACHE_SESSION_PATH!" 2>nul
79
+ for %%f in ("%SESSION_DIR%\*") do (
80
+ if /i not "%%~nxf"=="session.uuid" (
81
+ move /y "%%f" "!CACHE_SESSION_PATH!\" >nul 2>&1
82
+ )
83
+ )
84
+ for /d %%d in ("%SESSION_DIR%\*") do (
85
+ robocopy "%%d" "!CACHE_SESSION_PATH!\%%~nxd" /E /MOVE /NFL /NDL /NJH /NJS >nul 2>&1
86
+ )
87
+ )
88
+
89
+ cd /d "%WORKING_DIR%"
90
+
91
+ SET "MODEL_FLAG="
92
+ if defined MODEL (
93
+ SET "MODEL_FLAG=--model !MODEL!"
94
+ )
95
+
96
+ if defined PROMPT_FILE (
97
+ type "!PROMPT_FILE!" | call copilot --allow-all --resume !SESSION_UUID! !MODEL_FLAG! > "%OUTPUT_FILE%" 2>&1
98
+ ) else (
99
+ call copilot -p "%REQUEST%" --allow-all --resume !SESSION_UUID! !MODEL_FLAG! > "%OUTPUT_FILE%" 2>&1
100
+ )
101
+
102
+ SET "LOG_DIR=%COPILOT_BASE%\copilot-logs"
103
+ if not exist "!LOG_DIR!" mkdir "!LOG_DIR!"
104
+ SET "LOG_AGENT=unknown"
105
+ if defined AGENT_NAME SET "LOG_AGENT=!AGENT_NAME!"
106
+ for /f "tokens=*" %%t in ('powershell -NoProfile -Command "Get-Date -Format 'yyyyMMdd-HHmmss'"') do SET "LOG_TS=%%t"
107
+ SET "LOG_FILE=!LOG_DIR!\!LOG_AGENT!_!LOG_TS!.log"
108
+ echo === PROMPT (!LOG_TS!) === > "!LOG_FILE!"
109
+ echo Agent: !LOG_AGENT! >> "!LOG_FILE!"
110
+ echo ResultType: !RESULT_TYPE! >> "!LOG_FILE!"
111
+ echo Working Dir: %WORKING_DIR% >> "!LOG_FILE!"
112
+ echo --- >> "!LOG_FILE!"
113
+ if defined PROMPT_FILE (
114
+ type "!PROMPT_FILE!" >> "!LOG_FILE!" 2>nul
115
+ ) else (
116
+ echo %REQUEST% >> "!LOG_FILE!"
117
+ )
118
+ echo. >> "!LOG_FILE!"
119
+ echo === RESPONSE === >> "!LOG_FILE!"
120
+ type "%OUTPUT_FILE%" >> "!LOG_FILE!" 2>nul
121
+ echo. >> "!LOG_FILE!"
122
+ echo === END === >> "!LOG_FILE!"
123
+ for /f "skip=50 tokens=*" %%f in ('dir /b /o-d "!LOG_DIR!\!LOG_AGENT!_*.log" 2^>nul') do (
124
+ del "!LOG_DIR!\%%f" 2>nul
125
+ )
126
+
127
+ powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0copilot_wrapper_helper.ps1" "%OUTPUT_FILE%" "!RESULT_TYPE!" "!RESULT_SHAPE_FILE!"
128
+
129
+ if exist "!CACHE_SESSION_PATH!" (
130
+ for %%f in ("!CACHE_SESSION_PATH!\*") do (
131
+ move /y "%%f" "%SESSION_DIR%\" >nul 2>&1
132
+ )
133
+ for /d %%d in ("!CACHE_SESSION_PATH!\*") do (
134
+ robocopy "%%d" "%SESSION_DIR%\%%~nxd" /E /MOVE /NFL /NDL /NJH /NJS >nul 2>&1
135
+ )
136
+ rmdir "!CACHE_SESSION_PATH!" 2>nul
137
+ )
138
+
139
+ del "%LOCK_FILE%" 2>nul
140
+
141
+ endlocal
@@ -0,0 +1,181 @@
1
+ # clean_copilot_output.ps1
2
+ # Cleans copilot CLI output: filters noise lines and stats footer.
3
+ # Called by copilot_wrapper.bat after copilot runs and after logging (raw log preserved).
4
+ #
5
+ # Usage: clean_copilot_output.ps1 <output_file> <result_type> [result_shape_file]
6
+ # output_file - file containing raw copilot output; overwritten with cleaned result
7
+ # result_type=raw - strip noise + stats, write plain text back to output_file
8
+ # result_type=json - extract first JSON object whose keys match result_shape;
9
+ # if result_shape_file is absent, accepts any valid JSON object
10
+ # result_shape_file - (json result_type only) JSON file whose top-level keys are required in output
11
+ #
12
+ # raw result_type: right for chat responses and task executor sources.
13
+ # json result_type: right for structured calls where the input contained {prompt, result_shape}.
14
+
15
+ param(
16
+ [Parameter(Mandatory)][string]$OutputFile,
17
+ [Parameter(Mandatory)][string]$ResultType,
18
+ [string]$ResultShapeFile = ''
19
+ )
20
+
21
+ if (-not (Test-Path $OutputFile)) { exit 0 }
22
+
23
+ $raw = [IO.File]::ReadAllText($OutputFile, [Text.Encoding]::UTF8)
24
+ if ([string]::IsNullOrWhiteSpace($raw)) { exit 0 }
25
+
26
+ # --- Step 1: Filter noise lines ---
27
+ $lines = $raw -split "`r?`n" | Where-Object {
28
+ $_ -notmatch "^error: unknown option '--no-warnings'" -and
29
+ $_ -notmatch "^Try 'copilot --help' for more information"
30
+ }
31
+ $cleaned = ($lines -join "`n").Trim()
32
+
33
+ # --- Step 1b: Strip copilot-cli tool operation lines ---
34
+ # These are internal tool invocations that leak into output:
35
+ # ● Create/Read/Edit/List directory/Glob/Check ...
36
+ # X Read ... (failed tool ops)
37
+ # $ Get-Content/Set-Content ... (PowerShell invocations)
38
+ # └ N lines/files found
39
+ # ├ ... (tree lines)
40
+ # "The agent decision has been simulated and saved to ..."
41
+ # session-state file paths
42
+ $noiseLines = New-Object System.Collections.Generic.List[string]
43
+ $contentLines2 = New-Object System.Collections.Generic.List[string]
44
+ foreach ($line in ($cleaned -split "`n")) {
45
+ $t = $line.TrimStart()
46
+ if ($t -match '^[\u25cf\u2022] ' -or # ● bullet tool ops
47
+ $t -match '^X ' -or # X failed tool ops
48
+ $t -match '^\$ ' -or # $ shell commands
49
+ $t -match '^[\u2514\u251c]' -or # └ ├ tree lines
50
+ $t -match 'session-state.*\.json' -or # session-state file refs
51
+ $t -match 'agent.decision has been simulated' -or
52
+ $t -match 'has been simulated and saved' -or
53
+ $t -match '^\d+ (files?|lines?|matches?) found$' -or # "3 files found"
54
+ $t -match '^No matches found$' -or
55
+ $t -match '^Path does not exist$' -or
56
+ $t -match '^\d+ lines?( read)?$') { # "1 line read"
57
+ $noiseLines.Add($line)
58
+ } else {
59
+ $contentLines2.Add($line)
60
+ }
61
+ }
62
+ $cleaned = ($contentLines2 -join "`n").Trim()
63
+
64
+ # Write noise to sidecar file for upstream visibility
65
+ $NoiseFile = $OutputFile + '.noise'
66
+ if ($noiseLines.Count -gt 0) {
67
+ $noiseContent = "STRIPPED_LINES=$($noiseLines.Count)`n" + ($noiseLines -join "`n")
68
+ [IO.File]::WriteAllText($NoiseFile, $noiseContent, [Text.Encoding]::UTF8)
69
+ } elseif (Test-Path $NoiseFile) {
70
+ Remove-Item $NoiseFile -Force
71
+ }
72
+
73
+ # --- Step 2: Strip trailing usage stats ---
74
+ $statsPrefixes = @('Total usage est:', 'API time spent:', 'Total session time:',
75
+ 'Total code changes:', 'Breakdown by AI model:', 'Session:',
76
+ 'Changes', 'Requests', 'Tokens')
77
+ $resultLines = New-Object System.Collections.Generic.List[string]
78
+ $hitStats = $false
79
+ foreach ($line in $cleaned -split "`n") {
80
+ if (-not $hitStats) {
81
+ foreach ($sp in $statsPrefixes) {
82
+ if ($line.TrimStart().StartsWith($sp)) { $hitStats = $true; break }
83
+ }
84
+ }
85
+ if (-not $hitStats) { $resultLines.Add($line) }
86
+ }
87
+ $cleaned = ($resultLines -join "`n").Trim()
88
+
89
+ # --- raw result_type: write cleaned plain text and exit ---
90
+ if ($ResultType -eq 'raw') {
91
+ if ([string]::IsNullOrWhiteSpace($cleaned)) {
92
+ [IO.File]::WriteAllText($OutputFile, '', [Text.Encoding]::UTF8)
93
+ } else {
94
+ [IO.File]::WriteAllText($OutputFile, $cleaned, [Text.Encoding]::UTF8)
95
+ }
96
+ exit 0
97
+ }
98
+
99
+ # --- json result_type: extract JSON object matching result_shape ---
100
+
101
+ # Load result_shape keys (if provided) to use as required-key filter
102
+ $shapeKeys = @()
103
+ if ($ResultShapeFile -and (Test-Path $ResultShapeFile)) {
104
+ try {
105
+ $shape = [IO.File]::ReadAllText($ResultShapeFile, [Text.Encoding]::UTF8) | ConvertFrom-Json -ErrorAction Stop
106
+ $shapeKeys = @($shape.PSObject.Properties.Name)
107
+ } catch {}
108
+ }
109
+
110
+ if ([string]::IsNullOrWhiteSpace($cleaned)) {
111
+ $fallback = if ($shapeKeys.Count -gt 0) {
112
+ $obj = [ordered]@{}
113
+ foreach ($k in $shapeKeys) { $obj[$k] = $null }
114
+ $obj | ConvertTo-Json -Depth 2 -Compress
115
+ } else { '{}' }
116
+ [IO.File]::WriteAllText($OutputFile, $fallback, [Text.Encoding]::UTF8)
117
+ exit 0
118
+ }
119
+
120
+ # Helper: check if a parsed object has all required shape keys
121
+ function Test-ShapeMatch($obj) {
122
+ if ($shapeKeys.Count -eq 0) { return $true } # no shape constraint — accept any JSON object
123
+ foreach ($k in $shapeKeys) {
124
+ if (-not $obj.PSObject.Properties[$k]) { return $false }
125
+ }
126
+ return $true
127
+ }
128
+
129
+ $foundJson = $null
130
+
131
+ # 1: Look in ```json fenced blocks first
132
+ if ($cleaned -match '(?s)```json\s*(.*?)```') {
133
+ try {
134
+ $obj = $Matches[1].Trim() | ConvertFrom-Json -ErrorAction Stop
135
+ if (Test-ShapeMatch $obj) { $foundJson = $Matches[1].Trim() }
136
+ } catch {}
137
+ }
138
+
139
+ # 2: Scan for bare JSON objects
140
+ if (-not $foundJson) {
141
+ $depth = 0; $start = -1
142
+ for ($i = 0; $i -lt $cleaned.Length; $i++) {
143
+ if ($cleaned[$i] -eq '{') {
144
+ if ($depth -eq 0) { $start = $i }
145
+ $depth++
146
+ } elseif ($cleaned[$i] -eq '}') {
147
+ $depth--
148
+ if ($depth -eq 0 -and $start -ge 0) {
149
+ $candidate = $cleaned.Substring($start, $i - $start + 1)
150
+ try {
151
+ $obj = $candidate | ConvertFrom-Json -ErrorAction Stop
152
+ if (Test-ShapeMatch $obj) {
153
+ $foundJson = $candidate
154
+ break
155
+ }
156
+ } catch {}
157
+ $start = -1
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ if ($foundJson) {
164
+ [IO.File]::WriteAllText($OutputFile, $foundJson, [Text.Encoding]::UTF8)
165
+ } else {
166
+ # No matching JSON found — record raw in noise file, write shape-skeleton fallback
167
+ $NoiseFile = $OutputFile + '.noise'
168
+ $fallbackNoise = "FALLBACK=no_json_match`nSHAPE_KEYS=$($shapeKeys -join ',')`nRAW_LENGTH=$($cleaned.Length)`n---`n$cleaned"
169
+ if (Test-Path $NoiseFile) {
170
+ $existing = [IO.File]::ReadAllText($NoiseFile, [Text.Encoding]::UTF8)
171
+ [IO.File]::WriteAllText($NoiseFile, "$existing`n$fallbackNoise", [Text.Encoding]::UTF8)
172
+ } else {
173
+ [IO.File]::WriteAllText($NoiseFile, $fallbackNoise, [Text.Encoding]::UTF8)
174
+ }
175
+ $fallback = if ($shapeKeys.Count -gt 0) {
176
+ $obj = [ordered]@{}
177
+ foreach ($k in $shapeKeys) { $obj[$k] = $null }
178
+ $obj | ConvertTo-Json -Depth 2 -Compress
179
+ } else { '{}' }
180
+ [IO.File]::WriteAllText($OutputFile, $fallback, [Text.Encoding]::UTF8)
181
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yaml-flow",
3
- "version": "5.2.5",
3
+ "version": "5.2.6",
4
4
  "description": "Unified workflow engine: step-machine (sequential) + event-graph (stateless DAG) with pluggable storage",
5
5
  "author": "",
6
6
  "license": "MIT",