@codyswann/lisa 2.158.3 → 2.159.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.
Files changed (59) hide show
  1. package/dist/migrations/ensure-wiki-source-declared.d.ts +37 -0
  2. package/dist/migrations/ensure-wiki-source-declared.d.ts.map +1 -0
  3. package/dist/migrations/ensure-wiki-source-declared.js +86 -0
  4. package/dist/migrations/ensure-wiki-source-declared.js.map +1 -0
  5. package/dist/migrations/index.d.ts +1 -0
  6. package/dist/migrations/index.d.ts.map +1 -1
  7. package/dist/migrations/index.js +3 -0
  8. package/dist/migrations/index.js.map +1 -1
  9. package/package.json +1 -1
  10. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  11. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  12. package/plugins/lisa/skills/atlassian-access/SKILL.md +23 -9
  13. package/plugins/lisa-agy/plugin.json +1 -1
  14. package/plugins/lisa-agy/skills/atlassian-access/SKILL.md +23 -9
  15. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  18. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-copilot/skills/atlassian-access/SKILL.md +23 -9
  22. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-cursor/skills/atlassian-access/SKILL.md +23 -9
  24. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  26. package/plugins/lisa-expo-agy/plugin.json +1 -1
  27. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  36. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  37. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  41. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  42. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-rails-agy/plugin.json +1 -1
  47. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  52. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  57. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/src/base/skills/atlassian-access/SKILL.md +23 -9
