@proletariat/cli 0.3.48 → 0.3.49
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/dist/commands/claude/index.js +21 -21
- package/dist/commands/claude/open.js +1 -1
- package/dist/commands/config/index.js +2 -2
- package/dist/commands/execution/config.d.ts +2 -2
- package/dist/commands/execution/config.js +18 -18
- package/dist/commands/execution/list.js +2 -2
- package/dist/commands/execution/view.js +2 -2
- package/dist/commands/orchestrator/start.d.ts +1 -1
- package/dist/commands/orchestrator/start.js +19 -19
- package/dist/commands/qa/index.js +12 -12
- package/dist/commands/staff/add.js +1 -1
- package/dist/commands/work/linear.js +28 -5
- package/dist/commands/work/revise.js +8 -8
- package/dist/commands/work/spawn.js +1 -1
- package/dist/commands/work/start.js +12 -12
- package/dist/commands/work/watch.js +3 -3
- package/dist/lib/agents/index.js +2 -2
- package/dist/lib/database/drizzle-schema.d.ts +7 -7
- package/dist/lib/database/drizzle-schema.js +1 -1
- package/dist/lib/execution/config.d.ts +6 -6
- package/dist/lib/execution/config.js +17 -10
- package/dist/lib/execution/devcontainer.d.ts +3 -3
- package/dist/lib/execution/devcontainer.js +3 -3
- package/dist/lib/execution/runners.d.ts +2 -2
- package/dist/lib/execution/runners.js +23 -24
- package/dist/lib/execution/spawner.js +3 -3
- package/dist/lib/execution/storage.d.ts +2 -2
- package/dist/lib/execution/storage.js +3 -3
- package/dist/lib/execution/types.d.ts +2 -2
- package/dist/lib/execution/types.js +1 -1
- package/dist/lib/external-issues/linear.d.ts +6 -0
- package/dist/lib/external-issues/linear.js +63 -0
- package/dist/lib/pmo/schema.d.ts +1 -1
- package/dist/lib/pmo/schema.js +1 -1
- package/dist/lib/pmo/storage/base.js +31 -0
- package/dist/lib/repos/index.js +1 -1
- package/oclif.manifest.json +4318 -4313
- package/package.json +1 -1
|
@@ -18,7 +18,7 @@ function rowToAgentWork(row) {
|
|
|
18
18
|
executor: row.executor,
|
|
19
19
|
environment: (row.environment || 'host'),
|
|
20
20
|
displayMode: (row.display_mode || 'terminal'),
|
|
21
|
-
|
|
21
|
+
permissionMode: (row.permission_mode || 'safe'),
|
|
22
22
|
status: row.status,
|
|
23
23
|
branch: row.branch || undefined,
|
|
24
24
|
pid: row.pid || undefined,
|
|
@@ -51,10 +51,10 @@ export class ExecutionStorage {
|
|
|
51
51
|
const id = `WORK-${randomUUID().substring(0, 8).toUpperCase()}`;
|
|
52
52
|
this.db.prepare(`
|
|
53
53
|
INSERT INTO ${T.agent_work} (
|
|
54
|
-
id, ticket_id, agent_name, executor, environment, display_mode,
|
|
54
|
+
id, ticket_id, agent_name, executor, environment, display_mode, permission_mode,
|
|
55
55
|
status, branch, pid, container_id, session_id, host, log_path, started_at
|
|
56
56
|
) VALUES (?, ?, ?, ?, ?, ?, ?, 'starting', ?, ?, ?, ?, ?, ?, ?)
|
|
57
|
-
`).run(id, params.ticketId, params.agentName, params.executor, params.environment, params.displayMode, params.
|
|
57
|
+
`).run(id, params.ticketId, params.agentName, params.executor, params.environment, params.displayMode, params.permissionMode, params.branch || null, params.pid || null, params.containerId || null, params.sessionId || null, params.host || null, params.logPath || null, now);
|
|
58
58
|
return this.getExecution(id);
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
@@ -46,7 +46,7 @@ export interface AgentWork {
|
|
|
46
46
|
environment: ExecutionEnvironment;
|
|
47
47
|
displayMode: DisplayMode;
|
|
48
48
|
sessionManager?: SessionManager;
|
|
49
|
-
|
|
49
|
+
permissionMode: PermissionMode;
|
|
50
50
|
status: ExecutionStatus;
|
|
51
51
|
branch?: string;
|
|
52
52
|
pid?: string;
|
|
@@ -120,7 +120,7 @@ export interface ExecutionConfig {
|
|
|
120
120
|
autoExecute: boolean;
|
|
121
121
|
shell: Shell;
|
|
122
122
|
outputMode: OutputMode;
|
|
123
|
-
|
|
123
|
+
permissionMode: PermissionMode;
|
|
124
124
|
authMethod?: AuthMethod;
|
|
125
125
|
createPrDefault?: boolean;
|
|
126
126
|
tmux: {
|
|
@@ -131,7 +131,7 @@ export const DEFAULT_EXECUTION_CONFIG = {
|
|
|
131
131
|
autoExecute: false,
|
|
132
132
|
shell: 'zsh', // macOS default
|
|
133
133
|
outputMode: 'interactive', // Show streaming UI by default
|
|
134
|
-
|
|
134
|
+
permissionMode: 'safe', // Require approval for dangerous operations by default
|
|
135
135
|
tmux: {
|
|
136
136
|
session: 'proletariat',
|
|
137
137
|
layout: 'window',
|
|
@@ -28,6 +28,12 @@ export declare function buildLinearSpawnContextMessage(envelope: NormalizedIssue
|
|
|
28
28
|
* Build a CLI command string for selecting a specific Linear issue.
|
|
29
29
|
*/
|
|
30
30
|
export declare function buildLinearIssueChoiceCommand(issueIdentifier: string, projectId?: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Fetch a single Linear issue by identifier (for example, ENG-123) and normalize it.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getLinearIssueByIdentifier(configInput: LinearAdapterConfig, identifier: string, options?: {
|
|
35
|
+
fetchImpl?: typeof fetch;
|
|
36
|
+
}): Promise<NormalizedIssueEnvelope | null>;
|
|
31
37
|
/**
|
|
32
38
|
* Fetch and normalize Linear issues into NormalizedIssueEnvelopes.
|
|
33
39
|
*/
|
|
@@ -30,6 +30,27 @@ const LINEAR_ISSUES_QUERY = `
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
`;
|
|
33
|
+
const LINEAR_ISSUE_BY_IDENTIFIER_QUERY = `
|
|
34
|
+
query IssueForSpawn($id: String!) {
|
|
35
|
+
issue(id: $id) {
|
|
36
|
+
id
|
|
37
|
+
identifier
|
|
38
|
+
title
|
|
39
|
+
description
|
|
40
|
+
url
|
|
41
|
+
priority
|
|
42
|
+
labels {
|
|
43
|
+
nodes {
|
|
44
|
+
name
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
state {
|
|
48
|
+
name
|
|
49
|
+
type
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
33
54
|
function priorityFromLinear(value) {
|
|
34
55
|
switch (value) {
|
|
35
56
|
case 1:
|
|
@@ -155,6 +176,48 @@ export function buildLinearIssueChoiceCommand(issueIdentifier, projectId) {
|
|
|
155
176
|
}
|
|
156
177
|
return command;
|
|
157
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* Fetch a single Linear issue by identifier (for example, ENG-123) and normalize it.
|
|
181
|
+
*/
|
|
182
|
+
export async function getLinearIssueByIdentifier(configInput, identifier, options) {
|
|
183
|
+
const config = ensureLinearConfig(configInput);
|
|
184
|
+
const fetchImpl = options?.fetchImpl || fetch;
|
|
185
|
+
const response = await fetchImpl(config.apiUrl, {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
headers: {
|
|
188
|
+
'Content-Type': 'application/json',
|
|
189
|
+
Authorization: config.apiKey,
|
|
190
|
+
},
|
|
191
|
+
body: JSON.stringify({
|
|
192
|
+
query: LINEAR_ISSUE_BY_IDENTIFIER_QUERY,
|
|
193
|
+
variables: {
|
|
194
|
+
id: identifier,
|
|
195
|
+
},
|
|
196
|
+
}),
|
|
197
|
+
});
|
|
198
|
+
if (response.status === 401 || response.status === 403) {
|
|
199
|
+
throw new ExternalIssueAdapterError('AUTH_FAILED', 'Linear authentication failed. Verify your LINEAR_API_KEY token.');
|
|
200
|
+
}
|
|
201
|
+
if (!response.ok) {
|
|
202
|
+
throw new ExternalIssueAdapterError('REQUEST_FAILED', `Linear request failed with status ${response.status}.`);
|
|
203
|
+
}
|
|
204
|
+
const payload = await response.json();
|
|
205
|
+
if (payload.errors && payload.errors.length > 0) {
|
|
206
|
+
const message = payload.errors[0]?.message || 'Unknown Linear API error.';
|
|
207
|
+
if (/auth|token|forbidden|unauthorized/i.test(message)) {
|
|
208
|
+
throw new ExternalIssueAdapterError('AUTH_FAILED', `Linear authentication failed: ${message}`);
|
|
209
|
+
}
|
|
210
|
+
// "not found" should be treated as null, not hard failure.
|
|
211
|
+
if (/not found/i.test(message)) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
throw new ExternalIssueAdapterError('REQUEST_FAILED', `Linear API error: ${message}`);
|
|
215
|
+
}
|
|
216
|
+
const node = payload.data?.issue;
|
|
217
|
+
if (!node)
|
|
218
|
+
return null;
|
|
219
|
+
return normalizeLinearIssueToEnvelope(node);
|
|
220
|
+
}
|
|
158
221
|
/**
|
|
159
222
|
* Fetch and normalize Linear issues into NormalizedIssueEnvelopes.
|
|
160
223
|
*/
|
package/dist/lib/pmo/schema.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ export declare const PMO_TABLE_SCHEMAS: {
|
|
|
67
67
|
readonly project_specs: "\n CREATE TABLE IF NOT EXISTS pmo_project_specs (\n project_id TEXT NOT NULL REFERENCES pmo_projects(id) ON DELETE CASCADE,\n spec_id TEXT NOT NULL REFERENCES pmo_specs(id) ON DELETE CASCADE,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (project_id, spec_id)\n )";
|
|
68
68
|
readonly cache_metadata: "\n CREATE TABLE IF NOT EXISTS pmo_cache_metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )";
|
|
69
69
|
readonly settings: "\n CREATE TABLE IF NOT EXISTS pmo_settings (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n )";
|
|
70
|
-
readonly agent_work: "\n CREATE TABLE IF NOT EXISTS agent_work (\n id TEXT PRIMARY KEY,\n ticket_id TEXT NOT NULL,\n agent_name TEXT NOT NULL,\n executor TEXT NOT NULL,\n environment TEXT NOT NULL DEFAULT 'host',\n display_mode TEXT NOT NULL DEFAULT 'terminal',\n
|
|
70
|
+
readonly agent_work: "\n CREATE TABLE IF NOT EXISTS agent_work (\n id TEXT PRIMARY KEY,\n ticket_id TEXT NOT NULL,\n agent_name TEXT NOT NULL,\n executor TEXT NOT NULL,\n environment TEXT NOT NULL DEFAULT 'host',\n display_mode TEXT NOT NULL DEFAULT 'terminal',\n permission_mode TEXT NOT NULL DEFAULT 'safe',\n status TEXT NOT NULL DEFAULT 'starting',\n branch TEXT,\n pid TEXT,\n container_id TEXT,\n session_id TEXT,\n host TEXT,\n log_path TEXT,\n started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n completed_at TIMESTAMP,\n exit_code INTEGER,\n error_message TEXT,\n FOREIGN KEY (ticket_id) REFERENCES pmo_tickets(id) ON DELETE CASCADE\n )";
|
|
71
71
|
readonly containers: "\n CREATE TABLE IF NOT EXISTS containers (\n id TEXT PRIMARY KEY,\n agent_name TEXT NOT NULL,\n docker_id TEXT NOT NULL,\n docker_name TEXT,\n image TEXT,\n status TEXT NOT NULL DEFAULT 'unknown',\n current_execution_id TEXT,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n last_seen_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (agent_name) REFERENCES agents(name) ON DELETE CASCADE,\n FOREIGN KEY (current_execution_id) REFERENCES agent_work(id) ON DELETE SET NULL\n )";
|
|
72
72
|
readonly id_sequences: "\n CREATE TABLE IF NOT EXISTS id_sequences (\n table_name TEXT PRIMARY KEY,\n next_id INTEGER NOT NULL DEFAULT 1\n )";
|
|
73
73
|
readonly statuses: "\n CREATE TABLE IF NOT EXISTS pmo_statuses (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n name TEXT NOT NULL,\n category TEXT NOT NULL,\n position INTEGER NOT NULL DEFAULT 0,\n color TEXT,\n description TEXT,\n is_default INTEGER NOT NULL DEFAULT 0,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (project_id) REFERENCES pmo_projects(id) ON DELETE CASCADE,\n UNIQUE(project_id, name)\n )";
|
package/dist/lib/pmo/schema.js
CHANGED
|
@@ -328,7 +328,7 @@ export const PMO_TABLE_SCHEMAS = {
|
|
|
328
328
|
executor TEXT NOT NULL,
|
|
329
329
|
environment TEXT NOT NULL DEFAULT 'host',
|
|
330
330
|
display_mode TEXT NOT NULL DEFAULT 'terminal',
|
|
331
|
-
|
|
331
|
+
permission_mode TEXT NOT NULL DEFAULT 'safe',
|
|
332
332
|
status TEXT NOT NULL DEFAULT 'starting',
|
|
333
333
|
branch TEXT,
|
|
334
334
|
pid TEXT,
|
|
@@ -345,6 +345,37 @@ export function runMigrations(db) {
|
|
|
345
345
|
// Non-critical migration - don't fail initialization
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
|
+
// Migration: Rename sandboxed column to permission_mode in agent_work table
|
|
349
|
+
if (tableExists(T.agent_work)) {
|
|
350
|
+
const awColumns = db.pragma(`table_info(${T.agent_work})`);
|
|
351
|
+
const awColumnNames = new Set(awColumns.map(c => c.name));
|
|
352
|
+
if (awColumnNames.has('sandboxed') && !awColumnNames.has('permission_mode')) {
|
|
353
|
+
try {
|
|
354
|
+
db.exec(`ALTER TABLE ${T.agent_work} ADD COLUMN permission_mode TEXT NOT NULL DEFAULT 'safe'`);
|
|
355
|
+
// Migrate existing data: sandboxed=1 → 'safe', sandboxed=0 → 'danger'
|
|
356
|
+
db.exec(`UPDATE ${T.agent_work} SET permission_mode = CASE WHEN sandboxed = 1 THEN 'safe' ELSE 'danger' END`);
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
// Column may already exist
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
// Migration: Rename execution.sandboxed setting to execution.permission_mode
|
|
364
|
+
if (tableExists('workspace_settings')) {
|
|
365
|
+
try {
|
|
366
|
+
const oldSetting = db.prepare(`SELECT value FROM workspace_settings WHERE key = 'execution.sandboxed'`).get();
|
|
367
|
+
if (oldSetting) {
|
|
368
|
+
const permMode = oldSetting.value === 'true' ? 'safe' : 'danger';
|
|
369
|
+
db.prepare(`
|
|
370
|
+
INSERT INTO workspace_settings (key, value) VALUES ('execution.permission_mode', ?)
|
|
371
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
372
|
+
`).run(permMode);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// Non-critical migration
|
|
377
|
+
}
|
|
378
|
+
}
|
|
348
379
|
}
|
|
349
380
|
/**
|
|
350
381
|
* Seed built-in workflows from BUILTIN_TEMPLATES (single source of truth).
|
package/dist/lib/repos/index.js
CHANGED
|
@@ -451,7 +451,7 @@ export async function addRepository(hqPath, repoPath, action) {
|
|
|
451
451
|
addRepositoriesToDatabase(hqPath, dbRepoData);
|
|
452
452
|
// Create worktrees for existing agents
|
|
453
453
|
await createWorktreesForRepo(hqPath, repoName, targetPath);
|
|
454
|
-
// Create devcontainer config for
|
|
454
|
+
// Create devcontainer config for isolated execution in the central repo
|
|
455
455
|
console.log(styles.muted(`Creating devcontainer config for ${repoName}...`));
|
|
456
456
|
const gitIdentity = getGitIdentity();
|
|
457
457
|
createDevcontainerConfig({
|