@commonlyai/cli 0.1.171 → 0.1.172
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/package.json
CHANGED
|
@@ -81,7 +81,7 @@ import { deliverSeatCredential, withholdRuntimeCredential } from '../mcp-credent
|
|
|
81
81
|
import {
|
|
82
82
|
prepareMcpSpawn, PUBLIC_MCP_UNAVAILABLE_CODE, publicMcpUnavailableError, selectedMcpVersionDir,
|
|
83
83
|
} from '../mcp-home.js';
|
|
84
|
-
import { buildMemoryPreamble } from '../memory-bridge.js';
|
|
84
|
+
import { buildMemoryPreamble, ROW_SLICING_CUE } from '../memory-bridge.js';
|
|
85
85
|
import { claudeConfigDirFor, claudeContextTokens } from '../session-recycle.js';
|
|
86
86
|
import { skillsAsText } from '../skill-prompt.js';
|
|
87
87
|
import { adapterFailure, spawnCredentials } from '../upstream-refusal.js';
|
|
@@ -98,6 +98,16 @@ const DEFAULT_TIMEOUT_MS = (() => {
|
|
|
98
98
|
})();
|
|
99
99
|
|
|
100
100
|
const buildPrompt = buildMemoryPreamble;
|
|
101
|
+
|
|
102
|
+
// The working habits a private claude seat is taught on a fresh session (D48,
|
|
103
|
+
// TASK-545). Parallel reads live here because only this CLI has a subagent
|
|
104
|
+
// tool; codex is passed row slicing alone. A public seat is passed neither: its
|
|
105
|
+
// argv allows Read and the MCP under dontAsk, so it has no subagent to spawn,
|
|
106
|
+
// and it answers strangers rather than working board rows.
|
|
107
|
+
const PARALLEL_READS_CUE = 'Parallel reads: when a row needs several files or sources read, '
|
|
108
|
+
+ 'use the Agent tool. Spawn read-only subagents in parallel, brief each one with the files '
|
|
109
|
+
+ 'to read and the question to answer, and keep only their conclusions.';
|
|
110
|
+
const WORK_CUES = [PARALLEL_READS_CUE, ROW_SLICING_CUE];
|
|
101
111
|
const RUNTIME_CREDENTIAL_PLACEHOLDER = '${COMMONLY_AGENT_TOKEN}';
|
|
102
112
|
|
|
103
113
|
const QUOTE_SHELL_ARGUMENT = (value) => `'${String(value).replaceAll("'", "'\\''")}'`;
|
|
@@ -799,7 +809,12 @@ export default {
|
|
|
799
809
|
// the only two paths that build a real prompt. buildPrompt handles
|
|
800
810
|
// undefined and '' as absence itself; it does not need a guard, it needs
|
|
801
811
|
// the value.
|
|
802
|
-
const
|
|
812
|
+
const publicTrust = ctx.environment?.sandbox?.trust === 'public';
|
|
813
|
+
const workCues = publicTrust ? [] : WORK_CUES;
|
|
814
|
+
const fullPrompt = buildPrompt(prompt, ctx.memoryLongTerm, {
|
|
815
|
+
freshSession: !isResume,
|
|
816
|
+
workCues,
|
|
817
|
+
});
|
|
803
818
|
const sessionFlag = isResume ? '--resume' : '--session-id';
|
|
804
819
|
// Model pin from the ADR-008 environment spec. Absent it, claude picks its
|
|
805
820
|
// own default — which is how a fleet of ten agents ended up running three
|
|
@@ -839,7 +854,6 @@ export default {
|
|
|
839
854
|
let mcpConfig = null;
|
|
840
855
|
let publicClaudeState = null;
|
|
841
856
|
let publicSkillArgs = [];
|
|
842
|
-
const publicTrust = ctx.environment?.sandbox?.trust === 'public';
|
|
843
857
|
const publicNativeSandbox = publicTrust
|
|
844
858
|
&& PUBLIC_SANDBOX_MODES.has(resolvePublicSandboxMode(ctx.environment?.sandbox));
|
|
845
859
|
const publicBwrapSandbox = publicTrust
|
|
@@ -927,7 +941,10 @@ export default {
|
|
|
927
941
|
// The retry creates a new underlying CLI session. Rebuild its prompt
|
|
928
942
|
// as fresh too: otherwise a session-recovery path is the one fresh
|
|
929
943
|
// session that misses the durable-state cue.
|
|
930
|
-
const freshPrompt = buildPrompt(prompt, ctx.memoryLongTerm, {
|
|
944
|
+
const freshPrompt = buildPrompt(prompt, ctx.memoryLongTerm, {
|
|
945
|
+
freshSession: true,
|
|
946
|
+
workCues,
|
|
947
|
+
});
|
|
931
948
|
const retryBase = ['-p', freshPrompt,
|
|
932
949
|
'--output-format', 'text', '--session-id', freshId, ...modelArgs];
|
|
933
950
|
const retryCtx = {
|
|
@@ -66,7 +66,7 @@ import { CREDENTIAL_KEY, writeCredentialFile } from '../credential-file.js';
|
|
|
66
66
|
import { supportedGitHooks } from '../commit-attribution.js';
|
|
67
67
|
import { deliverSeatCredential, withholdRuntimeCredential } from '../mcp-credential-delivery.js';
|
|
68
68
|
import { prepareMcpSpawn, publicMcpUnavailableError, selectedMcpVersionDir } from '../mcp-home.js';
|
|
69
|
-
import { buildMemoryPreamble } from '../memory-bridge.js';
|
|
69
|
+
import { buildMemoryPreamble, ROW_SLICING_CUE } from '../memory-bridge.js';
|
|
70
70
|
import { resolveSkillSource, skillsAsText } from '../skill-prompt.js';
|
|
71
71
|
import { isLegacySandboxTrust, normalizeSandboxTrust } from '../environment.js';
|
|
72
72
|
import { adapterFailure, spawnCredentials } from '../upstream-refusal.js';
|
|
@@ -650,14 +650,20 @@ export default {
|
|
|
650
650
|
|
|
651
651
|
async spawn(prompt, ctx = {}) {
|
|
652
652
|
const seatModel = requireSeatModel(ctx.environment, 'codex');
|
|
653
|
+
const sandbox = normalizeSandboxTrust(ctx.environment?.sandbox);
|
|
653
654
|
// Passed through UNCOALESCED. `ctx.memoryLongTerm || ''` was here, and
|
|
654
655
|
// `null || ''` is `''` — which routed the unreadable case straight into
|
|
655
656
|
// the empty-memory branch and made the whole distinction unreachable from
|
|
656
657
|
// the only two paths that build a real prompt. buildPrompt handles
|
|
657
658
|
// undefined and '' as absence itself; it does not need a guard, it needs
|
|
658
659
|
// the value.
|
|
660
|
+
//
|
|
661
|
+
// Codex has no subagent tool, so of D48's two habits (TASK-545) it is
|
|
662
|
+
// taught row slicing alone; claude.js adds parallel reads. A public seat
|
|
663
|
+
// answers strangers rather than working board rows, so it is taught neither.
|
|
659
664
|
const fullPrompt = buildPrompt(prompt, ctx.memoryLongTerm, {
|
|
660
665
|
freshSession: !ctx.sessionId,
|
|
666
|
+
workCues: sandbox?.trust === 'public' ? [] : [ROW_SLICING_CUE],
|
|
661
667
|
});
|
|
662
668
|
|
|
663
669
|
// Per-spawn temp dir for --output-last-message. Cleaned up in `finally`
|
|
@@ -674,7 +680,6 @@ export default {
|
|
|
674
680
|
});
|
|
675
681
|
|
|
676
682
|
try {
|
|
677
|
-
const sandbox = normalizeSandboxTrust(ctx.environment?.sandbox);
|
|
678
683
|
const mcp = buildMcpOverrideArgs(ctx.environment?.mcp, {
|
|
679
684
|
runtimeToken: ctx.runtimeToken,
|
|
680
685
|
instanceUrl: ctx.instanceUrl,
|
package/src/lib/memory-bridge.js
CHANGED
|
@@ -22,6 +22,18 @@
|
|
|
22
22
|
|
|
23
23
|
export const SOURCE_RUNTIME = 'local-cli';
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Row slicing, the runtime-agnostic half of D48 (TASK-545). A row too large
|
|
27
|
+
* for one turn drifts when one seat carries it whole, so the seat splits it on
|
|
28
|
+
* the board before any code. It names the exact call and field for the reason
|
|
29
|
+
* the memory cue below names `long_term`: a seat adopts a habit through a
|
|
30
|
+
* surface it can see. Each adapter decides whether to pass it.
|
|
31
|
+
*/
|
|
32
|
+
export const ROW_SLICING_CUE = 'Slicing: when a row is too large for one turn, split it before '
|
|
33
|
+
+ 'writing any code. Post each slice as a child row (commonly_create_task with parentTask set '
|
|
34
|
+
+ "to the row's taskId) with one assignee, a written file or area boundary, and its own "
|
|
35
|
+
+ 'acceptance line.';
|
|
36
|
+
|
|
25
37
|
/**
|
|
26
38
|
* The turn preamble, shared by every adapter so the two cannot drift.
|
|
27
39
|
*
|
|
@@ -39,8 +51,17 @@ export const SOURCE_RUNTIME = 'local-cli';
|
|
|
39
51
|
* the section whose name most invites exactly this use — succeeds, returns 200,
|
|
40
52
|
* and is never seen again; the write and the silence are indistinguishable from
|
|
41
53
|
* a correct round trip. Naming the section is the whole point of the cue.
|
|
54
|
+
*
|
|
55
|
+
* `workCues` are working habits an adapter teaches on a fresh session, beside
|
|
56
|
+
* the memory cues and under the same once-per-session rule. An adapter passes
|
|
57
|
+
* only the habits its CLI can act on; passing none leaves the preamble as it
|
|
58
|
+
* was.
|
|
42
59
|
*/
|
|
43
|
-
export const buildMemoryPreamble = (
|
|
60
|
+
export const buildMemoryPreamble = (
|
|
61
|
+
prompt,
|
|
62
|
+
memoryLongTerm,
|
|
63
|
+
{ freshSession = false, workCues = [] } = {},
|
|
64
|
+
) => {
|
|
44
65
|
// `null` is the UNREADABLE signal, and it is deliberately not the same value
|
|
45
66
|
// as `''`. Telling a seat whose token was revoked that "nothing has ever been
|
|
46
67
|
// saved here" is a false claim about its own history, and it is the same
|
|
@@ -87,7 +108,10 @@ export const buildMemoryPreamble = (prompt, memoryLongTerm, { freshSession = fal
|
|
|
87
108
|
+ 'gates held, decisions pending, and task context, not a transcript — using '
|
|
88
109
|
+ 'the long_term write above.';
|
|
89
110
|
}
|
|
90
|
-
|
|
111
|
+
const workCue = workCues.length
|
|
112
|
+
? `\n=== Working a row ===\n${workCues.map((cue) => `- ${cue}`).join('\n')}\n`
|
|
113
|
+
: '';
|
|
114
|
+
return `${context}\n${freshReadCue}${workCue}\n=== Current turn ===\n${prompt}\n${sessionEndCue}`;
|
|
91
115
|
};
|
|
92
116
|
|
|
93
117
|
export const readLongTerm = async (client, { onError } = {}) => {
|