@@ -0,0 +1,37 @@
1
+ import type { Migration, MigrationContext, MigrationResult } from "./migration.interface.js";
2
+ /**
3
+ * Migration: when a project carries a local LLM Wiki (`wiki/lisa-wiki.config.json`
4
+ * exists) but its `.lisa.config.json` does not declare `wiki.source`, write the
5
+ * explicit default pointer `wiki.source.path = <wikiRoot>` (the path the wiki's
6
+ * own config reports, default `wiki`).
7
+ *
8
+ * Resolving the wiki is implicit local mode without this — the declaration just
9
+ * makes "this project has a wiki here" self-documenting in the project config,
10
+ * and is the consumer-side hook the remote-wiki story builds on. Idempotent:
11
+ * skips when `wiki.source` already exists, preserves all other config keys and
12
+ * any sibling `wiki` keys. Creates `.lisa.config.json` if absent (the project is
13
+ * already Lisa-managed by virtue of carrying a lisa-wiki).
14
+ */
15
+ export declare class EnsureWikiSourceDeclaredMigration implements Migration {
16
+ readonly name = "ensure-wiki-source-declared";
17
+ readonly description = "Declare wiki.source.path in .lisa.config.json when the project has a local wiki";
18
+ /**
19
+ * Gather the config + wiki root, or null when the project has no local wiki.
20
+ * @param projectDir - Destination project directory
21
+ * @returns Resolved state, or null when there is no local lisa-wiki
22
+ */
23
+ private readState;
24
+ /**
25
+ * Applies when a local wiki exists and `wiki.source` is not yet declared.
26
+ * @param ctx - Migration context
27
+ * @returns True when there is work to do
28
+ */
29
+ applies(ctx: MigrationContext): Promise<boolean>;
30
+ /**
31
+ * Write `wiki.source.path` into `.lisa.config.json`, preserving existing keys.
32
+ * @param ctx - Migration context
33
+ * @returns Result describing the action taken
34
+ */
35
+ apply(ctx: MigrationContext): Promise<MigrationResult>;
36
+ }
37
+ //# sourceMappingURL=ensure-wiki-source-declared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-wiki-source-declared.d.ts","sourceRoot":"","sources":["../../src/migrations/ensure-wiki-source-declared.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAuBlC;;;;;;;;;;;;GAYG;AACH,qBAAa,iCAAkC,YAAW,SAAS;IACjE,QAAQ,CAAC,IAAI,iCAAiC;IAC9C,QAAQ,CAAC,WAAW,qFACgE;IAEpF;;;;OAIG;YACW,SAAS;IAevB;;;;OAIG;IACG,OAAO,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAKtD;;;;OAIG;IACG,KAAK,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;CA+B7D"}
@@ -0,0 +1,86 @@
1
+ import * as path from "node:path";
2
+ import * as fse from "fs-extra";
3
+ import { readJsonOrNull, writeJson } from "../utils/json-utils.js";
4
+ const LISA_CONFIG = ".lisa.config.json";
5
+ const WIKI_CONFIG = path.join("wiki", "lisa-wiki.config.json");
6
+ const DEFAULT_WIKI_ROOT = "wiki";
7
+ /**
8
+ * Migration: when a project carries a local LLM Wiki (`wiki/lisa-wiki.config.json`
9
+ * exists) but its `.lisa.config.json` does not declare `wiki.source`, write the
10
+ * explicit default pointer `wiki.source.path = <wikiRoot>` (the path the wiki's
11
+ * own config reports, default `wiki`).
12
+ *
13
+ * Resolving the wiki is implicit local mode without this — the declaration just
14
+ * makes "this project has a wiki here" self-documenting in the project config,
15
+ * and is the consumer-side hook the remote-wiki story builds on. Idempotent:
16
+ * skips when `wiki.source` already exists, preserves all other config keys and
17
+ * any sibling `wiki` keys. Creates `.lisa.config.json` if absent (the project is
18
+ * already Lisa-managed by virtue of carrying a lisa-wiki).
19
+ */
20
+ export class EnsureWikiSourceDeclaredMigration {
21
+ name = "ensure-wiki-source-declared";
22
+ description = "Declare wiki.source.path in .lisa.config.json when the project has a local wiki";
23
+ /**
24
+ * Gather the config + wiki root, or null when the project has no local wiki.
25
+ * @param projectDir - Destination project directory
26
+ * @returns Resolved state, or null when there is no local lisa-wiki
27
+ */
28
+ async readState(projectDir) {
29
+ const wikiCfgPath = path.join(projectDir, WIKI_CONFIG);
30
+ if (!(await fse.pathExists(wikiCfgPath))) {
31
+ return null;
32
+ }
33
+ const wikiCfg = await readJsonOrNull(wikiCfgPath);
34
+ const configPath = path.join(projectDir, LISA_CONFIG);
35
+ const config = await readJsonOrNull(configPath);
36
+ return {
37
+ configPath,
38
+ config,
39
+ wikiRoot: wikiCfg?.wikiRoot ?? DEFAULT_WIKI_ROOT,
40
+ };
41
+ }
42
+ /**
43
+ * Applies when a local wiki exists and `wiki.source` is not yet declared.
44
+ * @param ctx - Migration context
45
+ * @returns True when there is work to do
46
+ */
47
+ async applies(ctx) {
48
+ const state = await this.readState(ctx.projectDir);
49
+ return state !== null && state.config?.wiki?.source === undefined;
50
+ }
51
+ /**
52
+ * Write `wiki.source.path` into `.lisa.config.json`, preserving existing keys.
53
+ * @param ctx - Migration context
54
+ * @returns Result describing the action taken
55
+ */
56
+ async apply(ctx) {
57
+ const state = await this.readState(ctx.projectDir);
58
+ if (state === null || state.config?.wiki?.source !== undefined) {
59
+ return { name: this.name, action: "noop" };
60
+ }
61
+ const { configPath, config, wikiRoot } = state;
62
+ const merged = {
63
+ ...(config ?? {}),
64
+ wiki: { ...(config?.wiki ?? {}), source: { path: wikiRoot } },
65
+ };
66
+ const message = `Declared wiki.source.path="${wikiRoot}" in ${LISA_CONFIG}`;
67
+ if (ctx.dryRun) {
68
+ ctx.logger.dry(`Would declare wiki.source.path="${wikiRoot}"`);
69
+ return {
70
+ name: this.name,
71
+ action: "applied",
72
+ changedFiles: [LISA_CONFIG],
73
+ message,
74
+ };
75
+ }
76
+ await writeJson(configPath, merged);
77
+ ctx.logger.success(message);
78
+ return {
79
+ name: this.name,
80
+ action: "applied",
81
+ changedFiles: [LISA_CONFIG],
82
+ message,
83
+ };
84
+ }
85
+ }
86
+ //# sourceMappingURL=ensure-wiki-source-declared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-wiki-source-declared.js","sourceRoot":"","sources":["../../src/migrations/ensure-wiki-source-declared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAOnE,MAAM,WAAW,GAAG,mBAAmB,CAAC;AACxC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;AAC/D,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAmBjC;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,iCAAiC;IACnC,IAAI,GAAG,6BAA6B,CAAC;IACrC,WAAW,GAClB,iFAAiF,CAAC;IAEpF;;;;OAIG;IACK,KAAK,CAAC,SAAS,CAAC,UAAkB;QACxC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACvD,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,cAAc,CAAwB,WAAW,CAAC,CAAC;QACzE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAa,UAAU,CAAC,CAAC;QAC5D,OAAO;YACL,UAAU;YACV,MAAM;YACN,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,iBAAiB;SACjD,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,GAAqB;QACjC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACnD,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC;IACpE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAC,GAAqB;QAC/B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YAC/D,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAC7C,CAAC;QACD,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;QAC/C,MAAM,MAAM,GAAG;YACb,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;YACjB,IAAI,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;SAC9D,CAAC;QAEF,MAAM,OAAO,GAAG,8BAA8B,QAAQ,QAAQ,WAAW,EAAE,CAAC;QAC5E,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,mCAAmC,QAAQ,GAAG,CAAC,CAAC;YAC/D,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,SAAS;gBACjB,YAAY,EAAE,CAAC,WAAW,CAAC;gBAC3B,OAAO;aACR,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACpC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC5B,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,SAAS;YACjB,YAAY,EAAE,CAAC,WAAW,CAAC;YAC3B,OAAO;SACR,CAAC;IACJ,CAAC;CACF"}
@@ -5,6 +5,7 @@ export { EnsureJestRnMockAccessibilityManagerMigration } from "./ensure-jest-rn-
5
5
  export { EnsureLisaPostinstallMigration } from "./ensure-lisa-postinstall.js";
