@cnrai/pave 0.3.35 → 0.3.51

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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -218
  3. package/package.json +32 -35
  4. package/pave.js +3 -0
  5. package/sandbox/SandboxRunner.js +1 -0
  6. package/sandbox/pave-run.js +2 -0
  7. package/sandbox/permission.js +1 -0
  8. package/sandbox/utils/yaml.js +1 -0
  9. package/MARKETPLACE.md +0 -406
  10. package/build-binary.js +0 -591
  11. package/build-npm.js +0 -537
  12. package/build.js +0 -230
  13. package/check-binary.js +0 -26
  14. package/deploy.sh +0 -95
  15. package/index.js +0 -5776
  16. package/lib/agent-registry.js +0 -1037
  17. package/lib/args-parser.js +0 -837
  18. package/lib/blessed-widget-patched.js +0 -93
  19. package/lib/cli-markdown.js +0 -590
  20. package/lib/compaction.js +0 -153
  21. package/lib/duration.js +0 -94
  22. package/lib/hash.js +0 -22
  23. package/lib/marketplace.js +0 -866
  24. package/lib/memory-config.js +0 -166
  25. package/lib/skill-manager.js +0 -891
  26. package/lib/soul.js +0 -31
  27. package/lib/tool-output-formatter.js +0 -180
  28. package/start-pave.sh +0 -149
  29. package/status.js +0 -271
  30. package/test/abort-stream.test.js +0 -445
  31. package/test/agent-auto-compaction.test.js +0 -552
  32. package/test/agent-comm-abort.test.js +0 -95
  33. package/test/agent-comm.test.js +0 -598
  34. package/test/agent-inbox.test.js +0 -576
  35. package/test/agent-init.test.js +0 -264
  36. package/test/agent-interrupt.test.js +0 -314
  37. package/test/agent-lifecycle.test.js +0 -520
  38. package/test/agent-log-files.test.js +0 -349
  39. package/test/agent-mode.manual-test.js +0 -392
  40. package/test/agent-parsing.test.js +0 -228
  41. package/test/agent-post-stream-idle.test.js +0 -762
  42. package/test/agent-registry.test.js +0 -359
  43. package/test/agent-rm.test.js +0 -442
  44. package/test/agent-spawn.test.js +0 -933
  45. package/test/agent-status-api.test.js +0 -624
  46. package/test/agent-update.test.js +0 -435
  47. package/test/args-parser.test.js +0 -391
  48. package/test/auto-compaction-chat.manual-test.js +0 -227
  49. package/test/auto-compaction.test.js +0 -941
  50. package/test/build-config.test.js +0 -120
  51. package/test/build-npm.test.js +0 -388
  52. package/test/chat-command.test.js +0 -137
  53. package/test/chat-leading-lines.test.js +0 -159
  54. package/test/config-flag.test.js +0 -272
  55. package/test/cursor-drift.test.js +0 -135
  56. package/test/debug-require.js +0 -23
  57. package/test/dir-migration.test.js +0 -323
  58. package/test/duration.test.js +0 -229
  59. package/test/ghostty-term.test.js +0 -202
  60. package/test/http500-backoff.test.js +0 -854
  61. package/test/integration.test.js +0 -86
  62. package/test/memory-guard-env.test.js +0 -220
  63. package/test/pr233-fixes.test.js +0 -259
  64. package/test/run-agent-init.js +0 -297
  65. package/test/run-all.js +0 -64
  66. package/test/run-config-flag.js +0 -159
  67. package/test/run-cursor-drift.js +0 -82
  68. package/test/run-session-path.js +0 -154
  69. package/test/run-tests.js +0 -643
  70. package/test/sandbox-redirect.test.js +0 -202
  71. package/test/session-path.test.js +0 -132
  72. package/test/shebang-strip.test.js +0 -241
  73. package/test/soul-reinject.test.js +0 -1027
  74. package/test/soul-reread.test.js +0 -281
  75. package/test/tool-output-formatter.test.js +0 -486
  76. package/test/tool-output-gating.test.js +0 -143
  77. package/test/tool-states.test.js +0 -167
  78. package/test/tools-flag.test.js +0 -65
  79. package/test/tui-attach.test.js +0 -1255
  80. package/test/tui-compaction.test.js +0 -354
  81. package/test/tui-wrap.test.js +0 -568
  82. package/test-binary.js +0 -52
  83. package/test-binary2.js +0 -36
