@pleaseai/work 0.1.4 → 0.1.6

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 (3) hide show
  1. package/README.md +22 -1
  2. package/dist/index.js +153 -18
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -165,6 +165,7 @@ agent:
165
165
 
166
166
  claude:
167
167
  permission_mode: acceptEdits
168
+ # setting_sources: [] # default: [project, local, user]; set [] for SDK isolation mode
168
169
  turn_timeout_ms: 3600000
169
170
  ---
170
171
 
@@ -224,6 +225,7 @@ agent:
224
225
 
225
226
  claude:
226
227
  permission_mode: acceptEdits
228
+ # setting_sources: [] # default: [project, local, user]; set [] for SDK isolation mode
227
229
  turn_timeout_ms: 3600000
228
230
  ---
229
231
 
@@ -287,6 +289,7 @@ agent:
287
289
 
288
290
  claude:
289
291
  permission_mode: acceptEdits
292
+ # setting_sources: [] # default: [project, local, user]; set [] for SDK isolation mode
290
293
  turn_timeout_ms: 3600000
291
294
  ---
292
295
 
@@ -394,9 +397,18 @@ claude:
394
397
  - Read
395
398
  - Write
396
399
  - Bash
400
+ setting_sources: # Optional: filesystem settings to load. Default: [project, local, user]
401
+ - project # load .claude/settings.json + CLAUDE.md from the workspace directory
402
+ - local # load .claude/settings.local.json from the workspace directory
403
+ - user # load ~/.claude/settings.json + global CLAUDE.md
404
+ # Only "project", "local", and "user" are valid — other values are ignored
397
405
  turn_timeout_ms: 3600000 # Optional: per-turn timeout in ms, default 3600000
398
406
  read_timeout_ms: 5000 # Optional: initial subprocess read timeout in ms, default 5000
399
407
  stall_timeout_ms: 300000 # Optional: stall detection timeout, default 300000
408
+ settings:
409
+ attribution:
410
+ commit: "🙏 Generated with [Work Please](https://github.com/pleaseai/work-please)" # Optional: appended to git commit messages. Defaults to Work Please link.
411
+ pr: "🙏 Generated with [Work Please](https://github.com/pleaseai/work-please)" # Optional: appended to PR descriptions. Defaults to Work Please link.
400
412
 
401
413
  server:
402
414
  port: 3000 # Optional: enable HTTP dashboard on this port
@@ -410,9 +422,10 @@ Your prompt template goes here. Available variables:
410
422
  - {{ issue.description }} — Issue body/description
411
423
  - {{ issue.state }} — Current tracker state name
412
424
  - {{ issue.url }} — Issue URL
413
- - {{ issue.assignee }} — Primary assignee login (GitHub) or email (Asana), or null if unassigned
425
+ - {{ issue.assignees }} — Array of assignee logins (GitHub) or emails (Asana)
414
426
  - {{ issue.labels }} — Array of label strings (normalized to lowercase)
415
427
  - {{ issue.blocked_by }} — Array of blocker refs (each has id, identifier, state)
428
+ - {{ issue.pull_requests }} — Array of linked PRs (each has number, title, url, state, branch_name)
416
429
  - {{ issue.priority }} — Numeric priority or null
417
430
  - {{ issue.created_at }} — ISO-8601 creation timestamp
418
431
  - {{ issue.updated_at }} — ISO-8601 last-updated timestamp
@@ -437,6 +450,14 @@ Blocked by:
437
450
  {% endfor %}
438
451
  {% endif %}
439
452
 
453
+ {% if issue.pull_requests.size > 0 %}
454
+ Linked pull requests:
455
+ {% for pr in issue.pull_requests %}
456
+ - PR #{{ pr.number }}: {{ pr.title }} ({{ pr.state }}){% if pr.branch_name %} — branch: {{ pr.branch_name }}{% endif %}{% if pr.url %} — {{ pr.url }}{% endif %}
457
+
458
+ {% endfor %}
459
+ {% endif %}
460
+
440
461
  {% if attempt %}
441
462
  Retry attempt: {{ attempt }}
442
463
  {% endif %}