6
6
  export { EnsureSonarExcludesLisaHarnessMigration } from "./ensure-sonar-excludes-lisa-harness.js";
7
7
  export { EnsureTsconfigLocalFilesFallbackMigration } from "./ensure-tsconfig-local-files-fallback.js";
8
+ export { EnsureWikiSourceDeclaredMigration } from "./ensure-wiki-source-declared.js";
8
9
  export { EnsureTsconfigLocalIncludesMigration } from "./ensure-tsconfig-local-includes.js";
9
10
  export { ReconcileClaudeStackPluginsMigration } from "./reconcile-claude-stack-plugins.js";
10
11
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAE3F;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAElD;;;OAGG;gBACS,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE;IAY7C;;;OAGG;IACH,MAAM,IAAI,SAAS,SAAS,EAAE;IAI9B;;;;OAIG;IACG,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;CAazE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAE3F;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAElD;;;OAGG;gBACS,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE;IAa7C;;;OAGG;IACH,MAAM,IAAI,SAAS,SAAS,EAAE;IAI9B;;;;OAIG;IACG,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;CAazE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D"}
@@ -3,6 +3,7 @@ import { EnsureJestRnMockAccessibilityManagerMigration } from "./ensure-jest-rn-
3
3
  import { EnsureLisaPostinstallMigration } from "./ensure-lisa-postinstall.js";
4
4
  import { EnsureSonarExcludesLisaHarnessMigration } from "./ensure-sonar-excludes-lisa-harness.js";
5
5
  import { EnsureTsconfigLocalFilesFallbackMigration } from "./ensure-tsconfig-local-files-fallback.js";
6
+ import { EnsureWikiSourceDeclaredMigration } from "./ensure-wiki-source-declared.js";
6
7
  import { EnsureTsconfigLocalIncludesMigration } from "./ensure-tsconfig-local-includes.js";
7
8
  import { ReconcileClaudeStackPluginsMigration } from "./reconcile-claude-stack-plugins.js";
8
9
  export { EnsureAuditIgnoreLocalExclusionsMigration } from "./ensure-audit-ignore-local-exclusions.js";