package/lib/compaction.js DELETED
@@ -1,153 +0,0 @@
1
- /**
2
- * Shared constants and helpers for auto-compaction feature.
3
- * This module has NO side effects when required - safe to import in tests.
4
- *
5
- * @module lib/compaction
6
- */
7
-
8
- /**
9
- * Allowlist of model IDs known to support compaction.
10
- * This is a subset of models from opencode-lite/src/provider/models.js - only
11
- * models verified to work well with compaction prompts are included.
12
- * When an unknown model is specified, we fall back to a known model for compaction checks.
13
- */
14
- const KNOWN_COMPACTION_MODELS = [
15
- 'claude-opus-4.5',
16
- 'claude-opus-4.6',
17
- 'claude-sonnet-4', // Canonical model advertised in CLI help
18
- 'claude-sonnet-4.5',
19
- 'claude-sonnet-4.6',
20
- 'claude-3-5-sonnet-20241022',
21
- 'claude-3-5-haiku-20241022',
22
- 'claude-3-opus-20240229',
23
- 'gpt-4',
24
- 'gpt-4-turbo',
25
- 'gpt-3.5-turbo',
26
- ];
27
-
28
- /**
29
- * Default provider ID when no provider prefix is given in the model string.
30
- * Resolved at call time from env vars so tests/consumers can change env after require.
31
- * Precedence: PAVE_COMPACT_MODEL > PAVE_MODEL > hardcoded default ('github-copilot')
32
- */
33
- function getDefaultProviderIDForCompaction() {
34
- const compactSpec = process.env.PAVE_COMPACT_MODEL;
35
- if (compactSpec) {
36
- // PAVE_COMPACT_MODEL is set - use its provider when both provider and model are non-empty.
37
- if (compactSpec.includes('/')) {
38
- const compactParts = compactSpec.split('/');
39
- const compactProvider = (compactParts[0] || '').trim();
40
- const compactModel = compactParts.slice(1).join('/').trim();
41
- if (compactProvider && compactModel) return compactProvider;
42
- // Empty provider but present model (e.g. "/model") -> treat like bare model ID
43
- if (!compactProvider && compactModel) return 'github-copilot';
44
- // Empty model (e.g. "provider/") -> fall through to PAVE_MODEL/default
45
- } else {
46
- // Bare model ID (no provider prefix) -> use hardcoded default provider without consulting PAVE_MODEL
47
- return 'github-copilot';
48
- }
49
- }
50
- const mainSpec = process.env.PAVE_MODEL;
51
- if (mainSpec && mainSpec.includes('/')) {
52
- const mainParts = mainSpec.split('/');
53
- const mainProvider = (mainParts[0] || '').trim();
54
- const mainModel = mainParts.slice(1).join('/').trim();
55
- if (mainProvider && mainModel) return mainProvider;
56
- // Empty provider but present model -> treat like bare model ID
57
- if (!mainProvider && mainModel) return 'github-copilot';
58
- // Malformed main spec -> fall through to hardcoded default
59
- }
60
- return 'github-copilot';
61
- }
62
-
63
- /**
64
- * Default model ID for compaction operations.
65
- * Resolved at call time from env vars so tests/consumers can change env after require.
66
- * Precedence: PAVE_COMPACT_MODEL > PAVE_MODEL > hardcoded default ('claude-opus-4.5')
67
- */
68
- function getDefaultModelIDForCompaction() {
69
- const compactSpec = process.env.PAVE_COMPACT_MODEL;
70
- if (compactSpec) {
71
- let compactModel;
72
- if (compactSpec.includes('/')) {
73
- compactModel = compactSpec.split('/').slice(1).join('/').trim();
74
- } else {
75
- compactModel = compactSpec.trim();
76
- }
77
- if (compactModel) return compactModel;
78
- // Malformed compact spec (e.g. "provider/") -> fall through to mainSpec/default
79
- }
80
- const mainSpec = process.env.PAVE_MODEL;
81
- if (mainSpec) {
82
- let mainModel;
83
- if (mainSpec.includes('/')) {
84
- mainModel = mainSpec.split('/').slice(1).join('/').trim();
85
- } else {
86
- mainModel = mainSpec.trim();
87
- }
88
- if (mainModel) return mainModel;
89
- // Malformed main spec -> fall through to hardcoded default
90
- }
91
- return 'claude-opus-4.5';
92
- }
93
-
94
- /**
95
- * Parse a model string into provider and model IDs for compaction operations.
96
- * Model strings can be "provider/model" or just "model".
97
- *
98
- * @param {string} model - The model string to parse (e.g., "github-copilot/claude-opus-4.6" or "gpt-4")
99
- * @returns {{ providerID: string, modelID: string, compactionModelID: string }}
100
- */
101
- function parseModelForCompaction(model) {
102
- // Resolve defaults at call time (not module-load time) so env var changes are respected
103
- const defaultProviderID = getDefaultProviderIDForCompaction();
104
- const defaultModelID = getDefaultModelIDForCompaction();
105
-
106
- let providerID = defaultProviderID;
107
- let modelID = defaultModelID;
108
-
109
- if (model) {
110
- if (model.includes('/')) {
111
- const parts = model.split('/');
112
- const parsedProvider = (parts[0] || '').trim();
113
- const parsedModel = parts.slice(1).join('/').trim();
114
- if (parsedProvider) providerID = parsedProvider;
115
- // else: empty provider (e.g. "/model") -> keep default
116
- if (parsedModel) modelID = parsedModel;
117
- // else: empty model (e.g. "provider/") -> keep default
118
- } else {
119
- const trimmedModel = model.trim();
120
- if (trimmedModel) modelID = trimmedModel;
121
- }
122
- }
123
-
124
- // Use a known model for compaction checks if the parsed model is not in the registry.
125
- // Also validate that defaultModelID is known; fall back to hardcoded default if env var
126
- // specifies an unlisted model (e.g. PAVE_COMPACT_MODEL=gpt-4o).
127
- const HARDCODED_COMPACTION_DEFAULT = 'claude-opus-4.5';
128
- const knownFallback = KNOWN_COMPACTION_MODELS.includes(defaultModelID)
129
- ? defaultModelID : HARDCODED_COMPACTION_DEFAULT;
130
- const compactionModelID = KNOWN_COMPACTION_MODELS.includes(modelID) ? modelID : knownFallback;
131
-
132
- return { providerID, modelID, compactionModelID };
133
- }
134
-
135
- module.exports = {
136
- KNOWN_COMPACTION_MODELS,
137
- // NOTE: DEFAULT_* are exported as getters so they reflect current env vars
138
- // on each property access, e.g.:
139
- // const compaction = require('./compaction');
140
- // const modelIdNow = compaction.DEFAULT_MODEL_ID;
141
- //
142
- // Do NOT destructure these if you need dynamic behavior:
143
- // const { DEFAULT_MODEL_ID } = require('./compaction');
144
- // This will snapshot the value at require time and will not see later
145
- // process.env changes. Prefer calling the functions directly instead:
146
- // const { getDefaultModelIDForCompaction } = require('./compaction');
147
- // const modelIdNow = getDefaultModelIDForCompaction();
148
- get DEFAULT_PROVIDER_ID() { return getDefaultProviderIDForCompaction(); },
149
- get DEFAULT_MODEL_ID() { return getDefaultModelIDForCompaction(); },
150
- getDefaultProviderIDForCompaction,
151
- getDefaultModelIDForCompaction,
152
- parseModelForCompaction,
153
- };
package/lib/duration.js DELETED
@@ -1,94 +0,0 @@
1
- /**
2
- * Duration parsing and formatting utilities for PAVE agent mode
3
- * Side-effect-free module that can be safely imported by tests
4
- */
5
-
6
- // Maximum setTimeout delay (~24.8 days) - Node.js uses 32-bit signed integer for delays
7
- const MAX_SETTIMEOUT_MS = 2147483647;
8
- const MIN_SLEEP_MS = 1000; // Minimum 1 second to prevent tight loops
9
-
10
- /**
11
- * Parse sleep duration string to milliseconds
12
- * Supports: 5s (seconds), 5m (minutes), 1h (hours), 1d (days)
13
- * @param {string|null|undefined} duration - Duration string (e.g., '30m', '1h', '5s'), or falsy value for default
14
- * @returns {number} Duration in milliseconds (default: 5 minutes if not specified or empty)
15
- */
16
- function parseSleepDuration(duration) {
17
- if (!duration) return 5 * 60 * 1000; // Default: 5 minutes (handles null, undefined, empty string)
18
-
19
- const match = duration.match(/^(\d+(?:\.\d+)?)\s*(s|sec|m|min|h|hr|hour|d|day)?$/i);
20
- if (!match) {
21
- throw new Error(`Invalid sleep duration: ${duration}. Use format like '30m', '1h', '5s'`);
22
- }
23
-
24
- const value = parseFloat(match[1]);
25
- const unit = (match[2] || 'm').toLowerCase();
26
-
27
- // Validate value is positive
28
- if (value <= 0) {
29
- throw new Error(`Sleep duration must be greater than 0. Got: ${duration}`);
30
- }
31
-
32
- let ms;
33
- switch (unit) {
34
- case 's':
35
- case 'sec':
36
- ms = value * 1000;
37
- break;
38
- case 'm':
39
- case 'min':
40
- ms = value * 60 * 1000;
41
- break;
42
- case 'h':
43
- case 'hr':
44
- case 'hour':
45
- ms = value * 60 * 60 * 1000;
46
- break;
47
- case 'd':
48
- case 'day':
49
- ms = value * 24 * 60 * 60 * 1000;
50
- break;
51
- default:
52
- ms = value * 60 * 1000; // Default to minutes
53
- }
54
-
55
- // Validate minimum sleep duration
56
- if (ms < MIN_SLEEP_MS) {
57
- throw new Error(`Sleep duration must be at least 1 second. Got: ${duration}`);
58
- }
59
-
60
- // Validate maximum sleep duration (setTimeout limit)
61
- if (ms > MAX_SETTIMEOUT_MS) {
62
- throw new Error(`Sleep duration exceeds maximum of ~24.8 days. Got: ${duration}. Use a smaller value.`);
63
- }
64
-
65
- return ms;
66
- }
67
-
68
- /**
69
- * Format milliseconds to human-readable duration
70
- * @param {number} ms - Duration in milliseconds
71
- * @returns {string} Human-readable duration string
72
- */
73
- function formatDuration(ms) {
74
- if (ms < 1000) return `${ms}ms`;
75
- if (ms < 60000) {
76
- const seconds = ms / 1000;
77
- const precision = Number.isInteger(seconds) ? 0 : 1;
78
- return `${seconds.toFixed(precision)}s`;
79
- }
80
- if (ms < 3600000) {
81
- const minutes = ms / 60000;
82
- const precision = Number.isInteger(minutes) ? 0 : 1;
83
- return `${minutes.toFixed(precision)}m`;
84
- }
85
- if (ms < 86400000) return `${(ms / 3600000).toFixed(1)}h`;
86
- return `${(ms / 86400000).toFixed(1)}d`;
87
- }
88
-
89
- module.exports = {
90
- parseSleepDuration,
91
- formatDuration,
92
- MAX_SETTIMEOUT_MS,
93
- MIN_SLEEP_MS,
94
- };
package/lib/hash.js DELETED
@@ -1,22 +0,0 @@
1
- /**
2
- * Simple string hash utility for SOUL content change detection.
3
- *
4
- * Uses a fast non-cryptographic hash (djb2) which is sufficient for
5
- * detecting file content changes. Avoids depending on the 'crypto'
6
- * module so that the same function can be used in sandboxed test
7
- * environments where 'crypto' is not available.
8
- *
9
- * @param {string} str - Input string to hash
10
- * @returns {string} Hex string hash
11
- */
12
- function simpleHash(str) {
13
- let hash = 5381;
14
- for (let i = 0; i < str.length; i++) {
15
- // hash * 33 + char
16
- hash = ((hash << 5) + hash + str.charCodeAt(i)) | 0;
17
- }
18
- // Convert to unsigned 32-bit hex string
19
- return (hash >>> 0).toString(16);
20
- }
21
-
22
- module.exports = { simpleHash };