gentle-pi 2.7.0 → 3.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.
Files changed (122) hide show
  1. package/README.md +24 -6
  2. package/assets/agents/gentle-ai-worker.md +5 -1
  3. package/assets/agents/sdd-apply.md +9 -7
  4. package/assets/agents/sdd-archive.md +42 -23
  5. package/assets/agents/sdd-proposal.md +2 -2
  6. package/assets/agents/sdd-remediate.md +4 -4
  7. package/assets/agents/sdd-research.md +20 -48
  8. package/assets/agents/sdd-tasks.md +5 -5
  9. package/assets/agents/sdd-verify.md +6 -28
  10. package/assets/chains/sdd-full.chain.md +4 -22
  11. package/assets/chains/sdd-verify.chain.md +3 -12
  12. package/assets/orchestrator-delegation.md +33 -3
  13. package/assets/orchestrator-memory.md +20 -7
  14. package/assets/orchestrator.md +5 -3
  15. package/assets/sdd-orchestrator-workflow.md +25 -58
  16. package/assets/support/sdd-status-contract.md +9 -12
  17. package/docs/gentle-shell.md +14 -4
  18. package/docs/readme-reference.md +171 -32
  19. package/extensions/codegraph-tools.ts +2 -0
  20. package/extensions/gentle-agents.ts +281 -361
  21. package/extensions/gentle-ai.ts +588 -117
  22. package/extensions/gentle-shell.ts +74 -30
  23. package/extensions/pi-pretty.ts +63 -14
  24. package/extensions/quiet-tools.ts +1 -2
  25. package/extensions/startup-banner.ts +10 -9
  26. package/lib/agent-home.ts +8 -0
  27. package/lib/agent-profile-pin.ts +336 -0
  28. package/lib/agent-profiles.ts +28 -8
  29. package/lib/agents-config.ts +24 -2
  30. package/lib/agents-history.ts +3 -97
  31. package/lib/agents-keys.ts +27 -0
  32. package/lib/agents-protocol.ts +2 -15
  33. package/lib/agents-runner.ts +67 -111
  34. package/lib/agents-session-transport.ts +691 -0
  35. package/lib/command-palette-catalog.ts +87 -0
  36. package/lib/command-palette.ts +346 -0
  37. package/lib/native-choice-list.ts +5 -0
  38. package/lib/native-review-cli.ts +10 -97
  39. package/lib/review-publication-gate.ts +11 -1
  40. package/lib/review-repository.ts +1 -1
  41. package/lib/review-snapshot.ts +1 -0
  42. package/lib/review-transaction.ts +4 -2
  43. package/lib/sdd-preflight.ts +2 -1
  44. package/lib/sdd-research-capabilities.ts +18 -152
  45. package/lib/sdd-status.ts +7 -779
  46. package/lib/session-change-capture.ts +2 -1
  47. package/lib/session-changes.ts +8 -1
  48. package/lib/shell-bar.ts +21 -12
  49. package/lib/shell-card.ts +8 -12
  50. package/lib/shell-changes.ts +3 -2
  51. package/lib/shell-prompt.ts +25 -8
  52. package/lib/shell-sidebar-banner.ts +2 -2
  53. package/lib/shell-sidebar-layout.ts +5 -2
  54. package/lib/windows-session-transport.ts +877 -0
  55. package/package.json +3 -3
  56. package/runtime/native-review-cli.mjs +9 -96
  57. package/runtime/windows-session-transport.ps1 +791 -0
  58. package/scripts/test-packed-runner.mjs +1668 -20
  59. package/scripts/verify-package-files.mjs +0 -1
  60. package/tests/agent-home.test.ts +52 -0
  61. package/tests/agent-profiles.test.ts +30 -1
  62. package/tests/agents-config.test.ts +44 -0
  63. package/tests/agents-history.test.ts +12 -24
  64. package/tests/agents-runner.test.ts +307 -58
  65. package/tests/agents-session-transport-process.test.ts +249 -0
  66. package/tests/agents-session-transport.test.ts +823 -0
  67. package/tests/artifact-language.test.ts +10 -7
  68. package/tests/command-palette.test.ts +378 -0
  69. package/tests/delegated-key-learnings-contract.test.ts +2 -2
  70. package/tests/fixtures/agents-session-transport-process.mjs +108 -0
  71. package/tests/fixtures/legacy/sdd-research-v2.5.0.md +54 -0
  72. package/tests/fixtures/windows-session-bootstrap.ps1 +129 -0
  73. package/tests/fixtures/windows-session-compile.ps1 +110 -0
  74. package/tests/gentle-agents.test.ts +849 -356
  75. package/tests/gentle-ai.test.ts +472 -4
  76. package/tests/gentle-shell.test.ts +201 -8
  77. package/tests/native-choice-list.test.ts +13 -0
  78. package/tests/native-review-cli.test.ts +0 -33
  79. package/tests/odd-routing-contract.test.ts +208 -0
  80. package/tests/orchestrator-budget.test.ts +17 -2
  81. package/tests/package-manifest.test.ts +115 -27
  82. package/tests/persona-single-channel.test.ts +3 -3
  83. package/tests/pi-pretty.test.ts +45 -0
  84. package/tests/profile-pin.test.ts +370 -0
  85. package/tests/quiet-tool-rendering.test.ts +32 -5
  86. package/tests/review-contract-prompt.test.ts +9 -0
  87. package/tests/review-controller.test.ts +0 -44
  88. package/tests/review-session-standing-permission-ipc.test.ts +427 -13
  89. package/tests/runtime-harness.mjs +4 -4
  90. package/tests/sdd-agent-tools.test.ts +15 -36
  91. package/tests/sdd-archive-replay.test.ts +82 -0
  92. package/tests/sdd-classical-continuation.test.ts +74 -0
  93. package/tests/sdd-execution-routing-contract.test.ts +18 -2
  94. package/tests/sdd-managed-runtime-settlement.test.ts +42 -330
  95. package/tests/sdd-native-managed-uptake.test.ts +11 -21
  96. package/tests/sdd-no-attempts-contract.test.ts +15 -0
  97. package/tests/sdd-odd-integration.test.ts +33 -0
  98. package/tests/sdd-optional-research.test.ts +124 -0
  99. package/tests/sdd-planning-routing-contract.test.ts +1 -1
  100. package/tests/sdd-preflight-rpc-input.test.ts +125 -0
  101. package/tests/sdd-preflight.test.ts +1 -1
  102. package/tests/sdd-research-capabilities.test.ts +20 -162
  103. package/tests/sdd-selection-transport.test.ts +180 -88
  104. package/tests/sdd-status.test.ts +5 -778
  105. package/tests/sdd-task-truth.test.ts +43 -0
  106. package/tests/session-change-capture.test.ts +20 -2
  107. package/tests/session-changes.test.ts +11 -0
  108. package/tests/shell-bar.test.ts +21 -0
  109. package/tests/shell-card.test.ts +8 -6
  110. package/tests/shell-changes.test.ts +8 -0
  111. package/tests/shell-prompt.test.ts +41 -7
  112. package/tests/shell-sidebar-banner.test.ts +4 -4
  113. package/tests/shell-sidebar-layout.test.ts +97 -13
  114. package/tests/startup-banner.test.ts +55 -2
  115. package/tests/windows-hidden-processes.test.ts +303 -0
  116. package/tests/windows-session-bootstrap.test.ts +1772 -0
  117. package/tests/windows-session-compile.test.ts +170 -0
  118. package/tests/windows-session-transport.test.ts +754 -0
  119. package/assets/agents/sdd-sync.md +0 -146
  120. package/lib/openspec-guardrails.ts +0 -99
  121. package/tests/native-sdd-attempt-authority.test.ts +0 -240
  122. package/tests/openspec-guardrails.test.ts +0 -71