package/dist/index.js CHANGED
@@ -2166,7 +2166,7 @@ var {
2166
2166
  var package_default = {
2167
2167
  name: "@pleaseai/work",
2168
2168
  type: "module",
2169
- version: "0.1.4",
2169
+ version: "0.1.6",
2170
2170
  description: "Symphony-spec orchestrator for Claude Code + Asana/GitHub Projects v2",
2171
2171
  license: "FSL-1.1-MIT",
2172
2172
  repository: {
@@ -3088,6 +3088,13 @@ agent:
3088
3088
  max_turns: 20
3089
3089
  claude:
3090
3090
  permission_mode: bypassPermissions
3091
+ # claude.settings controls the attribution text written into .claude/settings.local.json
3092
+ # of each workspace. Omit to use the default Work Please attribution.
3093
+ # claude:
3094
+ # settings:
3095
+ # attribution:
3096
+ # commit: "\uD83D\uDE4F Generated with Work Please"
3097
+ # pr: "\uD83D\uDE4F Generated with Work Please"
3091
3098
  # server:
3092
3099
  # port: 3000
3093
3100
  ---
@@ -31679,7 +31686,11 @@ function createToolsMcpServer(config2) {
31679
31686
  }
31680
31687
 
31681
31688
  // src/agent-runner.ts
31689
+ var UUID_PATTERN = /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i;
31690
+ var NEWLINE_PATTERN = /[\r\n]/g;
31691
+
31682
31692
  class AppServerClient {
31693
+ assignedSessionId = null;
31683
31694
  sessionId = null;
31684
31695
  abortController = null;
31685
31696
  workspace;
@@ -31690,11 +31701,20 @@ class AppServerClient {
31690
31701
  this.workspace = workspace;
31691
31702
  this.queryFn = queryFn;
31692
31703
  }
31693
- async startSession() {
31704
+ async startSession(sessionId) {
31705
+ this.assignedSessionId = null;
31706
+ this.sessionId = null;
31707
+ if (sessionId !== undefined && !UUID_PATTERN.test(sessionId)) {
31708
+ const preview = String(sessionId).slice(0, 64).replace(NEWLINE_PATTERN, " ");
31709
+ return new Error(`invalid_session_id: expected UUID format, got "${preview}"`);
31710
+ }
31694
31711
  const validationErr = this.validateWorkspaceCwd();
31695
31712
  if (validationErr)
31696
31713
  return validationErr;
31697
- return { threadId: randomUUID(), workspace: this.workspace };
31714
+ const id = sessionId ?? randomUUID();
31715
+ this.assignedSessionId = id;
31716
+ this.sessionId = sessionId ?? null;
31717
+ return { sessionId: id, workspace: this.workspace };
31698
31718
  }
31699
31719
  async runTurn(session, prompt, _issue, onMessage) {
31700
31720
  const controller = new AbortController;
@@ -31713,16 +31733,30 @@ class AppServerClient {
31713
31733
  }
31714
31734
  if (this.sessionId) {
31715
31735
  options.resume = this.sessionId;
31736
+ } else if (this.assignedSessionId) {
31737
+ options.sessionId = this.assignedSessionId;
31716
31738
  }
31717
31739
  if (this.config.claude.command !== "claude") {
31718
31740
  options.pathToClaudeCodeExecutable = this.config.claude.command;
31719
31741
  }
31742
+ if (this.config.claude.model) {
31743
+ options.model = this.config.claude.model;
31744
+ }
31745
+ const sp = this.config.claude.system_prompt;
31746
+ if (sp.type === "custom") {
31747
+ options.systemPrompt = sp.value;
31748
+ } else {
31749
+ options.systemPrompt = sp;
31750
+ }
31720
31751
  const toolSpecs = getToolSpecs(this.config);
31721
31752
  if (toolSpecs.length > 0) {
31722
31753
  options.mcpServers = {
31723
31754
  "work-please-tools": createToolsMcpServer(this.config)
31724
31755
  };
31725
31756
  }
31757
+ if (this.config.claude.setting_sources.length > 0) {
31758
+ options.settingSources = this.config.claude.setting_sources;
31759
+ }
31726
31760
  const turnId = randomUUID();
31727
31761
  let sessionId = null;
31728
31762
  let gotError = false;
@@ -31734,11 +31768,11 @@ class AppServerClient {
31734
31768
  const initMsg = msg;
31735
31769
  sessionId = initMsg.session_id;
31736
31770
  this.sessionId = sessionId;
31771
+ this.assignedSessionId = null;
31737
31772
  onMessage({
31738
31773
  event: "session_started",
31739
31774
  timestamp: new Date,
31740
31775
  session_id: sessionId,
31741
- thread_id: session.threadId,
31742
31776
  turn_id: turnId
31743
31777
  });
31744
31778
  } else if (msg.type === "result") {
@@ -31791,12 +31825,18 @@ class AppServerClient {
31791
31825
  });
31792
31826
  return err;
31793
31827
  }
31794
- return { thread_id: session.threadId, turn_id: turnId, session_id: sessionId };
31828
+ return { turn_id: turnId, session_id: sessionId };
31795
31829
  } catch (err) {
31796
31830
  clearTimeout(timeoutHandle);
31797
31831
  const error48 = err instanceof Error ? err : new Error(String(err));
31832
+ if (!sessionId) {
31833
+ if (!options.resume) {
31834
+ this.sessionId = null;
31835
+ this.assignedSessionId = null;
31836
+ }
31837
+ }
31798
31838
  onMessage({
31799
- event: "startup_failed",
31839
+ event: sessionId ? "turn_failed" : "startup_failed",
31800
31840
  timestamp: new Date,
31801
31841
  payload: { reason: error48.message }
31802
31842
  });
@@ -31805,6 +31845,7 @@ class AppServerClient {
31805
31845
  }
31806
31846
  stopSession() {
31807
31847
  this.abortController?.abort();
31848
+ this.assignedSessionId = null;
31808
31849
  this.sessionId = null;
31809
31850
  this.abortController = null;
31810
31851
  }
@@ -31825,6 +31866,7 @@ import { tmpdir } from "os";
31825
31866
  import { join, sep as sep2 } from "path";
31826
31867
  import process4 from "process";
31827
31868
  var ENV_VAR_RE = /^\$([A-Z_]\w*)$/i;
31869
+ var VALID_SETTING_SOURCES = new Set(["user", "project", "local"]);
31828
31870
  var DEFAULTS2 = {
31829
31871
  POLL_INTERVAL_MS: 30000,
31830
31872
  WORKSPACE_ROOT: join(tmpdir(), "work-please_workspaces"),
@@ -31835,6 +31877,7 @@ var DEFAULTS2 = {
31835
31877
  CLAUDE_COMMAND: "claude",
31836
31878
  CLAUDE_PERMISSION_MODE: "bypassPermissions",
31837
31879
  CLAUDE_ALLOWED_TOOLS: [],
31880
+ CLAUDE_SETTING_SOURCES: ["project", "local", "user"],
31838
31881
  CLAUDE_TURN_TIMEOUT_MS: 3600000,
31839
31882
  CLAUDE_READ_TIMEOUT_MS: 5000,
31840
31883
  CLAUDE_STALL_TIMEOUT_MS: 300000,
@@ -31876,19 +31919,33 @@ function buildConfig(workflow) {
31876
31919
  max_retry_backoff_ms: posIntValue(agent.max_retry_backoff_ms, DEFAULTS2.MAX_RETRY_BACKOFF_MS),
31877
31920
  max_concurrent_agents_by_state: stateLimitsValue(agent.max_concurrent_agents_by_state)
31878
31921
  },
31879
- claude: {
31880
- command: commandValue(claude.command) ?? DEFAULTS2.CLAUDE_COMMAND,
31881
- permission_mode: stringValue(claude.permission_mode) ?? DEFAULTS2.CLAUDE_PERMISSION_MODE,
31882
- allowed_tools: stringArrayValue(claude.allowed_tools, DEFAULTS2.CLAUDE_ALLOWED_TOOLS),
31883
- turn_timeout_ms: intValue(claude.turn_timeout_ms, DEFAULTS2.CLAUDE_TURN_TIMEOUT_MS),
31884
- read_timeout_ms: intValue(claude.read_timeout_ms, DEFAULTS2.CLAUDE_READ_TIMEOUT_MS),
31885
- stall_timeout_ms: intValue(claude.stall_timeout_ms, DEFAULTS2.CLAUDE_STALL_TIMEOUT_MS)
31886
- },
31922
+ claude: buildClaudeConfig(claude),
31887
31923
  server: {
31888
31924
  port: nonNegIntOrNull(server.port)
31889
31925
  }
31890
31926
  };
31891
31927
  }
31928
+ function buildClaudeConfig(claude) {
31929
+ const settingsSec = sectionMap(claude, "settings");
31930
+ const attributionSec = sectionMap(settingsSec, "attribution");
31931
+ return {
31932
+ model: stringValue(claude.model),
31933
+ command: commandValue(claude.command) ?? DEFAULTS2.CLAUDE_COMMAND,
31934
+ permission_mode: stringValue(claude.permission_mode) ?? DEFAULTS2.CLAUDE_PERMISSION_MODE,
31935
+ allowed_tools: stringArrayValue(claude.allowed_tools, DEFAULTS2.CLAUDE_ALLOWED_TOOLS),
31936
+ setting_sources: stringArrayValue(claude.setting_sources, DEFAULTS2.CLAUDE_SETTING_SOURCES).filter((s2) => VALID_SETTING_SOURCES.has(s2)),
31937
+ turn_timeout_ms: intValue(claude.turn_timeout_ms, DEFAULTS2.CLAUDE_TURN_TIMEOUT_MS),
31938
+ read_timeout_ms: intValue(claude.read_timeout_ms, DEFAULTS2.CLAUDE_READ_TIMEOUT_MS),
31939
+ stall_timeout_ms: intValue(claude.stall_timeout_ms, DEFAULTS2.CLAUDE_STALL_TIMEOUT_MS),
31940
+ system_prompt: systemPromptValue(claude.system_prompt),
31941
+ settings: {
31942
+ attribution: {
31943
+ commit: stringValue(attributionSec.commit),
31944
+ pr: stringValue(attributionSec.pr)
31945
+ }
31946
+ }
31947
+ };
31948
+ }
31892
31949
  function buildTrackerConfig(kind, tracker) {
31893
31950
  const label_prefix = stringValue(tracker.label_prefix) ?? null;
31894
31951
  const filter = buildFilterConfig(sectionMap(tracker, "filter"));
@@ -32002,6 +32059,26 @@ function maxConcurrentForState(config2, state) {
32002
32059
  const byState = config2.agent.max_concurrent_agents_by_state;
32003
32060
  return byState[normalized] ?? config2.agent.max_concurrent_agents;
32004
32061
  }
32062
+ var DEFAULT_SYSTEM_PROMPT = { type: "preset", preset: "claude_code" };
32063
+ function systemPromptValue(val) {
32064
+ if (val == null)
32065
+ return DEFAULT_SYSTEM_PROMPT;
32066
+ if (typeof val === "string") {
32067
+ const trimmed = val.trim();
32068
+ return trimmed ? { type: "custom", value: trimmed } : DEFAULT_SYSTEM_PROMPT;
32069
+ }
32070
+ if (typeof val === "object" && !Array.isArray(val)) {
32071
+ const obj = val;
32072
+ if (obj.type === "preset" && obj.preset === "claude_code") {
32073
+ return typeof obj.append === "string" ? { type: "preset", preset: "claude_code", append: obj.append } : { type: "preset", preset: "claude_code" };
32074
+ }
32075
+ if (obj.type === "custom" && typeof obj.value === "string") {
32076
+ const trimmed = obj.value.trim();
32077
+ return trimmed ? { type: "custom", value: trimmed } : DEFAULT_SYSTEM_PROMPT;
32078
+ }
32079
+ }
32080
+ return DEFAULT_SYSTEM_PROMPT;
32081
+ }
32005
32082
  function sectionMap(raw, key) {
32006
32083
  const val = raw[key];
32007
32084
  return val && typeof val === "object" && !Array.isArray(val) ? val : {};
@@ -32066,7 +32143,7 @@ function csvValue(val) {
32066
32143
  function stringArrayValue(val, fallback) {
32067
32144
  if (!Array.isArray(val))
32068
32145
  return fallback;
32069
- return val.filter((v) => typeof v === "string");
32146
+ return val.filter((v) => typeof v === "string" && v.trim().length > 0);
32070
32147
  }
32071
32148
  function stateLimitsValue(val) {
32072
32149
  if (!val || typeof val !== "object" || Array.isArray(val))
@@ -36929,6 +37006,7 @@ function issueToTemplateVars(issue2) {
36929
37006
  url: issue2.url,
36930
37007
  labels: issue2.labels,
36931
37008
  blocked_by: issue2.blocked_by,
37009
+ pull_requests: issue2.pull_requests,
36932
37010
  created_at: issue2.created_at?.toISOString() ?? null,
36933
37011
  updated_at: issue2.updated_at?.toISOString() ?? null
36934
37012
  };
@@ -37091,6 +37169,7 @@ function createAsanaAdapter(config2) {
37091
37169
  assignees: [],
37092
37170
  labels: [],
37093
37171
  blocked_by: [],
37172
+ pull_requests: [],
37094
37173
  created_at: null,
37095
37174
  updated_at: null
37096
37175
  });
@@ -37121,6 +37200,7 @@ function normalizeAsanaTask(task, sectionName) {
37121
37200
  assignees,
37122
37201
  labels,
37123
37202
  blocked_by: blockedBy,
37203
+ pull_requests: [],
37124
37204
  created_at: task.created_at ? new Date(String(task.created_at)) : null,
37125
37205
  updated_at: task.modified_at ? new Date(String(task.modified_at)) : null
37126
37206
  };
@@ -37184,12 +37264,16 @@ function createGitHubAdapter(config2) {
37184
37264
  labels(first: 20) { nodes { name } }
37185
37265
  assignees(first: 10) { nodes { login } }
37186
37266
  createdAt updatedAt
37267
+ closedByPullRequestsReferences(first: 10, includeClosedPrs: true) {
37268
+ nodes { number title url state headRefName }
37269
+ }
37187
37270
  }
37188
37271
  ... on PullRequest {
37189
37272
  number title body url
37190
37273
  labels(first: 20) { nodes { name } }
37191
37274
  assignees(first: 10) { nodes { login } }
37192
37275
  createdAt updatedAt
37276
+ headRefName
37193
37277
  }
37194
37278
  }
37195
37279
  }
@@ -37216,12 +37300,16 @@ function createGitHubAdapter(config2) {
37216
37300
  labels(first: 20) { nodes { name } }
37217
37301
  assignees(first: 10) { nodes { login } }
37218
37302
  createdAt updatedAt
37303
+ closedByPullRequestsReferences(first: 10, includeClosedPrs: true) {
37304
+ nodes { number title url state headRefName }
37305
+ }
37219
37306
  }
37220
37307
  ... on PullRequest {
37221
37308
  number title body url
37222
37309
  labels(first: 20) { nodes { name } }
37223
37310
  assignees(first: 10) { nodes { login } }
37224
37311
  createdAt updatedAt
37312
+ headRefName
37225
37313
  }
37226
37314
  }
37227
37315
  }
@@ -37253,12 +37341,16 @@ function createGitHubAdapter(config2) {
37253
37341
  labels(first: 20) { nodes { name } }
37254
37342
  assignees(first: 10) { nodes { login } }
37255
37343
  createdAt updatedAt
37344
+ closedByPullRequestsReferences(first: 10, includeClosedPrs: true) {
37345
+ nodes { number title url state headRefName }
37346
+ }
37256
37347
  }
37257
37348
  ... on PullRequest {
37258
37349
  number title body url
37259
37350
  labels(first: 20) { nodes { name } }
37260
37351
  assignees(first: 10) { nodes { login } }
37261
37352
  createdAt updatedAt
37353
+ headRefName
37262
37354
  }
37263
37355
  }
37264
37356
  }
@@ -37386,6 +37478,10 @@ function buildQueryString(filter2) {
37386
37478
  parts.push(`label:${filter2.label.join(",")}`);
37387
37479
  return parts.join(" ");
37388
37480
  }
37481
+ function normalizePrState(raw2) {
37482
+ const s2 = String(raw2 ?? "").toLowerCase();
37483
+ return s2 === "closed" || s2 === "merged" ? s2 : "open";
37484
+ }
37389
37485
  function normalizeProjectItem(node, status) {
37390
37486
  const content = node.content;
37391
37487
  const number4 = content?.number;
@@ -37393,6 +37489,15 @@ function normalizeProjectItem(node, status) {
37393
37489
  const labels = Array.isArray(content?.labels?.nodes) ? content.labels.nodes.map((l) => (l.name ?? "").toLowerCase()).filter(Boolean) : [];
37394
37490
  const assigneeNodes = content?.assignees?.nodes;
37395
37491
  const assignees = Array.isArray(assigneeNodes) ? assigneeNodes.map((n2) => n2.login ?? "").filter(Boolean) : [];
37492
+ const prRefNodes = content?.closedByPullRequestsReferences?.nodes;
37493
+ const pullRequests = Array.isArray(prRefNodes) ? prRefNodes.filter((pr) => pr !== null && typeof pr === "object" && typeof pr.number === "number" && pr.number > 0).map((pr) => ({
37494
+ number: pr.number,
37495
+ title: String(pr.title ?? ""),
37496
+ url: pr.url ? String(pr.url) : null,
37497
+ state: normalizePrState(pr.state),
37498
+ branch_name: pr.headRefName ? String(pr.headRefName) : null
37499
+ })) : [];
37500
+ const headRefName = content?.headRefName ? String(content.headRefName) : null;
37396
37501
  return {
37397
37502
  id: String(node.id ?? ""),
37398
37503
  identifier,
@@ -37400,11 +37505,12 @@ function normalizeProjectItem(node, status) {
37400
37505
  description: content?.body ? String(content.body) : null,
37401
37506
  priority: null,
37402
37507
  state: status,
37403
- branch_name: null,
37508
+ branch_name: headRefName,
37404
37509
  url: content?.url ? String(content.url) : null,
37405
37510
  assignees,
37406
37511
  labels,
37407
37512
  blocked_by: [],
37513
+ pull_requests: pullRequests,
37408
37514
  created_at: content?.createdAt ? new Date(String(content.createdAt)) : null,
37409
37515
  updated_at: content?.updatedAt ? new Date(String(content.updatedAt)) : null
37410
37516
  };
@@ -40140,9 +40246,28 @@ function isWorkflowError(result) {
40140
40246
  }
40141
40247
 
40142
40248
  // src/workspace.ts
40143
- import { existsSync as existsSync4, lstatSync as lstatSync2, mkdirSync as mkdirSync2, rmSync as rmSync2, statSync as statSync3 } from "fs";
40144
- import { join as join4, resolve as resolve4, sep as sep4 } from "path";
40249
+ import { existsSync as existsSync4, lstatSync as lstatSync2, mkdirSync as mkdirSync2, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync2 } from "fs";
40250
+ import { dirname as dirname2, join as join4, resolve as resolve4, sep as sep4 } from "path";
40145
40251
  import process6 from "process";
40252
+ var CLAUDE_SETTINGS_PATH = ".claude/settings.local.json";
40253
+ var WORK_PLEASE_URL = "https://github.com/pleaseai/work-please";
40254
+ var ATTRIBUTION_TEXT = `\uD83D\uDE4F Generated with [Work Please](${WORK_PLEASE_URL})`;
40255
+ function generateClaudeSettings(attribution) {
40256
+ return `${JSON.stringify({
40257
+ attribution: {
40258
+ commit: attribution?.commit ?? ATTRIBUTION_TEXT,
40259
+ pr: attribution?.pr ?? ATTRIBUTION_TEXT
40260
+ }
40261
+ }, null, 2)}
40262
+ `;
40263
+ }
40264
+ function ensureClaudeSettings(wsPath, attribution) {
40265
+ const settingsPath = join4(wsPath, CLAUDE_SETTINGS_PATH);
40266
+ if (existsSync4(settingsPath))
40267
+ return;
40268
+ mkdirSync2(dirname2(settingsPath), { recursive: true });
40269
+ writeFileSync2(settingsPath, generateClaudeSettings(attribution), "utf-8");
40270
+ }
40146
40271
  var _git = {
40147
40272
  spawnSync: (args) => Bun.spawnSync(args)
40148
40273
  };
@@ -40275,6 +40400,11 @@ async function createWorkspace(config2, identifier, issue2) {
40275
40400
  if (hookErr)
40276
40401
  return hookErr;
40277
40402
  }
40403
+ try {
40404
+ ensureClaudeSettings(wtPath, config2.claude.settings.attribution);
40405
+ } catch (err) {
40406
+ return err instanceof Error ? err : new Error(String(err));
40407
+ }
40278
40408
  return { path: wtPath, workspace_key: key, created_now: createdNow };
40279
40409
  }
40280
40410
  }
@@ -40305,6 +40435,11 @@ async function createWorkspace(config2, identifier, issue2) {
40305
40435
  if (hookErr)
40306
40436
  return hookErr;
40307
40437
  }
40438
+ try {
40439
+ ensureClaudeSettings(wsPath, config2.claude.settings.attribution);
40440
+ } catch (err) {
40441
+ return err instanceof Error ? err : new Error(String(err));
40442
+ }
40308
40443
  return workspace;
40309
40444
  }
40310
40445
  async function removeWorkspace(config2, identifier, issue2) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pleaseai/work",
3
3
  "type": "module",
4
- "version": "0.1.4",
4
+ "version": "0.1.6",
5
5
  "description": "Symphony-spec orchestrator for Claude Code + Asana/GitHub Projects v2",
6
6
  "license": "FSL-1.1-MIT",
7
7
  "repository": {