@@ -10,6 +11,7 @@ export { EnsureJestRnMockAccessibilityManagerMigration } from "./ensure-jest-rn-
10
11
  export { EnsureLisaPostinstallMigration } from "./ensure-lisa-postinstall.js";
11
12
  export { EnsureSonarExcludesLisaHarnessMigration } from "./ensure-sonar-excludes-lisa-harness.js";
12
13
  export { EnsureTsconfigLocalFilesFallbackMigration } from "./ensure-tsconfig-local-files-fallback.js";
14
+ export { EnsureWikiSourceDeclaredMigration } from "./ensure-wiki-source-declared.js";
13
15
  export { EnsureTsconfigLocalIncludesMigration } from "./ensure-tsconfig-local-includes.js";
14
16
  export { ReconcileClaudeStackPluginsMigration } from "./reconcile-claude-stack-plugins.js";
15
17
  /**
@@ -29,6 +31,7 @@ export class MigrationRegistry {
29
31
  new EnsureJestRnMockAccessibilityManagerMigration(),
30
32
  new EnsureLisaPostinstallMigration(),
31
33
  new EnsureSonarExcludesLisaHarnessMigration(),
34
+ new EnsureWikiSourceDeclaredMigration(),
32
35
  new ReconcileClaudeStackPluginsMigration(),
33
36
  ];
34
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAa3F,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAE3F;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACX,UAAU,CAAuB;IAElD;;;OAGG;IACH,YAAY,UAAiC;QAC3C,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI;YAC9B,IAAI,oCAAoC,EAAE;YAC1C,IAAI,yCAAyC,EAAE;YAC/C,IAAI,yCAAyC,EAAE;YAC/C,IAAI,6CAA6C,EAAE;YACnD,IAAI,8BAA8B,EAAE;YACpC,IAAI,uCAAuC,EAAE;YAC7C,IAAI,oCAAoC,EAAE;SAC3C,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,mBAAmB,CAAC,GAAqB;QAC7C,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,SAAS,CAAC,gBAAgB,EAAE,CAAC;gBAC/B,MAAM,SAAS,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,GAAqB;QAChC,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC/C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC1D,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,IAAI,iBAAiB,EAAE,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAa3F,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,6CAA6C,EAAE,MAAM,gDAAgD,CAAC;AAC/G,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,uCAAuC,EAAE,MAAM,yCAAyC,CAAC;AAClG,OAAO,EAAE,yCAAyC,EAAE,MAAM,2CAA2C,CAAC;AACtG,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAC3F,OAAO,EAAE,oCAAoC,EAAE,MAAM,qCAAqC,CAAC;AAE3F;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACX,UAAU,CAAuB;IAElD;;;OAGG;IACH,YAAY,UAAiC;QAC3C,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI;YAC9B,IAAI,oCAAoC,EAAE;YAC1C,IAAI,yCAAyC,EAAE;YAC/C,IAAI,yCAAyC,EAAE;YAC/C,IAAI,6CAA6C,EAAE;YACnD,IAAI,8BAA8B,EAAE;YACpC,IAAI,uCAAuC,EAAE;YAC7C,IAAI,iCAAiC,EAAE;YACvC,IAAI,oCAAoC,EAAE;SAC3C,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,mBAAmB,CAAC,GAAqB;QAC7C,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,IAAI,SAAS,CAAC,gBAAgB,EAAE,CAAC;gBAC/B,MAAM,SAAS,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,GAAqB;QAChC,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC/C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC1D,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,IAAI,iBAAiB,EAAE,CAAC;AACjC,CAAC"}
package/package.json CHANGED
@@ -84,7 +84,7 @@
84
84
  "lodash": ">=4.18.1"
85
85
  },
86
86
  "name": "@codyswann/lisa",
87
- "version": "2.158.3",
87
+ "version": "2.159.1",
88
88
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
89
89
  "main": "dist/index.js",
90
90
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: atlassian-access
3
- description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and its active profile matches the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are skipped, not used."
3
+ description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and switchable to a profile matching the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, and skipped only after switch plus re-verification fails."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -35,7 +35,7 @@ EMAIL=$(jq -r '.atlassian.email // empty' .lisa.config.local.json 2>/dev/null)
35
35
  [ -z "$CLOUDID" ] && { echo "Error: atlassian.cloudId not set. Run /lisa:setup:atlassian." >&2; exit 1; }
36
36
  ```
37
37
 
38
- Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are skipped, not used.
38
+ Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, then skipped only if the switch fails or re-verification still mismatches.
39
39
 
40
40
  ```bash
41
41
  substrate=""
@@ -43,13 +43,13 @@ substrate=""
43
43
  # Tier 1: acli
44
44
  if command -v acli >/dev/null 2>&1 && acli auth status >/dev/null 2>&1; then
45
45
  current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
46
+ if [ "$current_site" != "$SITE" ]; then
47
+ # acli installed but pointing at a different site. Try switching profiles.
48
+ acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1 || true
49
+ current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
50
+ fi
46
51
  if [ "$current_site" = "$SITE" ]; then
47
52
  substrate="acli"
48
- else
49
- # acli installed but pointing at a different site. Try switching profiles.
50
- if acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1; then
51
- substrate="acli"
52
- fi
53
53
  fi
54
54
  fi
55
55
 
@@ -164,7 +164,7 @@ Operation dispatch then uses `$substrate` for the primary route. If the operatio
164
164
 
165
165
  ### Step 2 — Connection-match check
166
166
 
167
- The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already verifies this implicitly (substrates that don't match are skipped). This step is the explicit assertion before any operation runs — defensive in case the substrate state changed since selection.
167
+ The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already tries to switch mismatched acli profiles and verifies the result before selection. This step repeats the assertion before any operation runs — defensive in case the substrate state changed since selection.
168
168
 
169
169
  Read configured site:
170
170
 
@@ -188,8 +188,22 @@ current_site=$(echo "$current" | jq -r '.site // empty')
188
188
  current_email=$(echo "$current" | jq -r '.email // empty')
189
189
 
190
190
  if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
191
- # Profile mismatch — switch.
191
+ # Profile mismatch — switch, then re-verify. Do not trust the switch exit
192
+ # status alone because acli's active account is machine-global state.
192
193
  acli auth switch --site "$site" ${email:+--email "$email"}
194
+ current=$(acli auth status --json 2>/dev/null)
195
+ current_site=$(echo "$current" | jq -r '.site // empty')
196
+ current_email=$(echo "$current" | jq -r '.email // empty')
197
+ fi
198
+
199
+ if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
200
+ echo "Error: acli active site is '$current_site', but .lisa.config.json requires '$site'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
201
+ exit 1
202
+ fi
203
+
204
+ if [ -n "$email" ] && [ -n "$current_email" ] && [ "$current_email" != "$email" ]; then
205
+ echo "Error: acli active account is '$current_email', but .lisa.config.json requires '$email'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
206
+ exit 1
193
207
  fi
194
208
  ```
195
209
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: atlassian-access
3
- description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and its active profile matches the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are skipped, not used."
3
+ description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and switchable to a profile matching the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, and skipped only after switch plus re-verification fails."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -35,7 +35,7 @@ EMAIL=$(jq -r '.atlassian.email // empty' .lisa.config.local.json 2>/dev/null)
35
35
  [ -z "$CLOUDID" ] && { echo "Error: atlassian.cloudId not set. Run /lisa:setup:atlassian." >&2; exit 1; }
36
36
  ```
37
37
 
38
- Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are skipped, not used.
38
+ Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, then skipped only if the switch fails or re-verification still mismatches.
39
39
 
40
40
  ```bash
41
41
  substrate=""
@@ -43,13 +43,13 @@ substrate=""
43
43
  # Tier 1: acli
44
44
  if command -v acli >/dev/null 2>&1 && acli auth status >/dev/null 2>&1; then
45
45
  current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
46
+ if [ "$current_site" != "$SITE" ]; then
47
+ # acli installed but pointing at a different site. Try switching profiles.
48
+ acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1 || true
49
+ current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
50
+ fi
46
51
  if [ "$current_site" = "$SITE" ]; then
47
52
  substrate="acli"
48
- else
49
- # acli installed but pointing at a different site. Try switching profiles.
50
- if acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1; then
51
- substrate="acli"
52
- fi
53
53
  fi
54
54
  fi
55
55
 
@@ -164,7 +164,7 @@ Operation dispatch then uses `$substrate` for the primary route. If the operatio
164
164
 
165
165
  ### Step 2 — Connection-match check
166
166
 
167
- The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already verifies this implicitly (substrates that don't match are skipped). This step is the explicit assertion before any operation runs — defensive in case the substrate state changed since selection.
167
+ The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already tries to switch mismatched acli profiles and verifies the result before selection. This step repeats the assertion before any operation runs — defensive in case the substrate state changed since selection.
168
168
 
169
169
  Read configured site:
170
170
 
@@ -188,8 +188,22 @@ current_site=$(echo "$current" | jq -r '.site // empty')
188
188
  current_email=$(echo "$current" | jq -r '.email // empty')
189
189
 
190
190
  if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
191
- # Profile mismatch — switch.
191
+ # Profile mismatch — switch, then re-verify. Do not trust the switch exit
192
+ # status alone because acli's active account is machine-global state.
192
193
  acli auth switch --site "$site" ${email:+--email "$email"}
194
+ current=$(acli auth status --json 2>/dev/null)
195
+ current_site=$(echo "$current" | jq -r '.site // empty')
196
+ current_email=$(echo "$current" | jq -r '.email // empty')
197
+ fi
198
+
199
+ if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
200
+ echo "Error: acli active site is '$current_site', but .lisa.config.json requires '$site'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
201
+ exit 1
202
+ fi
203
+
204
+ if [ -n "$email" ] && [ -n "$current_email" ] && [ "$current_email" != "$email" ]; then
205
+ echo "Error: acli active account is '$current_email', but .lisa.config.json requires '$email'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
206
+ exit 1
193
207
  fi
194
208
  ```
195
209
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: atlassian-access
3
- description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and its active profile matches the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are skipped, not used."
3
+ description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and switchable to a profile matching the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, and skipped only after switch plus re-verification fails."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -35,7 +35,7 @@ EMAIL=$(jq -r '.atlassian.email // empty' .lisa.config.local.json 2>/dev/null)
35
35
  [ -z "$CLOUDID" ] && { echo "Error: atlassian.cloudId not set. Run /lisa:setup:atlassian." >&2; exit 1; }
36
36
  ```
37
37
 
38
- Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are skipped, not used.
38
+ Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, then skipped only if the switch fails or re-verification still mismatches.
39
39
 
40
40
  ```bash
41
41
  substrate=""
@@ -43,13 +43,13 @@ substrate=""
43
43
  # Tier 1: acli
44
44
  if command -v acli >/dev/null 2>&1 && acli auth status >/dev/null 2>&1; then
45
45
  current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
46
+ if [ "$current_site" != "$SITE" ]; then
47
+ # acli installed but pointing at a different site. Try switching profiles.
48
+ acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1 || true
49
+ current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
50
+ fi
46
51
  if [ "$current_site" = "$SITE" ]; then
47
52
  substrate="acli"
48
- else
49
- # acli installed but pointing at a different site. Try switching profiles.
50
- if acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1; then
51
- substrate="acli"
52
- fi
53
53
  fi
54
54
  fi
55
55
 
@@ -164,7 +164,7 @@ Operation dispatch then uses `$substrate` for the primary route. If the operatio
164
164
 
165
165
  ### Step 2 — Connection-match check
166
166
 
167
- The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already verifies this implicitly (substrates that don't match are skipped). This step is the explicit assertion before any operation runs — defensive in case the substrate state changed since selection.
167
+ The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already tries to switch mismatched acli profiles and verifies the result before selection. This step repeats the assertion before any operation runs — defensive in case the substrate state changed since selection.
168
168
 
169
169
  Read configured site:
170
170
 
@@ -188,8 +188,22 @@ current_site=$(echo "$current" | jq -r '.site // empty')
188
188
  current_email=$(echo "$current" | jq -r '.email // empty')
189
189
 
190
190
  if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
191
- # Profile mismatch — switch.
191
+ # Profile mismatch — switch, then re-verify. Do not trust the switch exit
192
+ # status alone because acli's active account is machine-global state.
192
193
  acli auth switch --site "$site" ${email:+--email "$email"}
194
+ current=$(acli auth status --json 2>/dev/null)
195
+ current_site=$(echo "$current" | jq -r '.site // empty')
196
+ current_email=$(echo "$current" | jq -r '.email // empty')
197
+ fi
198
+
199
+ if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
200
+ echo "Error: acli active site is '$current_site', but .lisa.config.json requires '$site'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
201
+ exit 1
202
+ fi
203
+
204
+ if [ -n "$email" ] && [ -n "$current_email" ] && [ "$current_email" != "$email" ]; then
205
+ echo "Error: acli active account is '$current_email', but .lisa.config.json requires '$email'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
206
+ exit 1
193
207
  fi
194
208
  ```
195
209
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: atlassian-access
3
- description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and its active profile matches the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are skipped, not used."
3
+ description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and switchable to a profile matching the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, and skipped only after switch plus re-verification fails."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -35,7 +35,7 @@ EMAIL=$(jq -r '.atlassian.email // empty' .lisa.config.local.json 2>/dev/null)
35
35
  [ -z "$CLOUDID" ] && { echo "Error: atlassian.cloudId not set. Run /lisa:setup:atlassian." >&2; exit 1; }
36
36
  ```
37
37
 
38
- Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are skipped, not used.
38
+ Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, then skipped only if the switch fails or re-verification still mismatches.
39
39
 
40
40
  ```bash
41
41
  substrate=""
@@ -43,13 +43,13 @@ substrate=""
43
43
  # Tier 1: acli
44
44
  if command -v acli >/dev/null 2>&1 && acli auth status >/dev/null 2>&1; then
45
45
  current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
46
+ if [ "$current_site" != "$SITE" ]; then
47
+ # acli installed but pointing at a different site. Try switching profiles.
48
+ acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1 || true
49
+ current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
50
+ fi
46
51
  if [ "$current_site" = "$SITE" ]; then
47
52
  substrate="acli"
48
- else
49
- # acli installed but pointing at a different site. Try switching profiles.
50
- if acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1; then
51
- substrate="acli"
52
- fi
53
53
  fi
54
54
  fi
55
55
 
@@ -164,7 +164,7 @@ Operation dispatch then uses `$substrate` for the primary route. If the operatio
164
164
 
165
165
  ### Step 2 — Connection-match check
166
166
 
167
- The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already verifies this implicitly (substrates that don't match are skipped). This step is the explicit assertion before any operation runs — defensive in case the substrate state changed since selection.
167
+ The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already tries to switch mismatched acli profiles and verifies the result before selection. This step repeats the assertion before any operation runs — defensive in case the substrate state changed since selection.
168
168
 
169
169
  Read configured site:
170
170
 
@@ -188,8 +188,22 @@ current_site=$(echo "$current" | jq -r '.site // empty')
188
188
  current_email=$(echo "$current" | jq -r '.email // empty')
189
189
 
190
190
  if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
191
- # Profile mismatch — switch.
191
+ # Profile mismatch — switch, then re-verify. Do not trust the switch exit
192
+ # status alone because acli's active account is machine-global state.
192
193
  acli auth switch --site "$site" ${email:+--email "$email"}
194
+ current=$(acli auth status --json 2>/dev/null)
195
+ current_site=$(echo "$current" | jq -r '.site // empty')
196
+ current_email=$(echo "$current" | jq -r '.email // empty')
197
+ fi
198
+
199
+ if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
200
+ echo "Error: acli active site is '$current_site', but .lisa.config.json requires '$site'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
201
+ exit 1
202
+ fi
203
+
204
+ if [ -n "$email" ] && [ -n "$current_email" ] && [ "$current_email" != "$email" ]; then
205
+ echo "Error: acli active account is '$current_email', but .lisa.config.json requires '$email'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
206
+ exit 1
193
207
  fi
194
208
  ```
195
209
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.158.3",
3
+ "version": "2.159.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: atlassian-access
3
- description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and its active profile matches the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are skipped, not used."
3
+ description: "Vendor-neutral access layer for Atlassian (JIRA + Confluence). Every jira-* and confluence-* skill MUST delegate through this skill rather than calling Atlassian directly. Resolves a substrate per operation in this order: (1) acli if installed and switchable to a profile matching the configured site, (2) Atlassian MCP if authenticated and the configured cloudId is in its accessible resources, (3) curl + API-token Basic auth. Verifies the active connection matches `.lisa.config.json` before every operation — substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, and skipped only after switch plus re-verification fails."
4
4
  allowed-tools: ["Bash", "Read", "Skill"]
5
5
  ---
6
6
 
@@ -35,7 +35,7 @@ EMAIL=$(jq -r '.atlassian.email // empty' .lisa.config.local.json 2>/dev/null)
35
35
  [ -z "$CLOUDID" ] && { echo "Error: atlassian.cloudId not set. Run /lisa:setup:atlassian." >&2; exit 1; }
36
36
  ```
37
37
 
38
- Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are skipped, not used.
38
+ Probe each tier in order; the first that's ready AND identity-matches is the substrate for this operation. Identity-match is verified before any operation; substrates authenticated as a different Atlassian account are switched to the configured profile when one exists, then skipped only if the switch fails or re-verification still mismatches.
39
39
 
40
40
  ```bash
41
41
  substrate=""
@@ -43,13 +43,13 @@ substrate=""
43
43
  # Tier 1: acli
44
44
  if command -v acli >/dev/null 2>&1 && acli auth status >/dev/null 2>&1; then
45
45
  current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
46
+ if [ "$current_site" != "$SITE" ]; then
47
+ # acli installed but pointing at a different site. Try switching profiles.
48
+ acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1 || true
49
+ current_site=$(acli auth status 2>/dev/null | awk '/^ Site:/{print $2}')
50
+ fi
46
51
  if [ "$current_site" = "$SITE" ]; then
47
52
  substrate="acli"
48
- else
49
- # acli installed but pointing at a different site. Try switching profiles.
50
- if acli auth switch --site "$SITE" ${EMAIL:+--email "$EMAIL"} >/dev/null 2>&1; then
51
- substrate="acli"
52
- fi
53
53
  fi
54
54
  fi
55
55
 
@@ -164,7 +164,7 @@ Operation dispatch then uses `$substrate` for the primary route. If the operatio
164
164
 
165
165
  ### Step 2 — Connection-match check
166
166
 
167
- The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already verifies this implicitly (substrates that don't match are skipped). This step is the explicit assertion before any operation runs — defensive in case the substrate state changed since selection.
167
+ The active connection MUST point at the cloudId/site declared in `.lisa.config.json`. Step 1's substrate selection already tries to switch mismatched acli profiles and verifies the result before selection. This step repeats the assertion before any operation runs — defensive in case the substrate state changed since selection.
168
168
 
169
169
  Read configured site:
170
170
 
@@ -188,8 +188,22 @@ current_site=$(echo "$current" | jq -r '.site // empty')
188
188
  current_email=$(echo "$current" | jq -r '.email // empty')
189
189
 
190
190
  if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
191
- # Profile mismatch — switch.
191
+ # Profile mismatch — switch, then re-verify. Do not trust the switch exit
192
+ # status alone because acli's active account is machine-global state.
192
193
  acli auth switch --site "$site" ${email:+--email "$email"}
194
+ current=$(acli auth status --json 2>/dev/null)
195
+ current_site=$(echo "$current" | jq -r '.site // empty')
196
+ current_email=$(echo "$current" | jq -r '.email // empty')
197
+ fi
198
+
199
+ if [ -n "$site" ] && [ "$current_site" != "$site" ]; then
200
+ echo "Error: acli active site is '$current_site', but .lisa.config.json requires '$site'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
201
+ exit 1
202
+ fi
203
+
204
+ if [ -n "$email" ] && [ -n "$current_email" ] && [ "$current_email" != "$email" ]; then
205
+ echo "Error: acli active account is '$current_email', but .lisa.config.json requires '$email'. Run /lisa:setup:atlassian to add or repair the matching profile." >&2
206
+ exit 1
193
207
  fi
194
208
  ```
195
209