@brainervirus/workit-core 1.2.1 → 1.3.1
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 +1 -1
- package/skills/workit-babysit/SKILL.md +20 -26
- package/skills/workit-behavioral-tdd/SKILL.md +0 -5
- package/skills/workit-blast-radius/SKILL.md +0 -5
- package/skills/workit-challenge/SKILL.md +30 -47
- package/skills/workit-debug/SKILL.md +5 -27
- package/skills/workit-deslop/SKILL.md +0 -5
- package/skills/workit-diagram/SKILL.md +0 -5
- package/skills/workit-green-run/SKILL.md +0 -5
- package/skills/workit-handoff/SKILL.md +2 -8
- package/skills/workit-implement/SKILL.md +14 -20
- package/skills/workit-mockup/SKILL.md +0 -5
- package/skills/workit-plan/SKILL.md +30 -63
- package/skills/workit-review/SKILL.md +0 -5
- package/skills/workit-steer/SKILL.md +27 -27
- package/src/core/authority.ts +6 -1
- package/src/core/auto-approval.ts +34 -14
- package/src/core/branch.ts +293 -42
- package/src/core/config-conversion.ts +4 -4
- package/src/core/config-guard.ts +1 -7
- package/src/core/config.ts +1 -1
- package/src/core/cutover.ts +1207 -140
- package/src/core/doctor.ts +155 -82
- package/src/core/external-action-effects.ts +886 -172
- package/src/core/external-action.ts +222 -64
- package/src/core/init.ts +25 -115
- package/src/core/legacy-ownership.ts +47 -0
- package/src/core/methods.ts +65 -52
- package/src/core/policy-resolver.ts +13 -5
- package/src/core/ports/pr-create.ts +23 -15
- package/src/core/pr-create.ts +374 -84
- package/src/core/registration.ts +0 -15
- package/src/core/repo-tools.ts +0 -1
- package/src/core/route-intent.ts +34 -82
- package/src/core/safe-write.ts +66 -1
- package/src/core/setup-state.ts +7 -0
- package/src/core/setup.ts +175 -82
- package/src/core/task-contract.ts +66 -6
- package/src/core/task-engine.ts +47 -2
- package/src/core/task-store.ts +159 -1
- package/src/core/tracker-issues.ts +55 -118
- package/src/core/vcs-config.ts +178 -187
- package/src/core/workspaces.ts +554 -46
- package/src/core.ts +3 -2
- package/src/core/ports/vcs-token-create-urls.ts +0 -4
package/src/core/init.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { PLUGIN_ROOT } from "./scripts";
|
|
|
6
6
|
import { writeFileExclusive } from "./safe-write";
|
|
7
7
|
import { resolveWorkspace, workspacesPath } from "./workspaces";
|
|
8
8
|
import { applyWorkspaceBranchPolicy } from "./setup";
|
|
9
|
-
import {
|
|
9
|
+
import { vcsConfig, vcsVerifyToken } from "./vcs-config";
|
|
10
10
|
import { youTrackTokenCreateUrl, youTrackVerifyToken } from "./youtrack";
|
|
11
11
|
|
|
12
12
|
const TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
@@ -181,32 +181,28 @@ export function initStatusData(configDirPath = configDir()): Record<string, any>
|
|
|
181
181
|
items.push(youtrackTokenItem);
|
|
182
182
|
|
|
183
183
|
let vcsCfg: Record<string, any> | null = null;
|
|
184
|
-
let tokenCreateUrls: Record<string, any> | null = null;
|
|
185
184
|
const vcsParsed = readJson(vcsJson);
|
|
186
185
|
if (vcsParsed) {
|
|
187
186
|
const rawProvider = vcsParsed.provider;
|
|
187
|
+
const effective = vcsConfig("resolve", process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd());
|
|
188
188
|
const provider =
|
|
189
|
-
typeof
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
189
|
+
effective?.ok && typeof effective.provider === "string"
|
|
190
|
+
? effective.provider
|
|
191
|
+
: typeof rawProvider === "string" && rawProvider.trim()
|
|
192
|
+
? rawProvider.toLowerCase()
|
|
193
|
+
: null;
|
|
194
194
|
vcsCfg = {
|
|
195
195
|
config_edit_path: resolvePath(vcsJson),
|
|
196
196
|
provider,
|
|
197
|
-
defaultTargetBranch:
|
|
197
|
+
defaultTargetBranch: effective.ok
|
|
198
|
+
? effective.defaultTargetBranch
|
|
199
|
+
: (vcsParsed.defaultTargetBranch ?? "develop"),
|
|
198
200
|
pr: vcsParsed.pr ?? {},
|
|
199
|
-
tokenDefaults: vcsParsed.tokenDefaults,
|
|
200
201
|
gitlab: vcsParsed.gitlab,
|
|
201
202
|
github: vcsParsed.github,
|
|
202
203
|
skill: "/wk-pr",
|
|
203
204
|
switchHint: 'Set "provider" to "gitlab" or "github" in vcs.json',
|
|
204
205
|
};
|
|
205
|
-
tokenCreateUrls = vcsTokenCreateUrls();
|
|
206
|
-
if (!("error" in vcsCfg)) {
|
|
207
|
-
vcsCfg.tokenCreate = tokenCreateUrls.active;
|
|
208
|
-
vcsCfg.tokenCreateUrls = { gitlab: tokenCreateUrls.gitlab, github: tokenCreateUrls.github };
|
|
209
|
-
}
|
|
210
206
|
} else if (fs.existsSync(vcsJson)) {
|
|
211
207
|
vcsCfg = { config_edit_path: resolvePath(vcsJson), error: "invalid vcs.json" };
|
|
212
208
|
}
|
|
@@ -220,54 +216,6 @@ export function initStatusData(configDirPath = configDir()): Record<string, any>
|
|
|
220
216
|
fix: "workit_init_apply action=vcs_scaffold",
|
|
221
217
|
});
|
|
222
218
|
|
|
223
|
-
const provActive = vcsCfg && !("error" in vcsCfg) ? vcsCfg.provider : null;
|
|
224
|
-
const tokenItem = (tid: string, label: string, rawPath: string, providerKey: string) => {
|
|
225
|
-
const t = path.isAbsolute(rawPath) ? rawPath : path.resolve(configDirPath, rawPath);
|
|
226
|
-
const abs = fs.existsSync(t) ? resolvePath(t) : path.resolve(t);
|
|
227
|
-
const text = fs.existsSync(t) ? fs.readFileSync(t, "utf8").trim() : "";
|
|
228
|
-
const ph = isPlaceholder(text);
|
|
229
|
-
const ok = fs.existsSync(t) && modeOk(t) && Boolean(text) && !ph;
|
|
230
|
-
const item: Record<string, any> = {
|
|
231
|
-
id: tid,
|
|
232
|
-
label,
|
|
233
|
-
ok,
|
|
234
|
-
path: abs,
|
|
235
|
-
token_edit_path: abs,
|
|
236
|
-
placeholder: ph,
|
|
237
|
-
fix: `Open ${abs} — replace ${TOKEN_PLACEHOLDER}, save, then /wk-status`,
|
|
238
|
-
required: provActive === providerKey,
|
|
239
|
-
};
|
|
240
|
-
if (tokenCreateUrls) {
|
|
241
|
-
const block = tokenCreateUrls[providerKey] ?? {};
|
|
242
|
-
if (block.createUrl) item.token_create_url = block.createUrl;
|
|
243
|
-
if (block.createUrlClassic) item.token_create_url_classic = block.createUrlClassic;
|
|
244
|
-
if (block.scopes) item.token_scopes = block.scopes;
|
|
245
|
-
if (block.permissions) item.token_permissions = block.permissions;
|
|
246
|
-
if (block.name) item.token_name = block.name;
|
|
247
|
-
}
|
|
248
|
-
return item;
|
|
249
|
-
};
|
|
250
|
-
const vcsTokenFiles: Record<string, string> = {};
|
|
251
|
-
for (const k of ["gitlab", "github"]) {
|
|
252
|
-
vcsTokenFiles[k] = String(vcsParsed?.[k]?.tokenFile ?? path.join(configDirPath, `${k}.token`));
|
|
253
|
-
}
|
|
254
|
-
items.push(
|
|
255
|
-
tokenItem(
|
|
256
|
-
"gitlab_token",
|
|
257
|
-
"GitLab token (mode 600, not placeholder)",
|
|
258
|
-
vcsTokenFiles.gitlab,
|
|
259
|
-
"gitlab",
|
|
260
|
-
),
|
|
261
|
-
);
|
|
262
|
-
items.push(
|
|
263
|
-
tokenItem(
|
|
264
|
-
"github_token",
|
|
265
|
-
"GitHub token (mode 600, not placeholder)",
|
|
266
|
-
vcsTokenFiles.github,
|
|
267
|
-
"github",
|
|
268
|
-
),
|
|
269
|
-
);
|
|
270
|
-
|
|
271
219
|
return {
|
|
272
220
|
config_dir: configDirPath,
|
|
273
221
|
plugin_root: PLUGIN_ROOT,
|
|
@@ -290,11 +238,6 @@ export async function toolkitStatusData(configDirPath = configDir()): Promise<Re
|
|
|
290
238
|
typeof vcsCfg.provider === "string" && vcsCfg.provider.trim()
|
|
291
239
|
? vcsCfg.provider.toLowerCase()
|
|
292
240
|
: null;
|
|
293
|
-
const vcsTokenId =
|
|
294
|
-
provider === "gitlab" ? "gitlab_token" : provider === "github" ? "github_token" : null;
|
|
295
|
-
const vcsTokenItem =
|
|
296
|
-
(vcsTokenId ? status.items.find((i: Record<string, any>) => i.id === vcsTokenId) : null) ?? {};
|
|
297
|
-
const vcsPlaceholder = vcsTokenId ? (vcsTokenItem.placeholder ?? true) : true;
|
|
298
241
|
const vcsJsonOk = Boolean(status.items.find((i: Record<string, any>) => i.id === "vcs_json")?.ok);
|
|
299
242
|
|
|
300
243
|
const verify = placeholder
|
|
@@ -306,16 +249,13 @@ export async function toolkitStatusData(configDirPath = configDir()): Promise<Re
|
|
|
306
249
|
ok: false,
|
|
307
250
|
error: "vcs provider unconfigured — set provider to gitlab or github in vcs.json",
|
|
308
251
|
}
|
|
309
|
-
:
|
|
310
|
-
? { ok: false, error: "vcs token still placeholder YOUR_TOKEN_HERE" }
|
|
311
|
-
: await vcsVerifyToken();
|
|
252
|
+
: await vcsVerifyToken();
|
|
312
253
|
const youTrackHealth = ("data" in verify ? verify.data : verify) as Record<string, any>;
|
|
313
254
|
|
|
314
255
|
status.youtrack_verify = verify;
|
|
315
256
|
status.youtrack_ok = placeholder ? false : Boolean(youTrackHealth.ok);
|
|
316
257
|
status.vcs_verify = vcsVerify;
|
|
317
|
-
status.vcs_ok =
|
|
318
|
-
vcsJsonOk && !vcsPlaceholder ? Boolean((vcsVerify as Record<string, any>).ok) : false;
|
|
258
|
+
status.vcs_ok = vcsJsonOk && Boolean((vcsVerify as Record<string, any>).ok);
|
|
319
259
|
|
|
320
260
|
const fsReady = status.items.every((i: Record<string, any>) => i.required === false || i.ok);
|
|
321
261
|
status.ready = fsReady && Boolean(status.youtrack_ok) && (!vcsJsonOk || Boolean(status.vcs_ok));
|
|
@@ -328,13 +268,10 @@ export async function toolkitStatusData(configDirPath = configDir()): Promise<Re
|
|
|
328
268
|
status.next_step = createUrl
|
|
329
269
|
? "Open the YouTrack create-token URL, New token (name workit, scope YouTrack), paste into the token file, save, then run /wk-status"
|
|
330
270
|
: "Open the YouTrack token file, replace YOUR_TOKEN_HERE, save, then run /wk-status";
|
|
331
|
-
} else if (vcsJsonOk && vcsPlaceholder) {
|
|
332
|
-
status.vcs_token_edit_path = vcsTokenItem.token_edit_path ?? "";
|
|
333
|
-
status.next_step = `Open ${vcsTokenItem.token_edit_path ?? ""}, paste your ${provider} token, save, then run /wk-status`;
|
|
334
271
|
} else if (!status.youtrack_ok) {
|
|
335
272
|
status.next_step = "Fix YouTrack token or re-run /wk-init";
|
|
336
273
|
} else if (vcsJsonOk && !status.vcs_ok) {
|
|
337
|
-
status.next_step = `
|
|
274
|
+
status.next_step = `Run ${provider === "gitlab" ? "glab" : "gh"} auth login/switch, then /wk-status`;
|
|
338
275
|
} else if (status.ready) {
|
|
339
276
|
status.next_step = "All checks passed";
|
|
340
277
|
}
|
|
@@ -376,31 +313,22 @@ const youtrackJsonContent = (dir: string): Record<string, any> => ({
|
|
|
376
313
|
},
|
|
377
314
|
});
|
|
378
315
|
|
|
379
|
-
const vcsJsonContent = (
|
|
316
|
+
const vcsJsonContent = (): Record<string, any> => {
|
|
380
317
|
// Explicit provider at init: env wins, else the checkout's origin remote
|
|
381
318
|
// (same RL-03b rule as vcs-config). Unresolvable means the field is
|
|
382
319
|
// omitted — never a silent assumption downstream.
|
|
383
|
-
const provider = resolveInitProvider(
|
|
320
|
+
const provider = resolveInitProvider();
|
|
384
321
|
return {
|
|
385
322
|
...(provider ? { provider } : {}),
|
|
386
323
|
defaultTargetBranch: process.env.WORKFLOW_VCS_TARGET_BRANCH ?? "develop",
|
|
387
324
|
gitlab: {
|
|
388
325
|
host: process.env.WORKFLOW_GITLAB_HOST ?? "gitlab.com",
|
|
389
326
|
apiUrl: process.env.WORKFLOW_GITLAB_API_URL ?? "https://gitlab.com/api/v4",
|
|
390
|
-
tokenFile: path.join(dir, "gitlab.token"),
|
|
391
327
|
},
|
|
392
328
|
github: {
|
|
393
329
|
host: process.env.WORKFLOW_GITHUB_HOST ?? "github.com",
|
|
394
|
-
tokenFile: path.join(dir, "github.token"),
|
|
395
330
|
},
|
|
396
331
|
pr: { squashOnMerge: true, removeSourceBranch: true, pushBranch: true, confirmSkip: true },
|
|
397
|
-
tokenDefaults: {
|
|
398
|
-
name: "workit",
|
|
399
|
-
description: "OpenCode workit — /wk-pr and glab/gh",
|
|
400
|
-
gitlabScopes: ["api"],
|
|
401
|
-
githubPermissions: { pull_requests: "write", contents: "write", metadata: "read" },
|
|
402
|
-
githubClassicScopes: ["repo"],
|
|
403
|
-
},
|
|
404
332
|
};
|
|
405
333
|
};
|
|
406
334
|
|
|
@@ -494,15 +422,7 @@ export function initApplyData(
|
|
|
494
422
|
}
|
|
495
423
|
case "vcs_scaffold": {
|
|
496
424
|
const jsonOut = path.join(dir, "vcs.json");
|
|
497
|
-
fs.writeFileSync(jsonOut, JSON.stringify(vcsJsonContent(
|
|
498
|
-
const glPath = path.join(dir, "gitlab.token");
|
|
499
|
-
const ghPath = path.join(dir, "github.token");
|
|
500
|
-
const preservedTokens: string[] = [];
|
|
501
|
-
for (const p of [glPath, ghPath]) {
|
|
502
|
-
if (writeFileExclusive(p, TOKEN_PLACEHOLDER + "\n", 0o600) === "preserved") {
|
|
503
|
-
preservedTokens.push(path.resolve(p));
|
|
504
|
-
}
|
|
505
|
-
}
|
|
425
|
+
fs.writeFileSync(jsonOut, JSON.stringify(vcsJsonContent(), null, 2) + "\n", "utf8");
|
|
506
426
|
const configPath = path.resolve(jsonOut);
|
|
507
427
|
const prev = process.env.WORKFLOW_VCS_CONFIG;
|
|
508
428
|
process.env.WORKFLOW_VCS_CONFIG = configPath;
|
|
@@ -510,39 +430,23 @@ export function initApplyData(
|
|
|
510
430
|
const cfg = readJson(configPath) ?? {};
|
|
511
431
|
const rawProvider = cfg.provider;
|
|
512
432
|
const provider = typeof rawProvider === "string" && rawProvider.trim() ? rawProvider : null;
|
|
513
|
-
const tokenUrls = vcsTokenCreateUrls();
|
|
514
|
-
const active = tokenUrls.active ?? {};
|
|
515
|
-
const activePath =
|
|
516
|
-
provider === "gitlab"
|
|
517
|
-
? path.resolve(glPath)
|
|
518
|
-
: provider === "github"
|
|
519
|
-
? path.resolve(ghPath)
|
|
520
|
-
: null;
|
|
521
433
|
return {
|
|
522
434
|
action,
|
|
523
435
|
ok: true,
|
|
524
436
|
vcs_json: configPath,
|
|
525
437
|
config_edit_path: configPath,
|
|
526
|
-
gitlab_token: path.resolve(glPath),
|
|
527
|
-
github_token: path.resolve(ghPath),
|
|
528
|
-
token_edit_path: activePath,
|
|
529
|
-
token_create_url: active.createUrl,
|
|
530
|
-
token_create_urls: tokenUrls,
|
|
531
|
-
preserved_tokens: preservedTokens,
|
|
532
438
|
vcs_config: {
|
|
533
439
|
config_edit_path: configPath,
|
|
534
440
|
provider,
|
|
535
441
|
defaultTargetBranch: cfg.defaultTargetBranch,
|
|
536
442
|
pr: cfg.pr,
|
|
537
|
-
|
|
538
|
-
tokenCreateUrls: { gitlab: tokenUrls.gitlab, github: tokenUrls.github },
|
|
539
|
-
switchHint: 'Change "provider" to "github" when you migrate — token files are separate',
|
|
443
|
+
switchHint: 'Change "provider" to "github" when you migrate; authenticate with gh/glab',
|
|
540
444
|
skill: "/wk-pr",
|
|
541
445
|
},
|
|
542
446
|
instruction:
|
|
543
447
|
provider === null
|
|
544
448
|
? `No provider resolved — set provider to gitlab or github in ${configPath}, then /wk-status.`
|
|
545
|
-
: `
|
|
449
|
+
: `Run ${provider === "gitlab" ? "glab" : "gh"} auth login, then /wk-status.`,
|
|
546
450
|
};
|
|
547
451
|
} finally {
|
|
548
452
|
if (prev === undefined) delete process.env.WORKFLOW_VCS_CONFIG;
|
|
@@ -565,9 +469,15 @@ export function initApplyData(
|
|
|
565
469
|
|
|
566
470
|
export function initStatus(): Record<string, any> {
|
|
567
471
|
const data = initStatusData();
|
|
472
|
+
const workspaces: Record<string, any> = { path: workspacesPath(), resolved: null };
|
|
473
|
+
try {
|
|
474
|
+
workspaces.resolved = resolveWorkspace(process.cwd());
|
|
475
|
+
} catch (error) {
|
|
476
|
+
workspaces.error = error instanceof Error ? error.message : String(error);
|
|
477
|
+
}
|
|
568
478
|
return {
|
|
569
479
|
...data,
|
|
570
|
-
workspaces
|
|
480
|
+
workspaces,
|
|
571
481
|
};
|
|
572
482
|
}
|
|
573
483
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// SHA-256 of generated Cursor assets in the published 1.2.1 package. These
|
|
2
|
+
// hashes prove ownership for a narrow, known upgrade source; filenames alone
|
|
3
|
+
// never authorize replacing an installed file.
|
|
4
|
+
export const LEGACY_CURSOR_ASSET_DIGESTS: Readonly<Record<string, string>> = {
|
|
5
|
+
"commands/wk-babysit.md": "002b00bba340ace6bf64a605f7e26c56b6224010529dbf5fd8966102f0065553",
|
|
6
|
+
"commands/wk-blast-radius.md": "474030101d592fe61931baffd50158bf58987eb65902a594df26e53bd62e1d57",
|
|
7
|
+
"commands/wk-challenge.md": "65f3e3bf5ce2d2ec0b77d2fe061894a53c3de98ee5d00cba8cf6a8259b4c6f46",
|
|
8
|
+
"commands/wk-debug.md": "8a67a77da27df3e6416ec685f360c79537feac10c324baf4a2d6f3a0329d7623",
|
|
9
|
+
"commands/wk-deslop.md": "8d31b708225fcc8b6de12a8ce8b3e42c74a20821f1b86d347d969e0906bc1397",
|
|
10
|
+
"commands/wk-diagram.md": "d83a8b4b08f2e9ae30e7ee372b89ed400193ca6cc5fc918087b47283efe2b4a6",
|
|
11
|
+
"commands/wk-green-run.md": "0de645228cedb650ef24ade84d1800891a83ce39a568bc5f04f036542e1c0a4a",
|
|
12
|
+
"commands/wk-handoff.md": "525e3ea4717593826d6a2daf72bfdd35602b33dd77c6d03166e865ad29c65592",
|
|
13
|
+
"commands/wk-implement.md": "9e74766ba1829dbf04cc95e0c4d96fbeaafef57708ce6ff0d027a9ffad6de4c5",
|
|
14
|
+
"commands/wk-mockup.md": "9c441ada81c2b90510dd57804d25fc6b9ccc4f28870d98d1a3f2327e2b6564a4",
|
|
15
|
+
"commands/wk-plan.md": "8b3014450cdb1099f13628e983ce3b3d1566d8594c4bde8b31d74e8587b918ea",
|
|
16
|
+
"commands/wk-review.md": "4260e80e556a1b3042a3990cf1a53a4cb8ea74078667e5c24269f10c58f25f0e",
|
|
17
|
+
"commands/wk-steer.md": "251795b24df1395a4786d1565a2ab32a1f1d5321d33fbc3175bbf917a9c4ea1a",
|
|
18
|
+
"commands/wk-tdd.md": "b3e00a37d9ea1c0c133fc86aaf3c56b8d38bb443aded2ad05a06a9cc762c86f5",
|
|
19
|
+
"rules/workit-contract.mdc": "a7425e888f19c8984f784cc6395800f33ac094525863a894e5fba516ff7ff450",
|
|
20
|
+
"skills/workit-babysit/SKILL.md":
|
|
21
|
+
"a8958f7042be13048756a0c6ad7415feaf356132431b1d8b6e0f6617e34281a3",
|
|
22
|
+
"skills/workit-behavioral-tdd/SKILL.md":
|
|
23
|
+
"78207d684f9f50fa9c6d3ab68e425f71aa12975414c874975ce2daf427b9cf9d",
|
|
24
|
+
"skills/workit-blast-radius/SKILL.md":
|
|
25
|
+
"e829d3106a2b65c3f8aeceb53a1dbd3fadacbf1b1e1380a432e5e5f997e8a5a5",
|
|
26
|
+
"skills/workit-challenge/SKILL.md":
|
|
27
|
+
"60273fc7bdf7920e88e19c9d448f8d74a3e881dcce5f726f6aa947e4fc3881cf",
|
|
28
|
+
"skills/workit-debug/SKILL.md":
|
|
29
|
+
"e2776294e5ed3dc3c5c9d6c0d6321e53204cc4f0a7206424d32dca862d47d748",
|
|
30
|
+
"skills/workit-deslop/SKILL.md":
|
|
31
|
+
"e917dabad0fade7ee29bb4de36fd0bfeb9235d063951c3adad2f501c2d880f15",
|
|
32
|
+
"skills/workit-diagram/SKILL.md":
|
|
33
|
+
"d4a46c95d38b77e05f2246a3ab20b6ce8a5c5a2125df7c4ed5d4b79398307f9e",
|
|
34
|
+
"skills/workit-green-run/SKILL.md":
|
|
35
|
+
"f1bf1af81acd33c72f23a3f803a40c737bdd9e1a1889fb2c2b41ab9336679c4f",
|
|
36
|
+
"skills/workit-handoff/SKILL.md":
|
|
37
|
+
"855fc35166bb8886a1adca17f638ddb85508f36671bb034e00e1e0e2b403614a",
|
|
38
|
+
"skills/workit-implement/SKILL.md":
|
|
39
|
+
"7ba5adb7d6cf2acc34d25b10164e2af6b9f99d3bc5ef20ff5409b75e03e98bd4",
|
|
40
|
+
"skills/workit-mockup/SKILL.md":
|
|
41
|
+
"56fc4046599150874b498b269873d1522e671e72b17257fe312a4786205e15c3",
|
|
42
|
+
"skills/workit-plan/SKILL.md": "6283fdcc6c11c0267e679ce4eefbdd67e7fb5b819521dd86d9908a93bf78482e",
|
|
43
|
+
"skills/workit-review/SKILL.md":
|
|
44
|
+
"0f7c662abedd167589d3974013ff805df650dfc881d9709dfcfa4124c0dbe58d",
|
|
45
|
+
"skills/workit-steer/SKILL.md":
|
|
46
|
+
"5e7142010675d55c21ef84fc2b077f06163c27f95ff4d9ae22a7fda13c7ca543",
|
|
47
|
+
};
|
package/src/core/methods.ts
CHANGED
|
@@ -87,56 +87,69 @@ export function selectMethods(policy: Policy, capabilities: Capability[]): Selec
|
|
|
87
87
|
|
|
88
88
|
export const invariantBootstrap = (): string =>
|
|
89
89
|
`
|
|
90
|
-
Workit
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
90
|
+
Workit is optional coordination and repository-policy tooling around the host,
|
|
91
|
+
not a permission system or a mandatory workflow. Native host allow/ask/deny,
|
|
92
|
+
sandbox, plan/read-only mode, and organization rules remain authoritative.
|
|
93
|
+
Ordinary investigation, questions, non-Git work, and routine reversible edits
|
|
94
|
+
need zero Workit task, assessment, or writer calls. Use one compact tracked
|
|
95
|
+
record only when handoff, dependent steps, concurrent actors, or meaningful
|
|
96
|
+
decisions make continuity useful; similar titles alone never merge tasks.
|
|
97
|
+
|
|
98
|
+
For a routine user-authorized branch or commit, prefer native host Git/shell
|
|
99
|
+
tools from the outset when managed coordination or outcome reconciliation is
|
|
100
|
+
not needed. Inspect the actual target checkout and its configured conventions;
|
|
101
|
+
use Workit's read-only context/policy tools when needed. Do not start a task,
|
|
102
|
+
acquire a writer, or mint a decision receipt solely for a native Git action.
|
|
103
|
+
Native permissions still apply. Never switch execution paths to evade a denial
|
|
104
|
+
or repeat an uncertain managed effect. A local-commit endpoint does not imply
|
|
105
|
+
PR readiness, a fresh review, or post-commit assessment/closure paperwork.
|
|
106
|
+
|
|
107
|
+
For tracked work, inspect its current state and use the shared operations for
|
|
108
|
+
task, policy, evidence, finding, decision, worker, writer, and state changes.
|
|
109
|
+
Start a record once for an explicit tracked objective; assess or reassess only
|
|
110
|
+
when policy selection or changed evidence/constraints requires it. Omitted
|
|
111
|
+
expectedRevision and expectedWorkspaceRevision use current values; explicit
|
|
112
|
+
values are still concurrency-checked, so never copy revisions between calls.
|
|
113
|
+
A solo edit does not need writer acquisition; use it when concurrent checkout
|
|
114
|
+
writers need coordination. Record only observed facts and checks. Evidence can
|
|
115
|
+
become stale when its bound candidate changes; reconcile findings against the
|
|
116
|
+
current candidate before recording completion.
|
|
117
|
+
|
|
118
|
+
Workit validates domain policy against the actual action target, configured
|
|
119
|
+
account, branch and commit conventions, protected refs, and current repository
|
|
120
|
+
state. The task directory is coordination state, not a boundary on which
|
|
121
|
+
repository may be changed. Use an action-time cwd target where a managed
|
|
122
|
+
Git/hosting action supports it; a non-Git directory remains valid for OS work.
|
|
123
|
+
GitHub/GitLab use the active gh/glab CLI identity; YouTrack uses its own token.
|
|
124
|
+
Preserve uncertain external outcomes and reconcile repository/provider state
|
|
125
|
+
before retrying. Internal reservations prevent duplicate or ambiguous effects;
|
|
126
|
+
they are not permission tickets for every edit.
|
|
127
|
+
|
|
128
|
+
Use host-native authorization through the host's supported path. A native
|
|
129
|
+
question receipt records an actual question interaction; it is not automatic
|
|
130
|
+
host permission. Record a meaningful user choice once with provenance when
|
|
131
|
+
future retrieval helps. Never fabricate a receipt, re-ask only to mint one, or
|
|
132
|
+
let imported decisions grant authority. Never turn a host deny into allow or
|
|
133
|
+
claim enforcement/evidence a host cannot provide. A precise request with settled
|
|
134
|
+
constraints does not need an interview. Present genuine unresolved options with
|
|
135
|
+
evidence and a recommendation, then continue toward the requested delivery
|
|
136
|
+
endpoint: investigation, implementation, PR/MR-ready, merge, or release. Run
|
|
137
|
+
applicable checks and safe repairs without repeated continuation questions;
|
|
138
|
+
stop for missing host authority, a new consequential choice, a conflicting edit,
|
|
139
|
+
or an unresolved blocker. A tracked record may close when actual evidence
|
|
140
|
+
supports its outcome; no final human closure ceremony is required.
|
|
141
|
+
|
|
142
|
+
A completed native subagent run stops its bound worker by itself; if a worker
|
|
143
|
+
strands in cancelling with its run verifiably over, repeat worker.cancel to
|
|
144
|
+
confirm the stop. Preserve unresolved requirements, gaps, and uncertain workers.
|
|
145
|
+
When context changes, distinguish a quick question, same-task adjustment, and
|
|
146
|
+
separate request. Answer a quick question without pausing/resuming task state;
|
|
147
|
+
park a concise checkpoint only when substantial work needs to continue later.
|
|
148
|
+
|
|
149
|
+
Skill routing: slash aliases /wk-* load on demand. Use workit-steer for a
|
|
150
|
+
substantial interruption or change of direction, workit-deslop when relevant
|
|
151
|
+
to a PR-ready endpoint, workit-green-run for failing CI, workit-blast-radius
|
|
152
|
+
when impact is uncertain, and workit-challenge for genuinely open consequential
|
|
153
|
+
choices. Load workit-plan when dependencies or handoff need durable next actions.
|
|
154
|
+
Load the skill; never act from memory of it.
|
|
142
155
|
`.trim();
|
|
@@ -326,6 +326,11 @@ function resolveRequirements(input: NormalizedResolverInput): Requirement[] {
|
|
|
326
326
|
}),
|
|
327
327
|
);
|
|
328
328
|
|
|
329
|
+
const independentBehaviorReview =
|
|
330
|
+
input.preferences?.thorough === true ||
|
|
331
|
+
input.assessment.consequences.some((consequence) =>
|
|
332
|
+
["security", "data", "public_contract", "operations"].includes(consequence.area),
|
|
333
|
+
);
|
|
329
334
|
if (signals.behaviorChange.value === true)
|
|
330
335
|
requirements.push(
|
|
331
336
|
requirement({
|
|
@@ -340,15 +345,18 @@ function resolveRequirements(input: NormalizedResolverInput): Requirement[] {
|
|
|
340
345
|
acceptanceAllowed: false,
|
|
341
346
|
}),
|
|
342
347
|
requirement({
|
|
343
|
-
ruleId: "fresh-context-review",
|
|
348
|
+
ruleId: independentBehaviorReview ? "fresh-context-review" : "self-review",
|
|
344
349
|
dimension: "review",
|
|
345
350
|
scope,
|
|
346
|
-
reason:
|
|
347
|
-
|
|
348
|
-
"
|
|
351
|
+
reason: independentBehaviorReview
|
|
352
|
+
? "Consequential behavior or the thorough preference requires fresh-context review."
|
|
353
|
+
: "Bounded behavior changes use self-review unless consequential risks or trusted rules require more.",
|
|
354
|
+
satisfaction: independentBehaviorReview
|
|
355
|
+
? "A separate review context examines the current candidate and records its result."
|
|
356
|
+
: "The lead reviews the resulting diff and records the relevant scope and checks.",
|
|
349
357
|
before: "close",
|
|
350
358
|
dependentAction: null,
|
|
351
|
-
acceptanceAllowed:
|
|
359
|
+
acceptanceAllowed: !independentBehaviorReview,
|
|
352
360
|
}),
|
|
353
361
|
);
|
|
354
362
|
else if (signals.mechanicalLowRisk.value === true)
|
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
// CLI port of scripts/pr-create.sh — create | --build-body.
|
|
2
|
-
|
|
2
|
+
//
|
|
3
|
+
// Decision ae03c569 re-enabled hosted PR/MR creation with pre/post provider SHA
|
|
4
|
+
// verification and accepted the residual non-atomic source-SHA race. The legacy
|
|
5
|
+
// create mode still cannot mint the native action receipt, the one-time action
|
|
6
|
+
// reservation, or the target writer lease the shared contract requires, so it
|
|
7
|
+
// never performs a hosted create itself. It returns the same needs_input shape
|
|
8
|
+
// as the headless `workit action` route and points at the reserved,
|
|
9
|
+
// TTY-confirmed shared path.
|
|
10
|
+
import { prBuildBody } from "../pr-create";
|
|
3
11
|
|
|
4
12
|
const mode = process.argv[2] ?? "create";
|
|
5
13
|
if (mode === "--build-body") {
|
|
6
14
|
console.log(JSON.stringify({ body: prBuildBody(process.env, process.cwd()) }));
|
|
7
15
|
process.exit(0);
|
|
8
16
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
console.log(
|
|
18
|
+
JSON.stringify({
|
|
19
|
+
ok: false,
|
|
20
|
+
schemaVersion: 1,
|
|
21
|
+
code: "needs_input",
|
|
22
|
+
error: "hosted PR/MR creation requires the reserved shared action path with TTY confirmation",
|
|
23
|
+
details: {
|
|
24
|
+
operation: "hosting.pull_request",
|
|
25
|
+
guidance:
|
|
26
|
+
"Run `workit action hosting.pull_request --payload <file> --confirm` from the target checkout: it records the one-time action reservation behind the terminal confirmation and verifies the provider PR head against the approved source SHA before reporting success.",
|
|
27
|
+
},
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
process.exit(1);
|