@codyswann/lisa 2.237.0 → 2.239.0
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/core/learnings-writer.d.ts +22 -0
- package/dist/core/learnings-writer.d.ts.map +1 -1
- package/dist/core/learnings-writer.js +51 -8
- package/dist/core/learnings-writer.js.map +1 -1
- package/dist/core/learnings.d.ts +1 -1
- package/dist/core/learnings.d.ts.map +1 -1
- package/dist/core/learnings.js +1 -1
- package/dist/core/learnings.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-atlassian-access/SKILL.md +12 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
- package/plugins/lisa/.codex-plugin/skills/lisa-git-submit-pr/SKILL.md +3 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +5 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +5 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +54 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +5 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/SKILL.md +145 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/agents/openai.yaml +4 -0
- package/plugins/lisa/agents/learning-judge.md +119 -0
- package/plugins/lisa/commands/persist-learning.md +6 -0
- package/plugins/lisa/rules/eager/rejection-detection.md +40 -0
- package/plugins/lisa/rules/reference/rejection-detection.md +103 -0
- package/plugins/lisa/skills/lisa-atlassian-access/SKILL.md +12 -1
- package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
- package/plugins/lisa/skills/lisa-git-submit-pr/SKILL.md +3 -2
- package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +5 -1
- package/plugins/lisa/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +5 -1
- package/plugins/lisa/skills/lisa-linear-access/SKILL.md +54 -0
- package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +5 -1
- package/plugins/lisa/skills/lisa-persist-learning/SKILL.md +145 -0
- package/plugins/lisa/skills/lisa-persist-learning/agents/openai.yaml +4 -0
- package/plugins/lisa-agy/agents/learning-judge.md +119 -0
- package/plugins/lisa-agy/commands/lisa/persist-learning.md +6 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-atlassian-access/SKILL.md +12 -1
- package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
- package/plugins/lisa-agy/skills/lisa-git-submit-pr/SKILL.md +3 -2
- package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +5 -1
- package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +5 -1
- package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +54 -0
- package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +5 -1
- package/plugins/lisa-agy/skills/lisa-persist-learning/SKILL.md +145 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/agents/learning-judge.agent.md +119 -0
- package/plugins/lisa-copilot/commands/lisa/persist-learning.md +6 -0
- package/plugins/lisa-copilot/rules/eager/rejection-detection.md +40 -0
- package/plugins/lisa-copilot/rules/reference/rejection-detection.md +103 -0
- package/plugins/lisa-copilot/skills/lisa-atlassian-access/SKILL.md +12 -1
- package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
- package/plugins/lisa-copilot/skills/lisa-git-submit-pr/SKILL.md +3 -2
- package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +5 -1
- package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +5 -1
- package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +54 -0
- package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +5 -1
- package/plugins/lisa-copilot/skills/lisa-persist-learning/SKILL.md +145 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/agents/learning-judge.md +119 -0
- package/plugins/lisa-cursor/commands/lisa/persist-learning.md +6 -0
- package/plugins/lisa-cursor/rules/rejection-detection-reference.mdc +108 -0
- package/plugins/lisa-cursor/rules/rejection-detection.mdc +45 -0
- package/plugins/lisa-cursor/skills/lisa-atlassian-access/SKILL.md +12 -1
- package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
- package/plugins/lisa-cursor/skills/lisa-git-submit-pr/SKILL.md +3 -2
- package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +5 -1
- package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +5 -1
- package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +54 -0
- package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +5 -1
- package/plugins/lisa-cursor/skills/lisa-persist-learning/SKILL.md +145 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/agents/learning-judge.md +119 -0
- package/plugins/src/base/commands/persist-learning.md +6 -0
- package/plugins/src/base/rules/eager/rejection-detection.md +40 -0
- package/plugins/src/base/rules/reference/rejection-detection.md +103 -0
- package/plugins/src/base/skills/lisa-atlassian-access/SKILL.md +12 -1
- package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
- package/plugins/src/base/skills/lisa-git-submit-pr/SKILL.md +3 -2
- package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +5 -1
- package/plugins/src/base/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +5 -1
- package/plugins/src/base/skills/lisa-linear-access/SKILL.md +54 -0
- package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +5 -1
- package/plugins/src/base/skills/lisa-persist-learning/SKILL.md +145 -0
|
@@ -1,10 +1,32 @@
|
|
|
1
|
+
/** Write-time consolidation options for {@link persistConsolidatedLearning}. */
|
|
2
|
+
export interface ConsolidatedLearningOptions {
|
|
3
|
+
/** Ids of existing entries the new entry merges or replaces. */
|
|
4
|
+
readonly supersede?: readonly string[];
|
|
5
|
+
}
|
|
1
6
|
/**
|
|
2
7
|
* Persist one already-selected learning without generating or truncating it.
|
|
8
|
+
* Append-only: a duplicate id always throws. Kept as the stable back-compat
|
|
9
|
+
* entry point; consolidation-aware writers use
|
|
10
|
+
* {@link persistConsolidatedLearning} instead.
|
|
3
11
|
* @param projectRoot - Absolute path to the host project root
|
|
4
12
|
* @param candidate - Untrusted seven-field learning entry
|
|
5
13
|
* @returns Absolute path to the persisted learnings file
|
|
6
14
|
*/
|
|
7
15
|
export declare function persistLearningEntry(projectRoot: string, candidate: unknown): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Persist one learning with mandatory write-time consolidation semantics:
|
|
18
|
+
* entries named in `supersede` are dropped from the document in the same
|
|
19
|
+
* atomic write that adds the new entry, so a related existing entry is merged
|
|
20
|
+
* or replaced instead of gaining a near-duplicate sibling. The rendered
|
|
21
|
+
* document is re-validated against the shared entry and file budgets after
|
|
22
|
+
* consolidation. Without `supersede` this is exactly the append-only
|
|
23
|
+
* {@link persistLearningEntry} behavior, including the duplicate-id throw.
|
|
24
|
+
* @param projectRoot - Absolute path to the host project root
|
|
25
|
+
* @param candidate - Untrusted seven-field learning entry
|
|
26
|
+
* @param options - Optional consolidation directives
|
|
27
|
+
* @returns Absolute path to the persisted learnings file
|
|
28
|
+
*/
|
|
29
|
+
export declare function persistConsolidatedLearning(projectRoot: string, candidate: unknown, options?: ConsolidatedLearningOptions): Promise<string>;
|
|
8
30
|
export { parseLearningsFile, renderLearningsFile, } from "./learnings-document.js";
|
|
9
31
|
export { validateLearningEntry } from "./learnings-entry.js";
|
|
10
32
|
//# sourceMappingURL=learnings-writer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-writer.d.ts","sourceRoot":"","sources":["../../src/core/learnings-writer.ts"],"names":[],"mappings":"AAsBA
|
|
1
|
+
{"version":3,"file":"learnings-writer.d.ts","sourceRoot":"","sources":["../../src/core/learnings-writer.ts"],"names":[],"mappings":"AAsBA,gFAAgF;AAChF,MAAM,WAAW,2BAA2B;IAC1C,gEAAgE;IAChE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,2BAA2B,CAC/C,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,OAAO,EAClB,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,MAAM,CAAC,CA4BjB;AAED,OAAO,EACL,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -9,25 +9,44 @@ import { withLearningTargetLock } from "./learnings-lock.js";
|
|
|
9
9
|
import { readProjectConfig, resolveProjectLearningsFile, } from "./project-config.js";
|
|
10
10
|
/**
|
|
11
11
|
* Persist one already-selected learning without generating or truncating it.
|
|
12
|
+
* Append-only: a duplicate id always throws. Kept as the stable back-compat
|
|
13
|
+
* entry point; consolidation-aware writers use
|
|
14
|
+
* {@link persistConsolidatedLearning} instead.
|
|
12
15
|
* @param projectRoot - Absolute path to the host project root
|
|
13
16
|
* @param candidate - Untrusted seven-field learning entry
|
|
14
17
|
* @returns Absolute path to the persisted learnings file
|
|
15
18
|
*/
|
|
16
19
|
export async function persistLearningEntry(projectRoot, candidate) {
|
|
20
|
+
return persistConsolidatedLearning(projectRoot, candidate);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Persist one learning with mandatory write-time consolidation semantics:
|
|
24
|
+
* entries named in `supersede` are dropped from the document in the same
|
|
25
|
+
* atomic write that adds the new entry, so a related existing entry is merged
|
|
26
|
+
* or replaced instead of gaining a near-duplicate sibling. The rendered
|
|
27
|
+
* document is re-validated against the shared entry and file budgets after
|
|
28
|
+
* consolidation. Without `supersede` this is exactly the append-only
|
|
29
|
+
* {@link persistLearningEntry} behavior, including the duplicate-id throw.
|
|
30
|
+
* @param projectRoot - Absolute path to the host project root
|
|
31
|
+
* @param candidate - Untrusted seven-field learning entry
|
|
32
|
+
* @param options - Optional consolidation directives
|
|
33
|
+
* @returns Absolute path to the persisted learnings file
|
|
34
|
+
*/
|
|
35
|
+
export async function persistConsolidatedLearning(projectRoot, candidate, options = {}) {
|
|
17
36
|
const entry = validateLearningEntry(candidate);
|
|
18
|
-
const
|
|
37
|
+
const supersede = validateSupersedeIds(options.supersede);
|
|
19
38
|
const config = await readProjectConfig(projectRoot);
|
|
20
39
|
const relativeFile = resolveProjectLearningsFile(config);
|
|
21
40
|
const { root, target } = resolveSafeLearningTarget(projectRoot, relativeFile);
|
|
41
|
+
// Fast budget fail on the lone entry before any directory is created.
|
|
42
|
+
buildNextDocument([], entry, []);
|
|
22
43
|
await assertSafeLearningParents(root, path.dirname(target));
|
|
23
44
|
await fse.ensureDir(path.dirname(target));
|
|
24
45
|
return withLearningTargetLock(target, async () => {
|
|
25
46
|
await assertSafeLearningParents(root, path.dirname(target));
|
|
26
47
|
const existing = await readExistingLearnings(target);
|
|
27
48
|
const entries = existing === undefined ? [] : parseLearningsFile(existing);
|
|
28
|
-
const rendered =
|
|
29
|
-
? initialDocument
|
|
30
|
-
: buildNextDocument(entries, entry);
|
|
49
|
+
const rendered = buildNextDocument(entries, entry, supersede);
|
|
31
50
|
const temporary = path.join(path.dirname(target), `.${path.basename(target)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
32
51
|
try {
|
|
33
52
|
await writeFile(temporary, rendered, { encoding: "utf8", flag: "wx" });
|
|
@@ -43,18 +62,42 @@ export async function persistLearningEntry(projectRoot, candidate) {
|
|
|
43
62
|
export { parseLearningsFile, renderLearningsFile, } from "./learnings-document.js";
|
|
44
63
|
export { validateLearningEntry } from "./learnings-entry.js";
|
|
45
64
|
/**
|
|
46
|
-
* Build and budget-check the next canonical document
|
|
65
|
+
* Build and budget-check the next canonical document, dropping superseded
|
|
66
|
+
* entries before the new entry is added so consolidation and the budget
|
|
67
|
+
* re-assertion happen in one deterministic step.
|
|
47
68
|
* @param entries - Existing validated entries
|
|
48
69
|
* @param entry - New validated entry
|
|
70
|
+
* @param supersede - Ids of existing entries the new entry replaces
|
|
49
71
|
* @returns Next canonical document
|
|
50
72
|
*/
|
|
51
|
-
function buildNextDocument(entries, entry) {
|
|
52
|
-
|
|
73
|
+
function buildNextDocument(entries, entry, supersede) {
|
|
74
|
+
const missing = supersede.filter(id => !entries.some(current => current.id === id));
|
|
75
|
+
if (missing.length > 0) {
|
|
76
|
+
throw new Error(`Cannot supersede unknown learning id(s): ${missing.join(", ")}`);
|
|
77
|
+
}
|
|
78
|
+
const supersededIds = new Set(supersede);
|
|
79
|
+
const retained = entries.filter(current => !supersededIds.has(current.id));
|
|
80
|
+
if (retained.some(current => current.id === entry.id)) {
|
|
53
81
|
throw new Error(`Duplicate learning id: ${entry.id}`);
|
|
54
82
|
}
|
|
55
|
-
const nextEntries = [...
|
|
83
|
+
const nextEntries = [...retained, entry].sort((left, right) => left.id.localeCompare(right.id));
|
|
56
84
|
const rendered = renderLearningsFile(nextEntries);
|
|
57
85
|
assertDocumentBudget(rendered, nextEntries.length, "Learnings file");
|
|
58
86
|
return rendered;
|
|
59
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Reject malformed supersede directives before any filesystem work.
|
|
90
|
+
* @param supersede - Caller-supplied (possibly untrusted) supersede ids
|
|
91
|
+
* @returns Deduplicated list of validated supersede ids
|
|
92
|
+
*/
|
|
93
|
+
function validateSupersedeIds(supersede) {
|
|
94
|
+
if (supersede === undefined) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
if (!Array.isArray(supersede) ||
|
|
98
|
+
supersede.some(id => typeof id !== "string" || id.trim() === "")) {
|
|
99
|
+
throw new Error("Invalid supersede option: expected non-empty learning id strings");
|
|
100
|
+
}
|
|
101
|
+
return [...new Set(supersede)];
|
|
102
|
+
}
|
|
60
103
|
//# sourceMappingURL=learnings-writer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-writer.js","sourceRoot":"","sources":["../../src/core/learnings-writer.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"learnings-writer.js","sourceRoot":"","sources":["../../src/core/learnings-writer.ts"],"names":[],"mappings":"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"}
|
package/dist/core/learnings.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export * from "./learnings-contract.js";
|
|
2
2
|
export * from "./learnings-writer.js";
|
|
3
|
-
export { DEFAULT_PROJECT_RULES_FILE, PROJECT_LEARNINGS_FILENAME, resolveProjectLearningsFile, resolveProjectRulesFile, type ProjectConfig, } from "./project-config.js";
|
|
3
|
+
export { DEFAULT_PROJECT_RULES_FILE, PROJECT_LEARNINGS_FILENAME, readProjectConfig, resolveProjectLearningsFile, resolveProjectRulesFile, type ProjectConfig, } from "./project-config.js";
|
|
4
4
|
//# sourceMappingURL=learnings.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings.d.ts","sourceRoot":"","sources":["../../src/core/learnings.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"learnings.d.ts","sourceRoot":"","sources":["../../src/core/learnings.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,iBAAiB,EACjB,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAC"}
|
package/dist/core/learnings.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export * from "./learnings-contract.js";
|
|
2
2
|
export * from "./learnings-writer.js";
|
|
3
|
-
export { DEFAULT_PROJECT_RULES_FILE, PROJECT_LEARNINGS_FILENAME, resolveProjectLearningsFile, resolveProjectRulesFile, } from "./project-config.js";
|
|
3
|
+
export { DEFAULT_PROJECT_RULES_FILE, PROJECT_LEARNINGS_FILENAME, readProjectConfig, resolveProjectLearningsFile, resolveProjectRulesFile, } from "./project-config.js";
|
|
4
4
|
//# sourceMappingURL=learnings.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings.js","sourceRoot":"","sources":["../../src/core/learnings.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,2BAA2B,EAC3B,uBAAuB,GAExB,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"learnings.js","sourceRoot":"","sources":["../../src/core/learnings.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,iBAAiB,EACjB,2BAA2B,EAC3B,uBAAuB,GAExB,MAAM,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"form-data": ">=4.0.6"
|
|
103
103
|
},
|
|
104
104
|
"name": "@codyswann/lisa",
|
|
105
|
-
"version": "2.
|
|
105
|
+
"version": "2.239.0",
|
|
106
106
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
107
107
|
"main": "dist/index.js",
|
|
108
108
|
"exports": {
|
|
@@ -291,7 +291,8 @@ Substrate column meanings:
|
|
|
291
291
|
| `write-ticket payload:<P>` (create) | guarded fallback only: `acli jira workitem create --from-json <P>` + response tenant assertion | `mcp__plugin_atlassian_atlassian__createJiraIssue` | `POST https://api.atlassian.com/ex/jira/<CLOUDID>/rest/api/3/issue` body=`<P>` |
|
|
292
292
|
| `write-ticket payload:<P>` (edit) | guarded fallback only: `acli jira workitem edit <K> --from-json <P>` + response tenant assertion | `mcp__plugin_atlassian_atlassian__editJiraIssue` | `PUT https://api.atlassian.com/ex/jira/<CLOUDID>/rest/api/3/issue/<K>` body=`<P>` |
|
|
293
293
|
| `transition key:<K> to:<S>` | guarded fallback only: `acli jira workitem transition --key <K> --status "<S>" --yes` + post-read tenant assertion | `mcp__plugin_atlassian_atlassian__transitionJiraIssue` | resolve transition id then `POST https://api.atlassian.com/ex/jira/<CLOUDID>/rest/api/3/issue/<K>/transitions` |
|
|
294
|
-
| `transitions key:<K>` | (not exposed) | `mcp__plugin_atlassian_atlassian__getTransitionsForJiraIssue` | `GET https://<SITE>/rest/api/3/issue/<K>/transitions` |
|
|
294
|
+
| `transitions key:<K>` — **false friend:** available transitions from current status, **NOT** past history; for history use `changelog` | (not exposed) | `mcp__plugin_atlassian_atlassian__getTransitionsForJiraIssue` | `GET https://<SITE>/rest/api/3/issue/<K>/transitions` |
|
|
295
|
+
| `changelog key:<K>` (read; ordered past status transitions) | (not exposed) | (not exposed) | `GET https://<SITE>/rest/api/3/issue/<K>?expand=changelog` |
|
|
295
296
|
| `comment key:<K> body:<B>` | guarded fallback only: `acli jira workitem comment add --key <K> --body "<B>"` + post-read tenant assertion | `mcp__plugin_atlassian_atlassian__addCommentToJiraIssue` | `POST https://api.atlassian.com/ex/jira/<CLOUDID>/rest/api/3/issue/<K>/comment` |
|
|
296
297
|
| `link from:<K> to:<K2> type:<T>` | guarded fallback only: `acli jira workitem link create --in <K> --out <K2> --type "<T>" --yes` + direction and tenant assertion (see direction note) | `mcp__plugin_atlassian_atlassian__createJiraIssueLink` | `POST https://api.atlassian.com/ex/jira/<CLOUDID>/rest/api/3/issueLink` |
|
|
297
298
|
| `remote-links key:<K>` | (not exposed) | `mcp__plugin_atlassian_atlassian__getJiraIssueRemoteIssueLinks` | `GET https://<SITE>/rest/api/3/issue/<K>/remotelink` |
|
|
@@ -338,6 +339,16 @@ Operations not in this table are unsupported — add an adapter row before using
|
|
|
338
339
|
- `write-page` payload: supports a label-only mutation form — `{ "id": "<I>", "labels": { "add": [...], "remove": [...] } }` — so callers transitioning PRD lifecycle labels do not need to resend the page body. Full create/update payloads also accepted.
|
|
339
340
|
- `comment-page` `kind: inline` requires `anchor` (the highlighted text the comment attaches to). `kind: footer` ignores `anchor`.
|
|
340
341
|
|
|
342
|
+
### `changelog` — transition history (read-only)
|
|
343
|
+
|
|
344
|
+
`changelog key:<K>` returns the ordered past status transitions of a JIRA issue — the raw material for rejection detection (an issue that reached `review`/`done`-ward and is now back in `ready`). It is distinct from `transitions`, which is a false friend: `transitions` lists the *available* next transitions from the current status, never past ones. `read-ticket` uses `fields=*all`, which does **not** include the changelog — the expansion must be requested explicitly with `?expand=changelog`.
|
|
345
|
+
|
|
346
|
+
- **Substrate.** The only substrate that exposes the changelog is JIRA REST via the `?expand=changelog` query parameter (a read, so the `<SITE>` gateway is allowed after the token account check). Neither `acli jira workitem view` (a field-projection tool; the changelog is an `expand`, not a field) nor the Atlassian MCP surfaces a changelog expansion, so both are marked `(not exposed)` — do not invent a separate transport, and do not try to reconstruct history from `transitions`.
|
|
347
|
+
- **Shape.** Walk `changelog.histories[].items[]` and keep entries where `field == "status"`; for each emit `{ from, to, when, author }` — `items[].fromString` → `items[].toString`, `histories[].created` (ISO timestamp), `histories[].author.displayName`/`accountId`. Preserve JIRA's oldest→newest ordering.
|
|
348
|
+
- **Empty is valid.** An issue that never transitioned returns an **empty** history — an empty history is a valid result, not an error. Callers treat empty as "never left its initial status".
|
|
349
|
+
- **Pagination / truncation.** The issue-resource changelog (`?expand=changelog`) truncates busy issues (`changelog.maxResults`/`total`/`startAt`). When `total` exceeds what the issue resource returned, page the dedicated endpoint `GET https://<SITE>/rest/api/3/issue/<K>/changelog?startAt=<n>` until `startAt + maxResults >= total`, preserving order across pages. A silently truncated history is a correctness bug for detection.
|
|
350
|
+
- **Graceful degrade — never block the build.** A failed changelog fetch (network, auth, missing substrate) returns the substrate contract's `Error:` result. Callers MUST treat that as **unknown** history and proceed — a history read failure never blocks the build.
|
|
351
|
+
|
|
341
352
|
### Step 4 — Return result
|
|
342
353
|
|
|
343
354
|
Emit either:
|
|
@@ -19,17 +19,28 @@ merges" loop. Other skills delegate here instead of re-implementing it. Runs
|
|
|
19
19
|
`chore(release): X.Y.Z [skip ci]` commits and breaks release promotion detection.
|
|
20
20
|
- `verify_commit=<sha>` — the commit that MUST end up in the merged base (for the
|
|
21
21
|
ancestry check). Default: the PR head at the time this skill starts.
|
|
22
|
+
- `auto_merge=<true|false>` — whether this skill is allowed to merge the PR at
|
|
23
|
+
all. Default `true` (existing behavior, byte-identical for every current
|
|
24
|
+
caller). With `auto_merge=false` the PR is deliberately left for a human:
|
|
25
|
+
skip the **entire** "## 1. Enable auto-merge" step — including its
|
|
26
|
+
direct-merge capability fallback — and never run any `gh pr merge` variant.
|
|
27
|
+
Still drive every blocker per `on_blocker` (green checks, resolved reviews,
|
|
28
|
+
synced branch), then stop at the `awaiting-human` terminal state below. A
|
|
29
|
+
green, open, un-merged PR is the *success* outcome of this mode, not a hang.
|
|
30
|
+
Used by learning-persistence flows whose low-confidence PRs must wait for a
|
|
31
|
+
human (`lisa-persist-learning`).
|
|
22
32
|
- `on_blocker=<fix|report>` — what to do when a blocker needs code or review work.
|
|
23
33
|
Default `fix`.
|
|
24
34
|
- **`fix`** (the full loop): resolve conflicts, fix failing checks, address +
|
|
25
35
|
resolve review comments, dismiss stale review gates — drive until merged.
|
|
26
36
|
- **`report`** (diagnose & mechanically nudge only): perform just the safe,
|
|
27
|
-
idempotent, non-destructive actions — ensure auto-merge is enabled
|
|
37
|
+
idempotent, non-destructive actions — ensure auto-merge is enabled (when
|
|
38
|
+
`auto_merge=true`) and, if the
|
|
28
39
|
PR is `BEHIND` but otherwise clean, run `gh pr update-branch` only when the
|
|
29
40
|
base branch requires strict up-to-date checks. For **anything** that would
|
|
30
41
|
require editing code, resolving threads, or dismissing a review, **do not
|
|
31
42
|
act** — stop and return a structured blocker classification
|
|
32
|
-
(`merged` / `will-merge-after-resync` / `blocked:<conflict|checks|changes_requested|deploy>`)
|
|
43
|
+
(`merged` / `will-merge-after-resync` / `blocked:<conflict|checks|changes_requested|deploy|pending-auto-fix>`)
|
|
33
44
|
so the caller applies its own policy. This is the mode `repair-intake` and the
|
|
34
45
|
build-intake skills use to diagnose-and-route without fixing in place.
|
|
35
46
|
|
|
@@ -75,6 +86,31 @@ releases is why the TTL exists; do not rely on it as the normal release path.
|
|
|
75
86
|
|
|
76
87
|
## 1. Enable auto-merge
|
|
77
88
|
|
|
89
|
+
**Gate: only when `auto_merge=true` (the default).** When `auto_merge=false`,
|
|
90
|
+
skip the enable step and its capability fallback — do not enable auto-merge,
|
|
91
|
+
and do **not** use the capability fallback below: on a repo that disallows
|
|
92
|
+
auto-merge, an `auto_merge=false` PR must stay OPEN for human triage, never be
|
|
93
|
+
silently direct-merged.
|
|
94
|
+
|
|
95
|
+
With `auto_merge=false`, also **disarm any pre-existing auto-merge latch**
|
|
96
|
+
before entering the watch loop — skipping the enable step is not enough when a
|
|
97
|
+
prior session (or `lisa-git-submit-pr`'s default path) already armed the PR,
|
|
98
|
+
because an armed latch would still merge the instant checks go green:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
armed=$(gh pr view <pr> --json autoMergeRequest -q .autoMergeRequest)
|
|
102
|
+
if [ "$armed" != "null" ] && [ -n "$armed" ]; then
|
|
103
|
+
gh pr merge <pr> --disable-auto
|
|
104
|
+
fi
|
|
105
|
+
gh pr view <pr> --json autoMergeRequest -q .autoMergeRequest # must print null
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
If the disarm fails or the re-read still shows an armed `autoMergeRequest`,
|
|
109
|
+
**fail closed**: treat the PR as a hard block (section 4) and report that the
|
|
110
|
+
`awaiting-human` state was NOT reached — never proceed to a state in which the
|
|
111
|
+
PR could merge without a human. Once disarmed (or already unarmed), proceed
|
|
112
|
+
straight to the watch loop (section 2).
|
|
113
|
+
|
|
78
114
|
Before enabling auto-merge, capture the live PR head and compare it to
|
|
79
115
|
`verify_commit`:
|
|
80
116
|
|
|
@@ -98,9 +134,11 @@ started, then re-enable auto-merge. Do not leave auto-merge armed while a
|
|
|
98
134
|
required fix, CodeRabbit follow-up, generated artifact update, or CI auto-fix is
|
|
99
135
|
still in flight.
|
|
100
136
|
|
|
101
|
-
- **Capability fallback
|
|
102
|
-
watching; once checks are green, the review gate
|
|
103
|
-
run `gh pr merge <pr> --<merge_method>`
|
|
137
|
+
- **Capability fallback** (`auto_merge=true` only): if the repo disallows
|
|
138
|
+
auto-merge, do not fail. Keep watching; once checks are green, the review gate
|
|
139
|
+
is clear, and `mergeable == MERGEABLE`, run `gh pr merge <pr> --<merge_method>`
|
|
140
|
+
directly. This fallback lives inside the gated section above — with
|
|
141
|
+
`auto_merge=false` it never fires; the PR remains open awaiting a human.
|
|
104
142
|
|
|
105
143
|
## 2. The watch loop
|
|
106
144
|
|
|
@@ -114,9 +152,17 @@ Handle every blocker class; after any fix, re-poll and continue. Do not stop whi
|
|
|
114
152
|
the PR is still open and progress is possible. On each iteration, refresh the
|
|
115
153
|
babysitter lease if its last stamp is older than ~30 minutes (section 0).
|
|
116
154
|
|
|
155
|
+
With **`auto_merge=false`**, the loop's goal changes from "merged" to "clean and
|
|
156
|
+
waiting": drive blockers exactly the same, but exit successfully at
|
|
157
|
+
`awaiting-human` (section 4) once the PR is open with green checks, a clear
|
|
158
|
+
review gate, and `mergeable == MERGEABLE`. Never enable auto-merge or merge
|
|
159
|
+
directly in this mode.
|
|
160
|
+
|
|
117
161
|
In **`on_blocker=report`** mode, only the mechanical step (a) and auto-merge enabling
|
|
118
|
-
apply; for any of (b)–(
|
|
119
|
-
contract above.
|
|
162
|
+
(when `auto_merge=true`) apply; for any of (b)–(f) do not act — classify the blocker
|
|
163
|
+
and return per the input contract above. That includes (f): adjudicating a pending
|
|
164
|
+
auto-fix PR (merging, closing, or deleting its branch) is destructive work, not
|
|
165
|
+
diagnosis — return its classification (`blocked:pending-auto-fix`) instead.
|
|
120
166
|
|
|
121
167
|
### a. Branch behind base (`mergeStateStatus == BEHIND`)
|
|
122
168
|
Before proactively syncing a clean `BEHIND` PR, check whether the base branch
|
|
@@ -196,7 +242,9 @@ needed, otherwise close it and delete the side branch. Never leave it dangling
|
|
|
196
242
|
— it represents a competing writer's pending work. Merging it mutates the
|
|
197
243
|
driven branch, so treat it like any other push: disarm auto-merge first,
|
|
198
244
|
re-read `headRefOid`, reset `verify_commit` to the merged head, wait for that
|
|
199
|
-
head's checks to start, then re-enable auto-merge (section 1).
|
|
245
|
+
head's checks to start, then re-enable auto-merge (section 1). In
|
|
246
|
+
`on_blocker=report` mode this whole step is off-limits (diagnose-only): do not
|
|
247
|
+
merge, close, or delete anything — return `blocked:pending-auto-fix`.
|
|
200
248
|
|
|
201
249
|
## 3. Merge and verify it actually shipped (ancestry check)
|
|
202
250
|
|
|
@@ -220,6 +268,12 @@ failed drive-to-merge outcome, not a successful closeout.
|
|
|
220
268
|
Loop until one of:
|
|
221
269
|
|
|
222
270
|
- **`MERGED`** and the ancestry check passes → success.
|
|
271
|
+
- **`awaiting-human`** (`auto_merge=false` only) → success. The PR is `OPEN`,
|
|
272
|
+
required checks are green, the review gate is clear, and
|
|
273
|
+
`mergeable == MERGEABLE`, with auto-merge deliberately not enabled
|
|
274
|
+
(`gh pr view <pr> --json autoMergeRequest` shows `null`). Report the PR URL
|
|
275
|
+
and state — a human decides whether it merges. This is the intended outcome
|
|
276
|
+
of auto-merge-off mode, not a stall; do not keep looping for `MERGED`.
|
|
223
277
|
- **`CLOSED`** → report (PR was closed without merge).
|
|
224
278
|
- **Hard block needing a human**: an unresolvable conflict, a failing check that
|
|
225
279
|
needs design input, or genuine unresolved human objection (not a bot gate). Stop
|
|
@@ -14,6 +14,7 @@ Recognized optional hints:
|
|
|
14
14
|
- `target_branch=<branch>` or `base=<branch>` — intended PR base branch, used to decide whether a GitHub closing keyword is safe.
|
|
15
15
|
- `tracker_provider=<github|linear|jira|none>` — explicit provider when the ref shape is ambiguous.
|
|
16
16
|
- `pr_url=<url>` — live pull request URL, only needed when updating tracker backlinks from an existing PR context.
|
|
17
|
+
- `auto_merge=<true|false>` — whether the PR should merge automatically. Default `true` (existing behavior for every current caller). With `auto_merge=false`, skip step 5 entirely (never run `gh pr merge --auto`) and pass `auto_merge=false` through to the `drive-pr-to-merge` delegation in step 6 so the PR is driven to a clean, green, OPEN state and then left awaiting a human.
|
|
17
18
|
|
|
18
19
|
## Workflow
|
|
19
20
|
|
|
@@ -34,10 +35,10 @@ Recognized optional hints:
|
|
|
34
35
|
- Include native development linkage for the source work item when `work_item_ref` can be inferred from `$ARGUMENTS`, the current branch name, an existing PR body, or the issue/ticket context passed by the caller.
|
|
35
36
|
- After the PR exists, ensure the source work item has a backlink to the PR: invoke `lisa-tracker-sync` with the work item, milestone `pr-ready`, the live `pr_url`, and `tracker_provider` when known. This makes ticket -> PR linkage mandatory, not just a best-effort milestone comment.
|
|
36
37
|
- After the PR exists, re-resolve the live Pull Request node id and, when `github.projects.v2` is enabled, invoke `lisa-github-project-v2` with `operation: ensure-item` and `content_node_id: <pull-request-node-id>` so linked pull requests join the configured shared Project without replacing the PR as the durable review/merge surface.
|
|
37
|
-
5. **Auto-merge
|
|
38
|
+
5. **Auto-merge** (only when `auto_merge=true`, the default — with `auto_merge=false` skip this step entirely): Choose merge strategy by PR type:
|
|
38
39
|
- **Promotion PRs** (env → env, e.g. `dev` → `staging`): use `gh pr merge --auto --merge` (never squash). Squashing flattens the constituent `chore(release): X.Y.Z [skip ci]` commits into one commit titled with the PR title, stripping the `[skip ci]` markers and breaking the release workflow's promotion-detection regex — the destination branch then double-bumps its version. `--merge` keeps each `chore(release)` commit (and its `[skip ci]` marker) intact under a clean merge commit subject the workflow can recognize.
|
|
39
40
|
- **Feature PRs** (anything → `dev`): use `gh pr merge --auto --merge`.
|
|
40
|
-
6. **Drive to merge**: Opening the PR and enabling auto-merge is not terminal. Delegate the full mergeability loop to the `drive-pr-to-merge` skill — invoke it with the PR number and `merge_method=merge` (and `verify_commit=<pushed head sha>` for the ancestry check). That skill is the single source of truth for clearing every blocker: auto-merge with direct-merge fallback, `BEHIND` re-sync, conflict resolution, failing-check fixes, human + bot (CodeRabbit) review-comment handling with GraphQL thread resolution, stale `CHANGES_REQUESTED` dismissal, and post-merge ancestry verification. It runs inline and uses plain `gh`/`git` so Claude and Codex behave identically. Do not re-implement the loop here.
|
|
41
|
+
6. **Drive to merge**: Opening the PR and enabling auto-merge is not terminal. Delegate the full mergeability loop to the `drive-pr-to-merge` skill — invoke it with the PR number and `merge_method=merge` (and `verify_commit=<pushed head sha>` for the ancestry check). When the caller passed `auto_merge=false`, also pass `auto_merge=false` so the delegated loop drives the PR to green-and-open (`awaiting-human`) instead of merged — never merging it, even on repos that disallow auto-merge. That skill is the single source of truth for clearing every blocker: auto-merge with direct-merge fallback, `BEHIND` re-sync, conflict resolution, failing-check fixes, human + bot (CodeRabbit) review-comment handling with GraphQL thread resolution, stale `CHANGES_REQUESTED` dismissal, and post-merge ancestry verification. It runs inline and uses plain `gh`/`git` so Claude and Codex behave identically. Do not re-implement the loop here.
|
|
41
42
|
|
|
42
43
|
### Native Development Linkage
|
|
43
44
|
|
|
@@ -252,6 +252,10 @@ A blocker is active if it is open and has no cleared status label. Treat `status
|
|
|
252
252
|
|
|
253
253
|
#### 3b. Claim
|
|
254
254
|
|
|
255
|
+
**Rejection detection runs first — before the relabel below.** Per the vendor-neutral `rejection-detection` rule (cite the slug; do not restate its classification table), classify this item at the **top of 3b, BEFORE** the `$READY → $CLAIMED` relabel — after the relabel the current-lane signal is gone. Read the item's Label-Event History from `lisa-github-read-issue` (chronological `LabeledEvent` / `UnlabeledEvent` on the configured `$READY` label) and classify it `rejection-reclaim | forward-only | never-left-ready | unknown`. Lane names come from `.lisa.config.json` (`github.labels.build.*`), never hardcoded. A failing/absent history yields `unknown` and the claim proceeds — detection never blocks the build. Items carrying a learning marker (`[lisa-learning-drop]` / `[lisa-learning-pr]` / `[lisa-learning-upstream-handoff]`) or the `learning:needs-triage` label are never rejection triggers (no learning-about-learning). Carry the classification into the relabel and lifecycle below.
|
|
256
|
+
|
|
257
|
+
**On `rejection-reclaim`, reflect before re-implementing** (per `rejection-detection`): read the rejection evidence through the access layer — the issue comments posted after the backward transition (the QA rejection comment) and the review threads on the rejected PR via `lisa-github-read-issue` — assemble ONE candidate learning (rule, why, provenance linking the rejection comment + rejected PR, evidence links, scope hint, triggering issue, fingerprint `sll4-sha1(rule\ntriggering_issue)[:12]`), and route it to the `lisa-persist-learning` skill. If that skill is absent, record the candidate as a comment carrying a **visible prose line plus** the marker (a bare marker renders as an empty bubble) — `Recorded a candidate learning from this rejection (queued for the judgment gate): <one-line candidate rule>.` then `<!-- [lisa-rejection-candidate] key=<issue>-<transition-ts> -->` — and proceed. Dedupe on `<issue>-<backward-transition-timestamp>` — a second re-claim produces no duplicate. Unreadable/absent evidence → no candidate, still implement.
|
|
258
|
+
|
|
255
259
|
```bash
|
|
256
260
|
gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$CLAIMED"
|
|
257
261
|
# Assign to the authenticated user ONLY when the issue is currently unassigned (attributable claim;
|
|
@@ -274,7 +278,7 @@ After the claim succeeds, run the per-issue lifecycle defined by the `github-age
|
|
|
274
278
|
- `lisa-github-verify` — pre-flight quality gate, including the draft-then-block procedure on FAIL
|
|
275
279
|
- `lisa-ticket-triage` — analytical triage gate (a `BLOCKED` verdict stops the cycle with findings posted)
|
|
276
280
|
- Intent determination from the `type:` label
|
|
277
|
-
2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <org>/<repo>#<number>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic) — passing the full context bundle from the read step. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
|
|
281
|
+
2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <org>/<repo>#<number>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic) — passing the full context bundle from the read step. **When 3b classified this item `rejection-reclaim`, the context bundle passed to `lisa-implement` MUST include the rejection evidence summary** (what was rejected, the defect the QA comment named, the approach named as wrong) — reuse the evidence already read in 3b, do not fetch it twice — so the plan can address it per `rejection-detection`; absence of evidence never blocks. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
|
|
278
282
|
3. **Milestone sync and evidence** (`lisa-github-sync`, `lisa-github-evidence`) happen at the milestones the `github-agent` workflow defines, within the dispatched flow.
|
|
279
283
|
|
|
280
284
|
If you are somehow running this skill as a spawned teammate inside an existing team (nested misrouting — Intake keeps this chain in the lead session), do NOT run the lifecycle inline and do NOT spawn named peers. Return this payload to the lead so the lead session can run this Phase 3c in-session:
|
|
@@ -49,6 +49,8 @@ The team lead does NOT read the input directly. The first task on the team's pla
|
|
|
49
49
|
|
|
50
50
|
The input resolver is the only teammate that may be spawned before the Roster Decision exists. After it returns the resolved input, do not spawn any lifecycle, research, implementation, review, verification, or learning teammate until the Roster Decision has been recorded.
|
|
51
51
|
|
|
52
|
+
**Rejection evidence in the claim handoff.** When this flow was dispatched from a build-intake claim that classified the item as a `rejection-reclaim` (per the `rejection-detection` rule), the context bundle carries a **rejection evidence summary** (what was rejected, the defect the QA comment named, the approach named as wrong). The plan MUST explicitly address that rejection evidence and MUST NOT re-propose the specific approach the rejection named as wrong — a bounced item must come back fixed, not re-bounced. `lisa-implement` cannot fetch this itself (it never sees the claim); it consumes what the handoff carries. Absence of rejection evidence never blocks — plan and implement normally.
|
|
53
|
+
|
|
52
54
|
## Select the agent roster
|
|
53
55
|
|
|
54
56
|
Before spawning any teammate beyond the bounded input resolver, record a **Roster Decision** artifact. It must enumerate every agent or specialist type exposed by the current runtime's delegation tool and record one line per type:
|
|
@@ -196,6 +196,10 @@ This gate never blocks a legitimate flat Task/Bug: those have no open children a
|
|
|
196
196
|
|
|
197
197
|
#### 3b. Claim
|
|
198
198
|
|
|
199
|
+
**Rejection detection runs first — before the transition below.** Per the vendor-neutral `rejection-detection` rule (cite the slug; do not restate its classification table), classify this ticket at the **top of 3b, BEFORE** the `$READY → $CLAIMED` transition — after the transition the current-status signal is gone. Read the ticket's status changelog via `lisa-atlassian-access operation: changelog key: <TICKET>` and classify it `rejection-reclaim | forward-only | never-left-ready | unknown` (a `rejection-reclaim` is a changelog entry whose `to` is the configured `$READY` status following an earlier `review`/`done`-ward status). Status names come from `.lisa.config.json`, never hardcoded. A failing/absent changelog yields `unknown` and the claim proceeds — detection never blocks the build. Tickets carrying a learning marker (`[lisa-learning-drop]` / `[lisa-learning-pr]` / `[lisa-learning-upstream-handoff]`) or the `learning:needs-triage` label are never rejection triggers (no learning-about-learning). Carry the classification into the transition and lifecycle below.
|
|
200
|
+
|
|
201
|
+
**On `rejection-reclaim`, reflect before re-implementing** (per `rejection-detection`): read the rejection evidence through the access layer — the ticket comments posted after the backward transition (the QA rejection comment) via `lisa-atlassian-access operation: read-ticket` / `comment` reads and the review threads on the rejected PR — assemble ONE candidate learning (rule, why, provenance linking the rejection comment + rejected PR, evidence links, scope hint, triggering issue, fingerprint `sll4-sha1(rule\ntriggering_issue)[:12]`), and route it to the `lisa-persist-learning` skill. If that skill is absent, record the candidate via `lisa-atlassian-access operation: comment` as a comment carrying a **visible prose line plus** the marker (a bare marker renders as an empty bubble) — `Recorded a candidate learning from this rejection (queued for the judgment gate): <one-line candidate rule>.` then `<!-- [lisa-rejection-candidate] key=<issue>-<transition-ts> -->` — and proceed. Dedupe on `<issue>-<backward-transition-timestamp>` — a second re-claim produces no duplicate. Unreadable/absent evidence → no candidate, still implement.
|
|
202
|
+
|
|
199
203
|
Transition the ticket from `$READY` to `$CLAIMED` by invoking `lisa-atlassian-access` `operation: transition key: <TICKET> to: "$CLAIMED"`.
|
|
200
204
|
- **Assign to the authenticated user when the ticket is unassigned.** A claim must be attributable. If the ticket has no assignee, assign it to the authenticated account — prefer acli `--assignee @me` (resolves server-side to the authenticated user, which avoids the federated-`accountId` mis-assignment), or `write-ticket` with the `accountId` from the `/rest/api/3/myself` identity probe the access skill already documents. Leave an already-assigned ticket's assignee untouched — never reassign work that already has an owner.
|
|
201
205
|
- Post a `[claude-build-intake]` comment via `lisa-atlassian-access` `operation: comment key: <TICKET> body: "Claimed by Claude. Starting build."`
|
|
@@ -212,7 +216,7 @@ After the claim succeeds, run the per-ticket lifecycle defined by the `jira-agen
|
|
|
212
216
|
- `lisa-jira-verify` — pre-flight quality gate, including the draft-then-block procedure on FAIL
|
|
213
217
|
- `lisa-ticket-triage` — analytical triage gate (a `BLOCKED` verdict stops the cycle with findings posted)
|
|
214
218
|
- Intent determination from the issue type
|
|
215
|
-
2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <TICKET>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic) — passing the full context bundle from the read step. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
|
|
219
|
+
2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <TICKET>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic) — passing the full context bundle from the read step. **When 3b classified this ticket `rejection-reclaim`, the context bundle passed to `lisa-implement` MUST include the rejection evidence summary** (what was rejected, the defect the QA comment named, the approach named as wrong) — reuse the evidence already read in 3b, do not fetch it twice — so the plan can address it per `rejection-detection`; absence of evidence never blocks. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
|
|
216
220
|
3. **Milestone sync and evidence** (`lisa-jira-sync`, `lisa-jira-evidence`) happen at the milestones the `jira-agent` workflow defines, within the dispatched flow.
|
|
217
221
|
|
|
218
222
|
If you are somehow running this skill as a spawned teammate inside an existing team (nested misrouting — Intake keeps this chain in the lead session), do NOT run the lifecycle inline and do NOT spawn named peers. Return this payload to the lead so the lead session can run this Phase 3c in-session:
|
|
@@ -23,6 +23,7 @@ operation: get-issue id:<ID>
|
|
|
23
23
|
operation: save-issue payload:{...}
|
|
24
24
|
operation: list-comments issue_id:<ID>
|
|
25
25
|
operation: save-comment issue_id:<ID> body:"..."
|
|
26
|
+
operation: history id:<ID>
|
|
26
27
|
operation: list-issue-labels [team:<ID>]
|
|
27
28
|
operation: create-issue-label payload:{...}
|
|
28
29
|
operation: list-project-labels
|
|
@@ -81,6 +82,59 @@ linear_graphql() {
|
|
|
81
82
|
Map operation names to Linear GraphQL queries/mutations in this access skill.
|
|
82
83
|
Consumers pass business-shaped arguments only; they do not embed GraphQL.
|
|
83
84
|
|
|
85
|
+
## `history` — transition history (read-only)
|
|
86
|
+
|
|
87
|
+
`history id:<ID>` returns an Issue's ordered past state changes — the raw
|
|
88
|
+
material for rejection detection (an Issue that reached a `review`/`done`-ward
|
|
89
|
+
state and is now back in `ready`). `IssueHistory` is reachable today through the
|
|
90
|
+
existing `linear_graphql` adapter but was **not** in the documented contract; an
|
|
91
|
+
undocumented-but-reachable capability is not exposed, so it now appears in the
|
|
92
|
+
Invocation Contract above. Reuse the existing adapter — this is a
|
|
93
|
+
contract/surface change, not a new transport (the `integration-access-layer`
|
|
94
|
+
rule forbids consumers from reaching around the layer).
|
|
95
|
+
|
|
96
|
+
Query through `linear_graphql` (oldest→newest; page `history(first:…, after:…)`
|
|
97
|
+
via `pageInfo` for busy Issues so history never silently truncates):
|
|
98
|
+
|
|
99
|
+
```graphql
|
|
100
|
+
query($id:String!){
|
|
101
|
+
issue(id:$id){
|
|
102
|
+
history(first:100){
|
|
103
|
+
pageInfo{hasNextPage endCursor}
|
|
104
|
+
nodes{
|
|
105
|
+
createdAt
|
|
106
|
+
fromState{name type}
|
|
107
|
+
toState{name type}
|
|
108
|
+
actor{name}
|
|
109
|
+
addedLabelIds
|
|
110
|
+
removedLabelIds
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- **Shape.** For each node emit `{ from, to, when, who }` — `fromState.name` →
|
|
118
|
+
`toState.name`, `createdAt` (ISO timestamp), `actor.name`. Nodes with no
|
|
119
|
+
`fromState`/`toState` are non-state edits (label-only, assignee, etc.); keep
|
|
120
|
+
them for the label stream, skip them for workflow-state ordering.
|
|
121
|
+
- **Label history (honest caveat).** Linear's build lanes are **label-driven**
|
|
122
|
+
(`lisa-linear-build-intake` keys the queue on `status:*` labels), so label
|
|
123
|
+
moves matter as much as workflow-state moves. `IssueHistory` carries label
|
|
124
|
+
changes as `addedLabelIds` / `removedLabelIds` — arrays of label **IDs**, not
|
|
125
|
+
names. It does **not** inline label names, and it does not carry the label's
|
|
126
|
+
full prior/next set — only the per-event deltas. Resolve IDs → names by
|
|
127
|
+
cross-referencing `list-issue-labels`. Do not overclaim: a caller that needs
|
|
128
|
+
`status:*` label transitions reconstructs them from the ID deltas plus the
|
|
129
|
+
label catalog, not from an inline name on the history node.
|
|
130
|
+
- **Empty is valid.** An Issue that never changed state returns an **empty**
|
|
131
|
+
history — an empty history is a valid result, not an error.
|
|
132
|
+
- **Graceful degrade — never block the build.** A failed history fetch returns
|
|
133
|
+
the layer's `Error:` result. Callers MUST treat that as **unknown** history
|
|
134
|
+
and proceed — a history read failure never blocks the build. MCP cannot reach
|
|
135
|
+
`IssueHistory`, so the `history` operation resolves only through the
|
|
136
|
+
`LINEAR_API_KEY` GraphQL substrate; without it, the result is unknown.
|
|
137
|
+
|
|
84
138
|
## Invariants
|
|
85
139
|
|
|
86
140
|
- MCP is preferred when it is present and already authenticated.
|
|
@@ -186,6 +186,10 @@ This gate never blocks a legitimate flat Task/Bug: those have no open children a
|
|
|
186
186
|
|
|
187
187
|
#### 3b. Claim
|
|
188
188
|
|
|
189
|
+
**Rejection detection runs first — before the relabel below.** Per the vendor-neutral `rejection-detection` rule (cite the slug; do not restate its classification table), classify this Issue at the **top of 3b, BEFORE** the `$READY → $CLAIMED` relabel — after the relabel the current-lane signal is gone. Read the Issue's history via `lisa-linear-access operation: history id: <ISSUE-ID>`, keyed on `status:*` **label** history (Linear build lanes are label-driven; resolve `addedLabelIds`/`removedLabelIds` against `list-issue-labels`), and classify it `rejection-reclaim | forward-only | never-left-ready | unknown` (a `rejection-reclaim` is the configured `$READY` label re-added after a later-lane label). Label names come from `.lisa.config.json`, never hardcoded. A failing/absent history yields `unknown` and the claim proceeds — detection never blocks the build. Issues carrying a learning marker (`[lisa-learning-drop]` / `[lisa-learning-pr]` / `[lisa-learning-upstream-handoff]`) or the `learning:needs-triage` label are never rejection triggers (no learning-about-learning). Carry the classification into the relabel and lifecycle below.
|
|
190
|
+
|
|
191
|
+
**On `rejection-reclaim`, reflect before re-implementing** (per `rejection-detection`): read the rejection evidence through the access layer — the Issue comments posted after the backward transition (the QA rejection comment) via `lisa-linear-access operation: list-comments` and the review threads on the rejected PR — assemble ONE candidate learning (rule, why, provenance linking the rejection comment + rejected PR, evidence links, scope hint, triggering issue, fingerprint `sll4-sha1(rule\ntriggering_issue)[:12]`), and route it to the `lisa-persist-learning` skill. If that skill is absent, record the candidate via `lisa-linear-access operation: save-comment` as a comment carrying a **visible prose line plus** the marker (a bare marker renders as an empty bubble) — `Recorded a candidate learning from this rejection (queued for the judgment gate): <one-line candidate rule>.` then `<!-- [lisa-rejection-candidate] key=<issue>-<transition-ts> -->` — and proceed. Dedupe on `<issue>-<backward-transition-timestamp>` — a second re-claim produces no duplicate. Unreadable/absent evidence → no candidate, still implement.
|
|
192
|
+
|
|
189
193
|
Update labels via `lisa-linear-access operation: save-issue`: remove `$READY`, add `$CLAIMED`. Resolve label IDs via `list_issue_labels` (create `$CLAIMED` if missing).
|
|
190
194
|
|
|
191
195
|
**Assign to the authenticated user when the Issue is unassigned.** A claim must be attributable. If the Issue has no assignee, set its `assigneeId` to the authenticated viewer (resolve the viewer's id via the Linear MCP identity — e.g. `get_user` for the current actor) through `lisa-linear-access operation: save-issue`. Leave an already-assigned Issue's assignee untouched — never reassign work that already has an owner.
|
|
@@ -205,7 +209,7 @@ After the claim succeeds, run the per-Issue lifecycle defined by the `linear-age
|
|
|
205
209
|
- `lisa-linear-verify` — pre-flight quality gate, including the draft-then-block procedure on FAIL
|
|
206
210
|
- `lisa-ticket-triage` — analytical triage gate (a `BLOCKED` verdict stops the cycle with findings posted)
|
|
207
211
|
- Intent determination from the type label
|
|
208
|
-
2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <ISSUE-ID>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic-equivalent) — passing the full context bundle from the read step. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
|
|
212
|
+
2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <ISSUE-ID>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic-equivalent) — passing the full context bundle from the read step. **When 3b classified this Issue `rejection-reclaim`, the context bundle passed to `lisa-implement` MUST include the rejection evidence summary** (what was rejected, the defect the QA comment named, the approach named as wrong) — reuse the evidence already read in 3b, do not fetch it twice — so the plan can address it per `rejection-detection`; absence of evidence never blocks. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
|
|
209
213
|
3. **Milestone sync and evidence** (`lisa-linear-sync`, `lisa-linear-evidence`) happen at the milestones the `linear-agent` workflow defines, within the dispatched flow.
|
|
210
214
|
|
|
211
215
|
If you are somehow running this skill as a spawned teammate inside an existing team (nested misrouting — Intake keeps this chain in the lead session), do NOT run the lifecycle inline and do NOT spawn named peers. Return this payload to the lead so the lead session can run this Phase 3c in-session:
|