@ctrl-spc/cli 1.2.0 → 1.2.2
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/init.js +11 -2
- package/dist/commands/run.js +97 -0
- package/dist/mcp.js +6 -4
- package/dist/protocol.js +22 -3
- package/dist/skills.js +5 -1
- package/package.json +1 -2
package/dist/commands/init.js
CHANGED
|
@@ -6,6 +6,7 @@ import { getClient } from '../supabase.js';
|
|
|
6
6
|
import { ask, select } from '../prompt.js';
|
|
7
7
|
import { buildTopologyTargets, componentTargetId, discoverRepositoryTopology, planExplicitGrouping, readGroupingManifest, repositoryTargetId, } from '../topology.js';
|
|
8
8
|
import { upsertProjectLink } from './link.js';
|
|
9
|
+
import { registerMachineWorkspace } from './run.js';
|
|
9
10
|
function setGrouping(flags, grouping) {
|
|
10
11
|
if (flags.grouping) {
|
|
11
12
|
throw new Error(`Choose exactly one grouping option: --combine, --split, or --manifest <file>.`);
|
|
@@ -370,8 +371,16 @@ export async function init(argv = []) {
|
|
|
370
371
|
console.log(`Created project "${result.project_name}" in "${result.org_name ?? orgLabel}" — ${key}`);
|
|
371
372
|
break;
|
|
372
373
|
}
|
|
373
|
-
|
|
374
|
-
|
|
374
|
+
try {
|
|
375
|
+
const machine = getMachineIdentity();
|
|
376
|
+
await registerMachineWorkspace(client, userId, result.project_id, machine, repository.rootPath);
|
|
377
|
+
await upsertProjectLink(client, userId, result.project_id, repository.rootPath);
|
|
378
|
+
console.log(`Linked — local path ${repository.rootPath}`);
|
|
379
|
+
}
|
|
380
|
+
catch (err) {
|
|
381
|
+
console.error(`Failed to initialize this machine: ${err instanceof Error ? err.message : String(err)}`);
|
|
382
|
+
process.exitCode = 1;
|
|
383
|
+
}
|
|
375
384
|
return;
|
|
376
385
|
}
|
|
377
386
|
try {
|
package/dist/commands/run.js
CHANGED
|
@@ -15,6 +15,34 @@ import { discoverRepositoryTopology } from '../topology.js';
|
|
|
15
15
|
function mcpUrl() {
|
|
16
16
|
return `http://localhost:${MCP_PORT}/mcp`;
|
|
17
17
|
}
|
|
18
|
+
/** Retires the pre-1.2 background launcher, whose pinned repo checkout can
|
|
19
|
+
* otherwise reclaim the MCP port after an upgrade or reboot. */
|
|
20
|
+
export function retireLegacyDaemon(deps = {}) {
|
|
21
|
+
if (process.platform !== 'darwin' && !deps.launchAgentPath)
|
|
22
|
+
return false;
|
|
23
|
+
const path = deps.launchAgentPath ?? join(homedir(), 'Library', 'LaunchAgents', 'com.ctrl-spc.daemon.plist');
|
|
24
|
+
if (!(deps.exists ?? existsSync)(path))
|
|
25
|
+
return false;
|
|
26
|
+
const read = deps.read ?? ((target) => readFileSync(target, 'utf8'));
|
|
27
|
+
const contents = read(path);
|
|
28
|
+
if (!contents.includes('com.ctrl-spc.daemon') || !contents.includes('daemon'))
|
|
29
|
+
return false;
|
|
30
|
+
const uid = deps.uid ?? process.getuid?.();
|
|
31
|
+
if (uid !== undefined) {
|
|
32
|
+
try {
|
|
33
|
+
const bootout = deps.bootout ?? ((domain, target) => {
|
|
34
|
+
execFileSync('launchctl', ['bootout', domain, target], { stdio: 'ignore' });
|
|
35
|
+
});
|
|
36
|
+
bootout(`gui/${uid}`, path);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// An unloaded service is already safe; still remove its stale launcher.
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const remove = deps.remove ?? rmSync;
|
|
43
|
+
remove(path);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
18
46
|
export async function existingBrokerStatus(machineId, port = MCP_PORT, fetcher = fetch) {
|
|
19
47
|
try {
|
|
20
48
|
const response = await fetcher(`http://127.0.0.1:${port}/health`, {
|
|
@@ -127,6 +155,67 @@ export async function legacyCurrentProjectCandidates(client, cwd) {
|
|
|
127
155
|
throw new Error(`Could not resolve the current repository: ${error.message}`);
|
|
128
156
|
return (data ?? []).sort((left, right) => left.name.localeCompare(right.name) || left.id.localeCompare(right.id));
|
|
129
157
|
}
|
|
158
|
+
async function loadActiveProjectRemoteKeys(client, projectId) {
|
|
159
|
+
const { data, error } = await client
|
|
160
|
+
.from('project_repository_scopes')
|
|
161
|
+
.select('scope:repository_scopes!project_repository_scopes_repository_scope_id_fkey(' +
|
|
162
|
+
'repository:repositories!repository_scopes_repository_id_fkey(remote_key))')
|
|
163
|
+
.eq('project_id', projectId)
|
|
164
|
+
.eq('active', true);
|
|
165
|
+
if (error)
|
|
166
|
+
throw new Error(`Could not load project repositories: ${error.message}`);
|
|
167
|
+
const remotes = new Set();
|
|
168
|
+
for (const row of (data ?? [])) {
|
|
169
|
+
const scope = one(row.scope);
|
|
170
|
+
const repository = scope ? one(scope.repository) : null;
|
|
171
|
+
if (repository?.remote_key)
|
|
172
|
+
remotes.add(repository.remote_key);
|
|
173
|
+
}
|
|
174
|
+
return remotes;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Moves verifiable pre-machine project links onto this machine automatically.
|
|
178
|
+
* A legacy path is trusted only when it still exists as a Git checkout and its
|
|
179
|
+
* origin resolves back to the explicitly linked project. Stale paths from a
|
|
180
|
+
* different computer are ignored.
|
|
181
|
+
*/
|
|
182
|
+
export async function recoverLegacyProjectLinks(client, userId, machine, initializedProjectIds, deps = {}) {
|
|
183
|
+
const { data, error } = await client
|
|
184
|
+
.from('project_links')
|
|
185
|
+
.select('project_id,local_path')
|
|
186
|
+
.eq('user_id', userId);
|
|
187
|
+
if (error)
|
|
188
|
+
throw new Error(`Could not load legacy project links: ${error.message}`);
|
|
189
|
+
const observe = deps.observeWorkspace ?? observeLocalWorkspace;
|
|
190
|
+
const loadExpectedRemoteKeys = deps.loadExpectedRemoteKeys ?? loadActiveProjectRemoteKeys;
|
|
191
|
+
const register = deps.registerWorkspace ?? registerMachineWorkspace;
|
|
192
|
+
const recovered = [];
|
|
193
|
+
const links = [...(data ?? [])]
|
|
194
|
+
.sort((left, right) => left.project_id.localeCompare(right.project_id) || left.local_path.localeCompare(right.local_path));
|
|
195
|
+
for (const link of links) {
|
|
196
|
+
if (initializedProjectIds.has(link.project_id))
|
|
197
|
+
continue;
|
|
198
|
+
let observation;
|
|
199
|
+
try {
|
|
200
|
+
observation = observe(link.local_path);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const expectedRemoteKeys = await loadExpectedRemoteKeys(client, link.project_id);
|
|
206
|
+
const observedRemoteKeys = new Set(observation.checkouts
|
|
207
|
+
.map((checkout) => checkout.remoteKey)
|
|
208
|
+
.filter((remote) => remote !== null));
|
|
209
|
+
if (![...expectedRemoteKeys].some((remote) => observedRemoteKeys.has(remote)))
|
|
210
|
+
continue;
|
|
211
|
+
await register(client, userId, link.project_id, machine, link.local_path, {
|
|
212
|
+
observeWorkspace: () => observation,
|
|
213
|
+
});
|
|
214
|
+
initializedProjectIds.add(link.project_id);
|
|
215
|
+
recovered.push(link.project_id);
|
|
216
|
+
}
|
|
217
|
+
return recovered;
|
|
218
|
+
}
|
|
130
219
|
function checkoutPlan(workspaceId, repositories, observation, existing, inspectCheckout, verifiedAt) {
|
|
131
220
|
const rows = new Map();
|
|
132
221
|
const availableRepositoryIds = new Set();
|
|
@@ -545,6 +634,9 @@ function installShutdownHandler(presence, mcpServer) {
|
|
|
545
634
|
* sessions; begin_work binds each session to the pasted task's project.
|
|
546
635
|
*/
|
|
547
636
|
export async function run() {
|
|
637
|
+
if (retireLegacyDaemon()) {
|
|
638
|
+
console.log('Removed obsolete CTRL+SPC background launcher.');
|
|
639
|
+
}
|
|
548
640
|
const cwd = process.cwd();
|
|
549
641
|
const client = await getClient();
|
|
550
642
|
const { data: userData, error: userError } = await client.auth.getUser();
|
|
@@ -563,6 +655,11 @@ export async function run() {
|
|
|
563
655
|
return localObservation;
|
|
564
656
|
};
|
|
565
657
|
let projects = await loadMachineProjects(client, userId, machine.id);
|
|
658
|
+
const recoveredProjects = await recoverLegacyProjectLinks(client, userId, machine, new Set(projects.map((project) => project.id)));
|
|
659
|
+
if (recoveredProjects.length > 0) {
|
|
660
|
+
console.log(`Recovered ${recoveredProjects.length} initialized ${recoveredProjects.length === 1 ? 'project' : 'projects'} for this machine.`);
|
|
661
|
+
projects = await loadMachineProjects(client, userId, machine.id);
|
|
662
|
+
}
|
|
566
663
|
const legacyCandidates = await legacyCurrentProjectCandidates(client, cwd);
|
|
567
664
|
if (legacyCandidates.length === 1 && !projects.some((project) => project.id === legacyCandidates[0].id)) {
|
|
568
665
|
await registerMachineWorkspace(client, userId, legacyCandidates[0].id, machine, cwd, {
|
package/dist/mcp.js
CHANGED
|
@@ -372,7 +372,7 @@ export async function beginAgentRunHandler(deps, session, args) {
|
|
|
372
372
|
const projects = await accessibleProjects(deps, session.machineId);
|
|
373
373
|
if (!projects.some((project) => project.id === taskProjectId)) {
|
|
374
374
|
return errorResult(`Task "${args.task_id}" belongs to a project that is not initialized on this machine. ` +
|
|
375
|
-
'
|
|
375
|
+
`From that project's checkout, run \`ctrl-spc link --project ${taskProjectId}\`.`);
|
|
376
376
|
}
|
|
377
377
|
const result = await must(deps.client.rpc('begin_agent_run', {
|
|
378
378
|
p_task: args.task_id,
|
|
@@ -879,7 +879,8 @@ export async function listTasksHandler(deps, args = {}) {
|
|
|
879
879
|
try {
|
|
880
880
|
const projects = await accessibleProjects(deps);
|
|
881
881
|
if (args.project_id && !projects.some((project) => project.id === args.project_id)) {
|
|
882
|
-
return errorResult(`Project "${args.project_id}" is not initialized on this machine
|
|
882
|
+
return errorResult(`Project "${args.project_id}" is not initialized on this machine. ` +
|
|
883
|
+
`From its checkout, run \`ctrl-spc link --project ${args.project_id}\`.`);
|
|
883
884
|
}
|
|
884
885
|
const projectIds = args.project_id ? [args.project_id] : projects.map((project) => project.id);
|
|
885
886
|
if (projectIds.length === 0)
|
|
@@ -933,7 +934,8 @@ export async function getTaskHandler(deps, _attribution, args, machineId) {
|
|
|
933
934
|
return errorResult(`No task or artifact found for id "${args.id}".`);
|
|
934
935
|
}
|
|
935
936
|
if (!allowedProjectIds.has(row.project_id)) {
|
|
936
|
-
return errorResult(`The resolved item belongs to project "${row.project_id}", which is not initialized on this machine
|
|
937
|
+
return errorResult(`The resolved item belongs to project "${row.project_id}", which is not initialized on this machine. ` +
|
|
938
|
+
`From that project's checkout, run \`ctrl-spc link --project ${row.project_id}\`.`);
|
|
937
939
|
}
|
|
938
940
|
const task = parseTaskRow(row);
|
|
939
941
|
const topologyMachineId = machineId ?? deps.machineId;
|
|
@@ -1281,7 +1283,7 @@ export function protocolPromptHandler() {
|
|
|
1281
1283
|
// ---------------------------------------------------------------------------
|
|
1282
1284
|
const IDLE_TIMEOUT_MS = 10 * 60 * 1000;
|
|
1283
1285
|
const HEARTBEAT_INTERVAL_MS = 30 * 1000;
|
|
1284
|
-
export const BROKER_VERSION = '1.2.
|
|
1286
|
+
export const BROKER_VERSION = '1.2.1';
|
|
1285
1287
|
async function readJsonBody(req) {
|
|
1286
1288
|
const chunks = [];
|
|
1287
1289
|
for await (const chunk of req)
|
package/dist/protocol.js
CHANGED
|
@@ -13,6 +13,24 @@ export const PROTOCOL_FULL = `## 5a. Agent working protocol
|
|
|
13
13
|
|
|
14
14
|
Delivered redundantly (installed skill + MCP), phrased imperatively for the agent:
|
|
15
15
|
|
|
16
|
+
**HARD STOP — unclear novel feature.** After \`record_context_exploration\` succeeds,
|
|
17
|
+
if the task does not explicitly request a build or name a deliverable, the immediate
|
|
18
|
+
next tool call is \`ask_question\` with category \`intent\` and the exact question:
|
|
19
|
+
“What should I produce for this feature? Select one or more: build, plan, spec,
|
|
20
|
+
diagram, mock, wireframe.” Then call \`end_work\` with reason
|
|
21
|
+
\`pending_user_answer\` and outcome \`blocked\`. Do not call \`get_task\` again,
|
|
22
|
+
\`update_task\`, \`create_artifact\`, \`reserve_work_paths\`, or any intervening tool.
|
|
23
|
+
The context artifact is the only artifact allowed before the answer. A read-only
|
|
24
|
+
execution sandbox is not a missing checkout and never changes this intent question.
|
|
25
|
+
Multiple selections are allowed.
|
|
26
|
+
|
|
27
|
+
Before the context artifact exists, never state or imply a requested deliverable and
|
|
28
|
+
never mention repository counts, contents, tests, findings, or likely impact. If
|
|
29
|
+
progress commentary is required, use only: “The required CTRL+SPC context review is
|
|
30
|
+
in progress; no decision or repository change has been made.” After persistence and
|
|
31
|
+
before the intent question, either say nothing or only: “The required context review
|
|
32
|
+
is saved to the work item. I am applying the task's explicit intent gate now.”
|
|
33
|
+
|
|
16
34
|
1. **Resolve without side effects.** \`/ctrl-spc work <id>\` → call \`get_task(id)\` before
|
|
17
35
|
anything else. \`get_task\` is read-only: it does not change task status, presence,
|
|
18
36
|
collaboration, claims, or reservations. The ID is the only context in the paste;
|
|
@@ -64,9 +82,9 @@ Delivered redundantly (installed skill + MCP), phrased imperatively for the agen
|
|
|
64
82
|
authorized deliverable. Perform the action only when the item explicitly names it; do
|
|
65
83
|
not ask for confirmation. Otherwise use \`ask_question\`. For a bug, ask for reproduction steps,
|
|
66
84
|
expected behavior, or actual behavior only when each is missing and not discoverable.
|
|
67
|
-
For a novel feature with no explicit build action or deliverable, the
|
|
68
|
-
|
|
69
|
-
|
|
85
|
+
For a novel feature with no explicit build action or deliverable, apply the HARD STOP
|
|
86
|
+
above; the immediate next call is the exact build/plan/spec/diagram/mock/wireframe
|
|
87
|
+
\`ask_question\`.
|
|
70
88
|
Generic goals such as “improve,” “coordinate,” “prepare,” or “support” do not authorize
|
|
71
89
|
analysis, a release decision, implementation, or another artifact. In this state do not
|
|
72
90
|
call \`update_task\`, \`create_artifact\`, \`reserve_work_paths\`, or \`create_task\`; do not
|
|
@@ -109,6 +127,7 @@ Delivered redundantly (installed skill + MCP), phrased imperatively for the agen
|
|
|
109
127
|
abandoning the run. Missing, stale, foreign, duplicate, or incomplete receipts are
|
|
110
128
|
rejected. Ending releases only this session's work.`;
|
|
111
129
|
export const PROTOCOL_SHORT = 'ctrl-spc protocol (compact — full text: MCP prompt `ctrl-spc-protocol`): ' +
|
|
130
|
+
'HARD STOP unclear novel feature: immediately after record_context_exploration, ask_question category intent exactly “What should I produce for this feature? Select one or more: build, plan, spec, diagram, mock, wireframe.” Then end_work blocked pending_user_answer. No intervening get_task/update_task/create_artifact/reservation/tool; read-only sandbox is not a missing checkout. ' +
|
|
112
131
|
'1) get_task is read-only; begin_work (run coordinator); resolve missing checkouts via fetch/link or acknowledge_unavailable_checkout. ' +
|
|
113
132
|
'2) Every item needs read-only subagents covering scope IDs once. Codex spawn_agent MUST use fork_turns:none; its self-contained prompt has exact IDs/paths/focus, no copied command. Child calls no ctrl-spc tools and writes nothing. If unavailable, record blocked; stop. ' +
|
|
114
133
|
'3) Parent must record_context_exploration before deciding, asking, planning, reserving, or editing. Before success narrate process only—no findings/conclusions/impact/decisions. Later summaries add no unpersisted facts. ' +
|
package/dist/skills.js
CHANGED
|
@@ -38,12 +38,16 @@ export function codexLegacySkillPath() {
|
|
|
38
38
|
function protocolBody(mcpUrl) {
|
|
39
39
|
return `Resolve a CTRL+SPC work item or artifact pasted as \`/ctrl-spc work <id>\` or \`/ctrl-spc artifact <id>\`, then follow the ctrl-spc working protocol:
|
|
40
40
|
|
|
41
|
+
HARD STOP — unclear novel feature: after \`record_context_exploration\` succeeds, if the task does not explicitly request a build or name a deliverable, the next tool call MUST be \`ask_question\` with category \`intent\` and this exact question: “What should I produce for this feature? Select one or more: build, plan, spec, diagram, mock, wireframe.” Then call \`end_work\` with reason \`pending_user_answer\` and outcome \`blocked\`. In that run, never call \`get_task\` again, \`update_task\`, \`create_artifact\`, \`reserve_work_paths\`, or any other tool between the context artifact and \`ask_question\`. The context artifact is the only allowed artifact. Do not copy findings into the task description before the user answers. A read-only execution sandbox is not a missing checkout and must not change this intent question.
|
|
42
|
+
|
|
43
|
+
Before the context artifact exists, never state or imply a requested deliverable and never mention repository counts, contents, tests, findings, or likely impact. If progress commentary is required, use only: “The required CTRL+SPC context review is in progress; no decision or repository change has been made.” After the context artifact and before the intent question, either say nothing or use only: “The required context review is saved to the work item. I am applying the task's explicit intent gate now.”
|
|
44
|
+
|
|
41
45
|
1. Resolve without side effects — call \`get_task\` before anything else. It is read-only: it does not change status, presence, claims, or reservations. The ID is the only context in the paste; everything current lives in ctrl-spc.
|
|
42
46
|
2. Begin explicitly — call \`begin_work\` after reading the topology. The first live run is coordinator and \`begin_work\` moves Backlog to In Progress; later runs join as collaborators. Only the coordinator changes status. Never mark an item \`done\` autonomously.
|
|
43
47
|
3. Repair missing context — if \`begin_work\` reports an unavailable checkout, warn the user and offer to fetch or link it. Never fetch without approval. If the user explicitly continues without it, call \`acknowledge_unavailable_checkout\`, then call \`begin_work\` again after every missing scope is fetched or acknowledged.
|
|
44
48
|
4. Delegate exploration — every pasted work item MUST use at least one read-only subagent. After \`begin_work\` joins, partition every available repository scope exactly once across bounded subagent invocations. Every child prompt must explicitly list its assigned \`repository_scope_ids\`; across the batch each available ID appears exactly once. When using Codex \`spawn_agent\`, MUST pass \`fork_turns: "none"\`; never pass \`all\` or a recent-turn count. Give each child a self-contained assignment containing only its exact scope IDs, checkout paths, inspection focus, read-only restrictions, and required report shape. Never include or inherit the parent \`/ctrl-spc work\` command. The child must not call any ctrl-spc tool—including \`get_task\` or \`begin_work\`—or pick up the work item; it only inspects assigned paths and returns its report. If zero scopes are available after explicit acknowledgements, one child inspects the task/artifact context and reports those unavailable scopes without pretending they were reviewed. Children inspect only: no file mutation, path reservation, ctrl-spc call, \`tee\`, shell redirection, temp/capture file, install, formatter, cache-generating command, or any command that can write. Inspection-first is sufficient; do not decide intent before reports are persisted. Each report uses \`{ agent, focus, repository_scope_ids, inspected_paths, findings, likely_impact, unresolved_questions }\`. If no subagent is available, do not explore directly: call \`record_context_exploration\` with \`blocked_reason = subagents_unavailable\`, tell the user, and stop.
|
|
45
49
|
5. Persist context before deciding — the parent consolidates every child report and MUST call \`record_context_exploration\` to create the work item's analysis artifact before deciding what to do, asking a task question, planning, reserving, or editing. Pass the structured reports plus a separate coverage array; include every active scope exactly once, and give unavailable scopes their acknowledgement. Before the tool succeeds, commentary may state process only: never disclose findings, conclusions, likely impact, or decisions. After persistence, terminal summaries may reference the persisted artifact/question but must add no unpersisted facts.
|
|
46
|
-
6. Decide or ask deterministically — after exploration is recorded, classify intent only from the work item's explicit wording and accepted answers, never from findings. Findings do not authorize a deliverable. Infer and perform the action only when the item explicitly names it. Otherwise persist only the necessary question with \`ask_question\`. For a bug, ask for reproduction steps, expected behavior, or actual behavior only when each is missing and not discoverable. For a novel feature with no explicit build action or deliverable, the mandatory next mutating call after \`record_context_exploration\` is \`ask_question
|
|
50
|
+
6. Decide or ask deterministically — after exploration is recorded, classify intent only from the work item's explicit wording and accepted answers, never from findings. Findings do not authorize a deliverable. Infer and perform the action only when the item explicitly names it. Otherwise persist only the necessary question with \`ask_question\`. For a bug, ask for reproduction steps, expected behavior, or actual behavior only when each is missing and not discoverable. For a novel feature with no explicit build action or deliverable, apply the HARD STOP above: the mandatory next mutating call after \`record_context_exploration\` is \`ask_question\`; it must say “select one or more: build, plan, spec, diagram, mock, wireframe.” Generic goals such as “improve,” “coordinate,” “prepare,” or “support” are not deliverables. In this state do not call \`update_task\`, \`create_artifact\`, \`reserve_work_paths\`, or \`create_task\`; do not decide, edit, or complete. The context analysis is the only allowed artifact before the answer. Ask before overriding an unmet dependency, splitting work, fetching, or accepting a collision handoff. After \`ask_question\` succeeds, do no more work in that run: call \`end_work\` with reason \`pending_user_answer\` and outcome \`blocked\`, then wait for a later pasted run.
|
|
47
51
|
7. Persist answers and findings — after every accepted answer, call \`update_task\` to add the decision, constraint, acceptance criterion, and durable findings to the description. Pass the latest revision and refetch/reconcile on conflict. Do not use progress comments; do not leave findings only in the terminal.
|
|
48
52
|
8. Reserve before writing — call \`reserve_work_paths\` with the topology revision, exact checkout ID, and every repository-relative path you intend to edit. Do not edit until the full atomic request succeeds. On collision, narrow to disjoint paths, wait, ask for an explicit handoff, or use an isolated Git worktree. Never edit a conflicting path.
|
|
49
53
|
9. Persist every output — every substantive non-question output must be a ctrl-spc artifact before it is presented as complete. Use \`create_artifact\` type \`analysis\` for research/findings, \`plan\` for plans, \`spec\` for specifications or proposed schemas, and the matching type for diagrams, mocks, and wireframes. Never write planning documents into a repository. Every artifact includes exactly one coverage disposition and non-empty reason for every active repository scope.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ctrl-spc/cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "CTRL+SPC CLI — per-machine agent for browser login, project linking, presence, and the local MCP server.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22"
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
"typecheck:e2e-contract": "tsc -p e2e/tsconfig.json",
|
|
24
24
|
"run:e2e-copied-work": "node --experimental-strip-types e2e/run-copied-work-item.ts",
|
|
25
25
|
"run:e2e-hosted-topology": "npm run build && node --experimental-strip-types e2e/run-hosted-topology-management.ts",
|
|
26
|
-
"run:e2e-hosted-topology": "npm run build && node --experimental-strip-types e2e/run-hosted-topology-management.ts",
|
|
27
26
|
"setup:e2e-multirepo": "node --experimental-strip-types e2e/setup-multirepo-matrix.ts",
|
|
28
27
|
"verify:e2e-multirepo": "npm run build && node --experimental-strip-types e2e/run-multirepo-matrix.ts"
|
|
29
28
|
},
|