@@ -0,0 +1,129 @@
1
+ # Test-only ACL/reparse inspector. It never emits SIDs or descriptor bytes.
2
+ param(
3
+ [Parameter(Mandatory = $true)][ValidateSet('capture', 'equals', 'measure', 'add-extra-ace', 'junction', 'rename', 'replace-identical', 'hardlink', 'append', 'exclusive-open')][string]$Mode,
4
+ [Parameter(Mandatory = $true)][string]$Path,
5
+ [string]$BaselinePath,
6
+ [string]$Target
7
+ )
8
+ Set-StrictMode -Version Latest
9
+ $ErrorActionPreference = 'Stop'
10
+ function Write-Result([hashtable]$result) { [Console]::Out.WriteLine(($result | ConvertTo-Json -Compress)) }
11
+ function Get-ReplacementHResult($errorRecord) {
12
+ if ($null -eq $errorRecord) { return $null }
13
+ $exceptionProperty = $errorRecord.PSObject.Properties['Exception']
14
+ if ($null -eq $exceptionProperty -or $exceptionProperty.Value -isnot [Exception]) { return $null }
15
+ try { $baseException = $exceptionProperty.Value.GetBaseException() } catch { return $null }
16
+ if ($baseException -isnot [IO.IOException] -and $baseException -isnot [UnauthorizedAccessException] -and $baseException -isnot [Security.SecurityException] -and $baseException -isnot [ComponentModel.Win32Exception]) { return $null }
17
+ $hresultProperty = $baseException.PSObject.Properties['HResult']
18
+ if ($null -eq $hresultProperty -or $hresultProperty.Value -isnot [int] -or $hresultProperty.Value -eq 0) { return $null }
19
+ return [int]$hresultProperty.Value
20
+ }
21
+ try {
22
+ if ($Mode -eq 'capture') {
23
+ if ([string]::IsNullOrEmpty($BaselinePath)) { throw 'baseline-required' }
24
+ $acl = Get-Acl -LiteralPath $Path
25
+ [IO.File]::WriteAllBytes($BaselinePath, $acl.GetSecurityDescriptorBinaryForm())
26
+ Write-Result @{ ok = $true; equal = $true }
27
+ exit 0
28
+ }
29
+ if ($Mode -eq 'equals') {
30
+ if ([string]::IsNullOrEmpty($BaselinePath) -or -not [IO.File]::Exists($BaselinePath)) { throw 'baseline-required' }
31
+ $actual = (Get-Acl -LiteralPath $Path).GetSecurityDescriptorBinaryForm()
32
+ $expected = [IO.File]::ReadAllBytes($BaselinePath)
33
+ Write-Result @{ ok = $true; equal = ([Convert]::ToBase64String($actual) -ceq [Convert]::ToBase64String($expected)) }
34
+ exit 0
35
+ }
36
+ if ($Mode -eq 'add-extra-ace') {
37
+ $acl = Get-Acl -LiteralPath $Path
38
+ $authenticatedUsers = [Security.Principal.SecurityIdentifier]::new([Security.Principal.WellKnownSidType]::AuthenticatedUserSid, $null)
39
+ $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new($authenticatedUsers, [Security.AccessControl.FileSystemRights]::ReadAndExecute, [Security.AccessControl.AccessControlType]::Allow))
40
+ Set-Acl -LiteralPath $Path -AclObject $acl
41
+ Write-Result @{ ok = $true; changed = $true }
42
+ exit 0
43
+ }
44
+ if ($Mode -eq 'replace-identical') {
45
+ $temp = "$Path.replacement"
46
+ $replacementStage = 'replacement-copy'
47
+ try {
48
+ [IO.File]::Copy($Path, $temp, $true)
49
+ $replacementStage = 'replacement-acl'
50
+ Set-Acl -LiteralPath $temp -AclObject (Get-Acl -LiteralPath $Path)
51
+ $replacementStage = 'replacement-rename'
52
+ Add-Type -TypeDefinition @'
53
+ using System;
54
+ using System.Runtime.InteropServices;
55
+ public static class WindowsSessionBootstrapFixture {
56
+ [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] public static extern bool MoveFileEx(string source, string destination, uint flags);
57
+ }
58
+ '@ -ErrorAction Stop
59
+ $original = "$Path.original-$([Guid]::NewGuid().ToString('N'))"
60
+ $movedOriginal = [WindowsSessionBootstrapFixture]::MoveFileEx($Path, $original, 0)
61
+ if (-not $movedOriginal) {
62
+ $replacementCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
63
+ $replacementCodeKind = if ($replacementCode -eq 0) { 'unknown' } else { 'win32' }
64
+ if ($replacementCodeKind -eq 'unknown') { $replacementCode = $null }
65
+ Write-Result @{ ok = $false; kind = 'windows-session-bootstrap-fixture-failure'; stage = $replacementStage; codeKind = $replacementCodeKind; code = $replacementCode }
66
+ exit 1
67
+ }
68
+ $movedReplacement = [WindowsSessionBootstrapFixture]::MoveFileEx($temp, $Path, 0)
69
+ if (-not $movedReplacement) {
70
+ $replacementCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
71
+ $replacementCodeKind = if ($replacementCode -eq 0) { 'unknown' } else { 'win32' }
72
+ if ($replacementCodeKind -eq 'unknown') { $replacementCode = $null }
73
+ Write-Result @{ ok = $false; kind = 'windows-session-bootstrap-fixture-failure'; stage = $replacementStage; codeKind = $replacementCodeKind; code = $replacementCode }
74
+ exit 1
75
+ }
76
+ } catch {
77
+ $replacementCode = Get-ReplacementHResult $_
78
+ $replacementCodeKind = if ($null -eq $replacementCode) { 'unknown' } else { 'hresult' }
79
+ Write-Result @{ ok = $false; kind = 'windows-session-bootstrap-fixture-failure'; stage = $replacementStage; codeKind = $replacementCodeKind; code = $replacementCode }
80
+ exit 1
81
+ }
82
+ Write-Result @{ ok = $true; replaced = $true }
83
+ exit 0
84
+ }
85
+ if ($Mode -eq 'hardlink') {
86
+ if ([string]::IsNullOrEmpty($Target)) { throw 'target-required' }
87
+ Add-Type -TypeDefinition @'
88
+ using System;
89
+ using System.Runtime.InteropServices;
90
+ public static class WindowsSessionBootstrapHardlinkFixture {
91
+ [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] public static extern bool CreateHardLink(string name, string existing, IntPtr security);
92
+ }
93
+ '@ -ErrorAction Stop
94
+ if (-not [WindowsSessionBootstrapHardlinkFixture]::CreateHardLink($Target, $Path, [IntPtr]::Zero)) { throw 'hardlink-failed' }
95
+ Write-Result @{ ok = $true; hardlink = $true }
96
+ exit 0
97
+ }
98
+ if ($Mode -eq 'exclusive-open') {
99
+ $stream = [IO.File]::Open($Path, [IO.FileMode]::Open, [IO.FileAccess]::ReadWrite, [IO.FileShare]::None)
100
+ try { Write-Result @{ ok = $true; exclusive = $true } } finally { $stream.Dispose() }
101
+ exit 0
102
+ }
103
+ if ($Mode -eq 'append') {
104
+ $bytes = [Text.Encoding]::UTF8.GetBytes(('x' * 8193))
105
+ $share = [IO.FileShare]::ReadWrite -bor [IO.FileShare]::Delete
106
+ $stream = [IO.FileStream]::new($Path, [IO.FileMode]::Append, [IO.FileAccess]::Write, $share)
107
+ try { $stream.Write($bytes, 0, $bytes.Length); $stream.Flush(); Write-Result @{ ok = $true; appended = $true } } finally { $stream.Dispose() }
108
+ exit 0
109
+ }
110
+ if ($Mode -eq 'rename') {
111
+ if ([string]::IsNullOrEmpty($Target)) { throw 'target-required' }
112
+ [IO.Directory]::Move($Path, $Target)
113
+ Write-Result @{ ok = $true; renamed = $true }
114
+ exit 0
115
+ }
116
+ if ($Mode -eq 'junction') {
117
+ if ([string]::IsNullOrEmpty($Target)) { throw 'target-required' }
118
+ New-Item -ItemType Junction -Path $Path -Target $Target | Out-Null
119
+ Write-Result @{ ok = $true; reparse = $true }
120
+ exit 0
121
+ }
122
+ $item = Get-Item -LiteralPath $Path -Force
123
+ $sid = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
124
+ $acl = Get-Acl -LiteralPath $Path
125
+ $rules = @($acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
126
+ $ownerCurrent = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value -eq $sid
127
+ $private = $ownerCurrent -and $acl.AreAccessRulesProtected -and $rules.Count -eq 1 -and -not $rules[0].IsInherited -and $rules[0].IdentityReference.Value -eq $sid -and $rules[0].AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and [int64]$rules[0].FileSystemRights -eq [int64][Security.AccessControl.FileSystemRights]::FullControl
128
+ Write-Result @{ ok = $true; directory = $item.PSIsContainer; reparse = (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0); ownerCurrent = $ownerCurrent; privateBoundary = $private }
129
+ } catch { Write-Result @{ ok = $false }; exit 1 }
@@ -0,0 +1,110 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [string]$SourcePath
4
+ )
5
+
6
+ $maxEntries = 8
7
+ $maxLocation = 1000000
8
+ $stage = 'control-failure'
9
+ $outcome = 'not-compiled'
10
+ $sourceExtracted = $false
11
+ $success = $false
12
+ $errorList = [System.Collections.Generic.List[object]]::new()
13
+ $warningList = [System.Collections.Generic.List[object]]::new()
14
+ $tempRoot = $null
15
+ $tempFiles = $null
16
+ $provider = $null
17
+
18
+ function Add-CompilerEntry([System.Collections.Generic.List[object]]$entries, [object]$compilerError) {
19
+ if ($entries.Count -ge $maxEntries) { return }
20
+ $code = [string]$compilerError.ErrorNumber
21
+ if ($code -cnotmatch '\ACS[0-9]{4}\z') { return }
22
+ $line = 0
23
+ $column = 0
24
+ try { $line = [Convert]::ToInt32($compilerError.Line) } catch {}
25
+ try { $column = [Convert]::ToInt32($compilerError.Column) } catch {}
26
+ if ($line -lt 0 -or $line -gt $maxLocation) { $line = 0 }
27
+ if ($column -lt 0 -or $column -gt $maxLocation) { $column = 0 }
28
+ $entries.Add([pscustomobject]@{ code = $code; line = $line; column = $column })
29
+ }
30
+
31
+ function Get-AddTypeLiteral([System.Management.Automation.Language.Ast]$ast) {
32
+ $commands = @($ast.FindAll({ param($node) $node -is [System.Management.Automation.Language.CommandAst] -and $node.GetCommandName() -ceq 'Add-Type' }, $true))
33
+ if ($commands.Count -ne 1) { return $null }
34
+ $values = [System.Collections.Generic.List[string]]::new()
35
+ $elements = $commands[0].CommandElements
36
+ for ($index = 0; $index -lt $elements.Count; $index++) {
37
+ $element = $elements[$index]
38
+ if ($element -isnot [System.Management.Automation.Language.CommandParameterAst] -or $element.ParameterName -cne 'TypeDefinition') { continue }
39
+ if ($index + 1 -ge $elements.Count -or $elements[$index + 1] -isnot [System.Management.Automation.Language.StringConstantExpressionAst]) { return $null }
40
+ $values.Add([string]$elements[$index + 1].Value)
41
+ }
42
+ if ($values.Count -ne 1 -or [string]::IsNullOrEmpty($values[0])) { return $null }
43
+ return $values[0]
44
+ }
45
+
46
+ try {
47
+ $resolvedSource = (Resolve-Path -LiteralPath $SourcePath -ErrorAction Stop).Path
48
+ $tokens = $null
49
+ $parseErrors = $null
50
+ $ast = [System.Management.Automation.Language.Parser]::ParseFile($resolvedSource, [ref]$tokens, [ref]$parseErrors)
51
+ if ($null -eq $ast -or $null -eq $parseErrors -or $parseErrors.Count -ne 0) {
52
+ $stage = 'source-parse'
53
+ } else {
54
+ $literal = Get-AddTypeLiteral $ast
55
+ if ($null -eq $literal) {
56
+ $stage = 'source-contract'
57
+ } else {
58
+ $sourceExtracted = $true
59
+ $tempRoot = [IO.Path]::Combine([IO.Path]::GetTempPath(), ('gentle-pi-csharp-control-' + [Guid]::NewGuid().ToString('N')))
60
+ [void][IO.Directory]::CreateDirectory($tempRoot)
61
+ $tempFiles = [System.CodeDom.Compiler.TempFileCollection]::new($tempRoot, $false)
62
+ $parameters = [System.CodeDom.Compiler.CompilerParameters]::new()
63
+ $parameters.GenerateExecutable = $false
64
+ $parameters.GenerateInMemory = $true
65
+ $parameters.TempFiles = $tempFiles
66
+ # This Framework baseline is a compile-control comparison, not proof that Add-Type uses an identical reference set.
67
+ [void]$parameters.ReferencedAssemblies.Add("System.dll")
68
+ [void]$parameters.ReferencedAssemblies.Add("System.Core.dll")
69
+ $provider = [Microsoft.CSharp.CSharpCodeProvider]::new()
70
+ $result = $provider.CompileAssemblyFromSource($parameters, $literal)
71
+ $hasCompilerErrors = $false
72
+ foreach ($compilerError in $result.Errors) {
73
+ if ($compilerError.IsWarning) { Add-CompilerEntry $warningList $compilerError }
74
+ else { $hasCompilerErrors = $true; Add-CompilerEntry $errorList $compilerError }
75
+ }
76
+ if ($hasCompilerErrors -and $errorList.Count -eq 0) { throw [InvalidOperationException]::new('CSharp compiler error had no reportable code') }
77
+ $stage = if ($hasCompilerErrors) { 'compile' } else { 'completed' }
78
+ $outcome = if ($hasCompilerErrors) { 'compile-errors' } else { 'compile-success' }
79
+ $success = -not $hasCompilerErrors
80
+ }
81
+ }
82
+ } catch {
83
+ $stage = 'control-failure'
84
+ $success = $false
85
+ } finally {
86
+ $cleanupFailed = $false
87
+ if ($null -ne $provider) { try { $provider.Dispose() } catch { $cleanupFailed = $true } }
88
+ if ($null -ne $tempFiles) { try { $tempFiles.Dispose() } catch { $cleanupFailed = $true } }
89
+ if ($null -ne $tempRoot) { try { if ([IO.Directory]::Exists($tempRoot)) { [IO.Directory]::Delete($tempRoot, $true) } } catch { $cleanupFailed = $true } }
90
+ if ($cleanupFailed) {
91
+ $stage = 'control-failure'
92
+ $outcome = 'not-compiled'
93
+ $success = $false
94
+ $errorList.Clear()
95
+ $warningList.Clear()
96
+ }
97
+ $record = [ordered]@{
98
+ kind = 'windows-session-csharp-compile-control'
99
+ success = $success
100
+ sourceExtracted = $sourceExtracted
101
+ stage = $stage
102
+ outcome = $outcome
103
+ errorlist = @($errorList.ToArray())
104
+ }
105
+ if ($warningList.Count -gt 0) { $record.warnings = @($warningList.ToArray()) }
106
+ [Console]::Out.WriteLine(($record | ConvertTo-Json -Compress -Depth 3))
107
+ }
108
+
109
+ if ($success) { exit 0 }
110
+ exit 1