@superjackfruitlabs/salaam 0.0.3 → 0.0.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/CHANGELOG.md +86 -0
- package/README.md +12 -11
- package/dist/src/acp-desk.js +140 -0
- package/dist/src/acp-outcome.js +182 -18
- package/dist/src/acp.js +296 -15
- package/dist/src/agent-profiles.js +45 -0
- package/dist/src/agentpod-authority.js +169 -11
- package/dist/src/agentpod-default-config.js +12 -0
- package/dist/src/agentpod-work-decision-protocol.js +40 -6
- package/dist/src/agentpod-work-decisions.js +108 -4
- package/dist/src/agentpod-work.js +1214 -127
- package/dist/src/approval-rules.js +287 -0
- package/dist/src/attach.js +3 -1
- package/dist/src/autonomy.js +80 -9
- package/dist/src/board-reads.js +106 -0
- package/dist/src/children.js +83 -0
- package/dist/src/cli-help.js +61 -6
- package/dist/src/cli.js +140 -4
- package/dist/src/command-danger.js +797 -0
- package/dist/src/command-network.js +200 -0
- package/dist/src/command-sandbox.js +327 -0
- package/dist/src/custom-commands.js +159 -0
- package/dist/src/danger-classifier.js +286 -0
- package/dist/src/execution-evidence.js +33 -1
- package/dist/src/git-helpers.js +160 -0
- package/dist/src/hooks.js +351 -0
- package/dist/src/host-bind.js +111 -0
- package/dist/src/host-breaker.js +88 -0
- package/dist/src/host-start.js +41 -1
- package/dist/src/host.js +284 -6
- package/dist/src/house-extension.js +292 -61
- package/dist/src/local-coding.js +726 -35
- package/dist/src/local-edit-helper.js +25 -0
- package/dist/src/local-edits.js +168 -6
- package/dist/src/local-undo.js +25 -16
- package/dist/src/managed.js +1 -1
- package/dist/src/mentions.js +277 -0
- package/dist/src/operator-mcp-cli.js +107 -0
- package/dist/src/operator-mcp.js +342 -0
- package/dist/src/persona.js +31 -0
- package/dist/src/pi-sessions.js +5 -1
- package/dist/src/pi.js +22 -1
- package/dist/src/project-instructions.js +195 -0
- package/dist/src/protocol.js +9 -3
- package/dist/src/rate-limit-retries.js +62 -0
- package/dist/src/recurring-work.js +1 -0
- package/dist/src/repository-snapshots.js +5 -2
- package/dist/src/run-grants.js +62 -0
- package/dist/src/service.js +482 -10
- package/dist/src/session-pick.js +77 -0
- package/dist/src/shell-passthrough.js +39 -0
- package/dist/src/station-checkpoints.js +139 -0
- package/dist/src/station-config.js +8 -1
- package/dist/src/station-files.js +20 -1
- package/dist/src/station-task-verification.js +6 -3
- package/dist/src/station-work.js +315 -22
- package/dist/src/store.js +70 -4
- package/dist/src/supervisor.js +408 -25
- package/dist/src/task-budget.js +39 -3
- package/dist/src/task-context.js +8 -2
- package/dist/src/task-critic.js +115 -0
- package/dist/src/task-driver.js +46 -2
- package/dist/src/task-policy.js +44 -12
- package/dist/src/task-verification.js +42 -9
- package/dist/src/task-work.js +47 -0
- package/dist/src/terminal-status.js +88 -0
- package/dist/src/tool-identity.js +69 -0
- package/dist/src/tui-activity.js +99 -0
- package/dist/src/tui-classifier.js +25 -0
- package/dist/src/tui-client.js +186 -5
- package/dist/src/tui-commands.js +23 -5
- package/dist/src/tui-composer.js +113 -0
- package/dist/src/tui-keymap.js +116 -0
- package/dist/src/tui-mentions.js +38 -0
- package/dist/src/tui-modals.js +157 -34
- package/dist/src/tui-notify.js +62 -0
- package/dist/src/tui-review.js +55 -0
- package/dist/src/tui-turn-keys.js +52 -0
- package/dist/src/tui-view.js +243 -69
- package/dist/src/tui.js +875 -118
- package/dist/src/turn-checkpoints.js +221 -0
- package/dist/src/turn-rewind.js +168 -0
- package/dist/src/usage.js +1 -1
- package/dist/src/web-fetch.js +114 -0
- package/dist/src/web-guard.js +163 -0
- package/dist/src/web-search.js +302 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/acp-desk.ts +155 -0
- package/src/acp-outcome.ts +174 -20
- package/src/acp.ts +386 -30
- package/src/agent-profiles.ts +48 -0
- package/src/agentpod-authority.ts +234 -15
- package/src/agentpod-default-config.ts +16 -0
- package/src/agentpod-work-decision-protocol.ts +69 -8
- package/src/agentpod-work-decisions.ts +123 -5
- package/src/agentpod-work.ts +1455 -152
- package/src/approval-rules.ts +360 -0
- package/src/attach.ts +4 -1
- package/src/autonomy.ts +111 -10
- package/src/board-reads.ts +148 -0
- package/src/children.ts +112 -0
- package/src/cli-help.ts +60 -6
- package/src/cli.ts +174 -4
- package/src/command-danger.ts +886 -0
- package/src/command-network.ts +215 -0
- package/src/command-sandbox.ts +393 -0
- package/src/custom-commands.ts +175 -0
- package/src/danger-classifier.ts +321 -0
- package/src/execution-evidence.ts +31 -1
- package/src/git-helpers.ts +177 -0
- package/src/hooks.ts +425 -0
- package/src/host-bind.ts +156 -0
- package/src/host-breaker.ts +89 -0
- package/src/host-start.ts +51 -1
- package/src/host.ts +365 -6
- package/src/house-extension.ts +313 -60
- package/src/local-coding.ts +894 -43
- package/src/local-edit-helper.ts +26 -0
- package/src/local-edits.ts +191 -8
- package/src/local-undo.ts +29 -14
- package/src/managed.ts +2 -2
- package/src/mentions.ts +304 -0
- package/src/operator-mcp-cli.ts +108 -0
- package/src/operator-mcp.ts +420 -0
- package/src/persona.ts +37 -0
- package/src/pi-sessions.ts +9 -1
- package/src/pi.ts +23 -1
- package/src/project-instructions.ts +229 -0
- package/src/protocol.ts +25 -3
- package/src/rate-limit-retries.ts +69 -0
- package/src/recurring-work.ts +1 -0
- package/src/repository-snapshots.ts +5 -2
- package/src/run-grants.ts +107 -0
- package/src/service.ts +709 -10
- package/src/session-pick.ts +102 -0
- package/src/shell-passthrough.ts +38 -0
- package/src/station-checkpoints.ts +183 -0
- package/src/station-config.ts +10 -1
- package/src/station-files.ts +20 -1
- package/src/station-task-verification.ts +6 -3
- package/src/station-work.ts +369 -20
- package/src/store.ts +70 -3
- package/src/supervisor.ts +463 -26
- package/src/task-budget.ts +48 -3
- package/src/task-context.ts +9 -2
- package/src/task-critic.ts +171 -0
- package/src/task-driver.ts +49 -2
- package/src/task-policy.ts +65 -13
- package/src/task-verification.ts +53 -9
- package/src/task-work.ts +75 -0
- package/src/terminal-status.ts +103 -0
- package/src/tool-identity.ts +110 -0
- package/src/tui-activity.ts +133 -0
- package/src/tui-classifier.ts +38 -0
- package/src/tui-client.ts +239 -8
- package/src/tui-commands.ts +49 -10
- package/src/tui-composer.ts +124 -0
- package/src/tui-keymap.ts +152 -0
- package/src/tui-mentions.ts +43 -0
- package/src/tui-modals.ts +173 -43
- package/src/tui-notify.ts +77 -0
- package/src/tui-review.ts +76 -0
- package/src/tui-turn-keys.ts +77 -0
- package/src/tui-view.ts +341 -88
- package/src/tui.ts +1047 -137
- package/src/turn-checkpoints.ts +253 -0
- package/src/turn-rewind.ts +258 -0
- package/src/usage.ts +1 -1
- package/src/web-fetch.ts +140 -0
- package/src/web-guard.ts +195 -0
- package/src/web-search.ts +402 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A provider 429 on a step is retried as a fresh admitted attempt of that step, after a backoff,
|
|
3
|
+
* up to RATE_LIMIT_MAX_FAILURES rate-limited attempts in all. Each retry is a new attempt with its
|
|
4
|
+
* own admission and budget charge, never a replay of the refused request. After the last one the
|
|
5
|
+
* task stops with RATE_LIMIT_STOP, a block the stopped-run recovery can prove and settle.
|
|
6
|
+
*/
|
|
7
|
+
export const RATE_LIMIT_MAX_FAILURES = 3;
|
|
8
|
+
export const RATE_LIMIT_BACKOFF_MS = [30_000, 60_000, 120_000];
|
|
9
|
+
export const RATE_LIMIT_STOP = 'Provider rate limit reached';
|
|
10
|
+
export class RateLimitRetries {
|
|
11
|
+
store;
|
|
12
|
+
constructor(store) {
|
|
13
|
+
this.store = store;
|
|
14
|
+
store.db.exec(`CREATE TABLE IF NOT EXISTS task_rate_limits(
|
|
15
|
+
task_id TEXT NOT NULL,
|
|
16
|
+
step_id TEXT NOT NULL,
|
|
17
|
+
attempt_id TEXT NOT NULL UNIQUE,
|
|
18
|
+
failures INTEGER NOT NULL,
|
|
19
|
+
retry_at INTEGER NOT NULL,
|
|
20
|
+
PRIMARY KEY(task_id, step_id, failures))`);
|
|
21
|
+
}
|
|
22
|
+
/** Whether this attempt failed because the provider rate-limited it. */
|
|
23
|
+
rateLimited(attempt) {
|
|
24
|
+
const row = this.store.db.prepare('SELECT state,outcome FROM attempts WHERE id=?').get(attempt);
|
|
25
|
+
if (!row || row.state !== 'failed' || typeof row.outcome !== 'string')
|
|
26
|
+
return false;
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(row.outcome)?.failure?.kind === 'rate_limit';
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** What the driver does with a task whose step failed. Records each rate-limited attempt once. */
|
|
35
|
+
decide(task, now = Date.now()) {
|
|
36
|
+
const failed = task.steps.filter((s) => ['failed', 'interrupted', 'cancelled'].includes(s.state));
|
|
37
|
+
const step = failed[0];
|
|
38
|
+
if (failed.length !== 1 || !step || step.state !== 'failed' || !step.attempt_id)
|
|
39
|
+
return { action: 'none' };
|
|
40
|
+
if (!this.rateLimited(step.attempt_id))
|
|
41
|
+
return { action: 'none' };
|
|
42
|
+
let row = this.store.db
|
|
43
|
+
.prepare('SELECT failures,retry_at FROM task_rate_limits WHERE attempt_id=?')
|
|
44
|
+
.get(step.attempt_id);
|
|
45
|
+
if (!row) {
|
|
46
|
+
const prior = Number(this.store.db
|
|
47
|
+
.prepare('SELECT count(*) AS n FROM task_rate_limits WHERE task_id=? AND step_id=?')
|
|
48
|
+
.get(task.id, step.id).n);
|
|
49
|
+
const failures = prior + 1;
|
|
50
|
+
const retry_at = now + (RATE_LIMIT_BACKOFF_MS[failures - 1] ?? RATE_LIMIT_BACKOFF_MS.at(-1));
|
|
51
|
+
this.store.db
|
|
52
|
+
.prepare('INSERT INTO task_rate_limits VALUES (?,?,?,?,?)')
|
|
53
|
+
.run(task.id, step.id, step.attempt_id, failures, retry_at);
|
|
54
|
+
row = { failures, retry_at };
|
|
55
|
+
}
|
|
56
|
+
if (row.failures >= RATE_LIMIT_MAX_FAILURES)
|
|
57
|
+
return { action: 'stop', reason: RATE_LIMIT_STOP };
|
|
58
|
+
if (now < row.retry_at)
|
|
59
|
+
return { action: 'wait' };
|
|
60
|
+
return { action: 'retry', step: step.id, n: row.failures };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -54,9 +54,12 @@ export class RepositorySnapshots {
|
|
|
54
54
|
}
|
|
55
55
|
read(binding, args) {
|
|
56
56
|
const tree = this.tree(binding), action = string(args.action, 'action', 32), offset = integer(args.offset ?? 0, 'offset');
|
|
57
|
+
// A snapshot-only reviewer (the critic) has no workspace; leave those fields out rather than
|
|
58
|
+
// undefined, since every read result is digested into the journal (card_5dcbd5d9be5c4183).
|
|
57
59
|
const identity = {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
...(binding.workspace
|
|
61
|
+
? { workspace_id: binding.workspace.id, revision: binding.workspace.revision }
|
|
62
|
+
: {}),
|
|
60
63
|
digest: binding.repository.digest,
|
|
61
64
|
artifact_id: binding.repository.artifact_id,
|
|
62
65
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
export const runGrantPrefix = (runId) => /^run_[A-Za-z0-9]{6,}$/.test(runId) ? `runs/${runId}/` : null;
|
|
3
|
+
/** Whether a station patch's arguments are a write a grant for this prefix may answer. */
|
|
4
|
+
export function runGrantCovers(prefix, args) {
|
|
5
|
+
if (args.action !== 'patch' || typeof args.content !== 'string')
|
|
6
|
+
return false;
|
|
7
|
+
const path = args.path;
|
|
8
|
+
if (typeof path !== 'string' || !path.startsWith(prefix) || path.length === prefix.length)
|
|
9
|
+
return false;
|
|
10
|
+
return path.split('/').every((s) => s !== '' && s !== '.' && s !== '..' && !s.startsWith('.'));
|
|
11
|
+
}
|
|
12
|
+
export class RunGrants {
|
|
13
|
+
store;
|
|
14
|
+
constructor(store) {
|
|
15
|
+
this.store = store;
|
|
16
|
+
store.db.exec(`CREATE TABLE IF NOT EXISTS run_grants(
|
|
17
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
18
|
+
session_id TEXT NOT NULL,
|
|
19
|
+
task_id TEXT NOT NULL,
|
|
20
|
+
plan_revision INTEGER NOT NULL,
|
|
21
|
+
binding_digest TEXT NOT NULL,
|
|
22
|
+
path_prefix TEXT NOT NULL,
|
|
23
|
+
approval_id TEXT NOT NULL UNIQUE,
|
|
24
|
+
granted_by TEXT NOT NULL,
|
|
25
|
+
created_at TEXT NOT NULL,
|
|
26
|
+
revoked_at TEXT)`);
|
|
27
|
+
}
|
|
28
|
+
/** Within the caller's transaction, next to the decision that granted it. Idempotent per approval. */
|
|
29
|
+
createInTransaction(input) {
|
|
30
|
+
if (!this.store.db.isTransaction)
|
|
31
|
+
throw Error('A run grant is created with its decision');
|
|
32
|
+
const saved = this.store.db
|
|
33
|
+
.prepare('SELECT * FROM run_grants WHERE approval_id=?')
|
|
34
|
+
.get(input.approval_id);
|
|
35
|
+
if (saved)
|
|
36
|
+
return saved;
|
|
37
|
+
const grant = {
|
|
38
|
+
...input,
|
|
39
|
+
id: randomUUID(),
|
|
40
|
+
created_at: new Date().toISOString(),
|
|
41
|
+
revoked_at: null,
|
|
42
|
+
};
|
|
43
|
+
this.store.db
|
|
44
|
+
.prepare('INSERT INTO run_grants VALUES (?,?,?,?,?,?,?,?,?,?)')
|
|
45
|
+
.run(grant.id, grant.session_id, grant.task_id, grant.plan_revision, grant.binding_digest, grant.path_prefix, grant.approval_id, grant.granted_by, grant.created_at, null);
|
|
46
|
+
this.store.event(grant.session_id, 'run_grant.created', {
|
|
47
|
+
grant_id: grant.id,
|
|
48
|
+
approval_id: grant.approval_id,
|
|
49
|
+
task_id: grant.task_id,
|
|
50
|
+
path_prefix: grant.path_prefix,
|
|
51
|
+
});
|
|
52
|
+
return grant;
|
|
53
|
+
}
|
|
54
|
+
/** The live grant for exactly this session, task, plan revision and binding, if any. */
|
|
55
|
+
active(scope) {
|
|
56
|
+
if (['cancelled', 'succeeded', 'succeeded_with_exception'].includes(scope.task_state))
|
|
57
|
+
return null;
|
|
58
|
+
return (this.store.db
|
|
59
|
+
.prepare('SELECT * FROM run_grants WHERE session_id=? AND task_id=? AND plan_revision=? AND binding_digest=? AND revoked_at IS NULL ORDER BY created_at DESC LIMIT 1')
|
|
60
|
+
.get(scope.session_id, scope.task_id, scope.plan_revision, scope.binding_digest) ?? null);
|
|
61
|
+
}
|
|
62
|
+
}
|